authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-26 10:55:29-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-26 10:55:29-04:00
logbbfff4614614726dd2ef2c05f851f91be5368f84
tree9cbfbb8b744c883150312bc9adf068778c60397e
parentce68dda4b60914e947088e7cf0c5626ea7cebc08
parent27cbb44993389ae042a03266743379c0f15a523e

Merge remote-tracking branch 'origin/master' into llvm7


89 files changed, 9577 insertions(+), 4971 deletions(-)

.travis.yml+13-9
......@@ -1,18 +1,22 @@
11sudo: required
22services:
3 - docker
3- docker
44os:
5 - linux
6 - osx
5- linux
6- osx
77dist: trusty
88osx_image: xcode8.3
99language: cpp
1010before_install:
11 - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_before_install; fi
12 - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ci/travis_osx_before_install; fi
11- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_before_install; fi
12- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ci/travis_osx_before_install; fi
1313install:
14 - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_install; fi
15 - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ci/travis_osx_install; fi
14- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_install; fi
15- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ci/travis_osx_install; fi
1616script:
17 - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_script; fi
18 - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ci/travis_osx_script; fi
17- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_script; fi
18- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ci/travis_osx_script; fi
19env:
20 global:
21 - secure: QmJ+eLOxj3Irl5SHxt6lQvrj7++1AIz8bYri6RScAQGHQPIztkmbpBjAkpFgYaWPkZ04ROtamFXdS7oHtJHSECesgPoqM/CHIychQkgpDq30+TsFyYbBpDGHY+N6r2WnQTvg+9EuAp6P365us6qFS0D5zQ3P40c56uMbazFu3J4W1HZP+pLWlLjEXaN88ePhHWqNZyvwGMkLpYl3ghcrE9H4vGZQ7jenRW4UmskLEkuhUPJbQiow3Td8arJiRmLVISzWqneqNraLUpGyUVr4F3Rbjzacfoo3r9ZZynhY0mFsEye82x6TMGgH2xsNGkd91zpQuckWUT+pQv/G6FXpnEnjIJSO2Z5WAxXrx6xB1k2HZ17/4NWLF3fJVhdQJm3mS6odeGzUjgGrl1A42evxU+7VbcofEJq1aMiLgU1jUT2pt+pefCwmKJYLpEsSzuyrVxgvskQz0QpC053TAYSNf2Jj6Qhg9YDWyOeemYmDgffTqErF7AYhc6NKH0s0XKkIiNFSxorkEsfG/Ck1o+15slHNmWZXlmXToxDqFkLDoPvfGKg7koU5YTGvci/F9ZKb1juhGLxZbwap/18zN40BqA+Ip2yDBJAKxsIiwSjSIguy6g/Z1I50s0xNGOr36urfRRQX5H+rqr/xCZ63B6WSe6qBcZboWAQMDn8HLS9Xiwc=
22 - secure: dnb7r5guUeMOX9e7XlPUSZzmga8VW3G9Q1aa7LxEKiTjSnWhu5KpPDe8o1X3Rj6nc5iXDqmBH/C/7eNXPDyXJJWPvpE2YRpGymyUkRaakul0QBKJEaMvwy2SuAfS69CWC+TSzfGRvtSYkdpBhhLvs0h5S819S5jYbCNSCmOKfFucaP5NsHNIZ/I19oIeTPTa0/UnVm7DLFZXZjvbS+czkdyH1DhbT85sLj+XqNTzLePImE68efrjaHnlSy/CzBVJzj55UgD5i9fxNCQWzGWim/SD5xZ0zKtLycSOf6wQN2lCo0lkjw9rDlYz69mM5L9ikfYL9oHDPZnh84oXKglQ5miOHCgqs/qs4439I05lIu8i/EfbFA55YG4NyO3rL9YVOOt5gwiwvJYhDcnkVVzSl0o5bsoZgQfYvPWaIQKNkl3C53zfDQjgqS54CeDzlZpFrQTDQ1RrH8oeVC1gfYAeMabMDadox5rfZmLIN5JTf/F8iD/QdxGcoUvkEENcQgfP9PnubExtexgHGsEmqbm6ORSZ1MkEh2m3fo0f8KE6TbN1UigmcQ8nTkWBHsSmfHnB8HwJQp8mwQmDamXA+Hl3e3w4LOdYkJVlNW1/TTyJJOOvjMQCjF8SJmPHuh+QpqKbSaT9XM/vBhxbIZEufH8kawJKCBBcCNspGMNjhXfNjM0=
CMakeLists.txt+26-1
......@@ -498,7 +498,28 @@ set(ZIG_STD_FILES
498498 "math/tan.zig"
499499 "math/tanh.zig"
500500 "math/trunc.zig"
501 "math/x86_64/sqrt.zig"
501 "math/complex/abs.zig"
502 "math/complex/acosh.zig"
503 "math/complex/acos.zig"
504 "math/complex/arg.zig"
505 "math/complex/asinh.zig"
506 "math/complex/asin.zig"
507 "math/complex/atanh.zig"
508 "math/complex/atan.zig"
509 "math/complex/conj.zig"
510 "math/complex/cosh.zig"
511 "math/complex/cos.zig"
512 "math/complex/exp.zig"
513 "math/complex/index.zig"
514 "math/complex/ldexp.zig"
515 "math/complex/log.zig"
516 "math/complex/pow.zig"
517 "math/complex/proj.zig"
518 "math/complex/sinh.zig"
519 "math/complex/sin.zig"
520 "math/complex/sqrt.zig"
521 "math/complex/tanh.zig"
522 "math/complex/tan.zig"
502523 "mem.zig"
503524 "net.zig"
504525 "os/child_process.zig"
......@@ -509,13 +530,17 @@ set(ZIG_STD_FILES
509530 "os/index.zig"
510531 "os/linux/errno.zig"
511532 "os/linux/index.zig"
533 "os/linux/vdso.zig"
512534 "os/linux/x86_64.zig"
513535 "os/path.zig"
536 "os/time.zig"
537 "os/epoch.zig"
514538 "os/windows/error.zig"
515539 "os/windows/index.zig"
516540 "os/windows/util.zig"
517541 "os/zen.zig"
518542 "rand/index.zig"
543 "rand/ziggurat.zig"
519544 "sort.zig"
520545 "special/bootstrap.zig"
521546 "special/bootstrap_lib.zig"
ci/travis_linux_script+1-1
......@@ -19,5 +19,5 @@ if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then
1919 echo "secret_key = $AWS_SECRET_ACCESS_KEY" >> ~/.s3cfg
2020 s3cmd put -P $TRAVIS_BUILD_DIR/artifacts/* s3://ziglang.org/builds/
2121 touch empty
22 s3cmd put -P empty s3://ziglang.org/builds/zig-linux-x86_64-$TRAVIS_BRANCH.tar.xz --add-header=x-amz-website-redirect-location:/builds/$(ls $TRAVIS_BUILD_DIR/artifacts)
22 s3cmd put -P empty s3://ziglang.org/builds/zig-linux-x86_64-$TRAVIS_BRANCH.tar.xz --add-header="Cache-Control: max-age=0, must-revalidate" --add-header=x-amz-website-redirect-location:/builds/$(ls $TRAVIS_BUILD_DIR/artifacts)
2323fi
deps/lld/ELF/MarkLive.cpp+9
......@@ -301,6 +301,15 @@ template <class ELFT> void elf::markLive() {
301301 // Follow the graph to mark all live sections.
302302 doGcSections<ELFT>();
303303
304 // If all references to a DSO happen to be weak, the DSO is removed from
305 // DT_NEEDED, which creates dangling shared symbols to non-existent DSO.
306 // We'll replace such symbols with undefined ones to fix it.
307 for (Symbol *Sym : Symtab->getSymbols())
308 if (auto *S = dyn_cast<SharedSymbol>(Sym))
309 if (S->isWeak() && !S->getFile<ELFT>().IsNeeded)
310 replaceSymbol<Undefined>(S, nullptr, S->getName(), STB_WEAK, S->StOther,
311 S->Type);
312
304313 // Report garbage-collected sections.
305314 if (Config->PrintGcSections)
306315 for (InputSectionBase *Sec : InputSections)
doc/docgen.zig+19
......@@ -749,6 +749,10 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
749749 try build_args.append("--release-fast");
750750 try out.print(" --release-fast");
751751 },
752 builtin.Mode.ReleaseSmall => {
753 try build_args.append("--release-small");
754 try out.print(" --release-small");
755 },
752756 }
753757 for (code.link_objects) |link_object| {
754758 const name_with_ext = try std.fmt.allocPrint(allocator, "{}{}", link_object, obj_ext);
......@@ -810,6 +814,10 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
810814 try test_args.append("--release-fast");
811815 try out.print(" --release-fast");
812816 },
817 builtin.Mode.ReleaseSmall => {
818 try test_args.append("--release-small");
819 try out.print(" --release-small");
820 },
813821 }
814822 if (code.target_windows) {
815823 try test_args.appendSlice([][]const u8{
......@@ -840,6 +848,10 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
840848 try test_args.append("--release-fast");
841849 try out.print(" --release-fast");
842850 },
851 builtin.Mode.ReleaseSmall => {
852 try test_args.append("--release-small");
853 try out.print(" --release-small");
854 },
843855 }
844856 const result = try os.ChildProcess.exec(allocator, test_args.toSliceConst(), null, null, max_doc_file_size);
845857 switch (result.term) {
......@@ -874,6 +886,7 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
874886 builtin.Mode.Debug => {},
875887 builtin.Mode.ReleaseSafe => try test_args.append("--release-safe"),
876888 builtin.Mode.ReleaseFast => try test_args.append("--release-fast"),
889 builtin.Mode.ReleaseSmall => try test_args.append("--release-small"),
877890 }
878891
879892 const result = try os.ChildProcess.exec(allocator, test_args.toSliceConst(), null, null, max_doc_file_size);
......@@ -927,6 +940,12 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
927940 try out.print(" --release-fast");
928941 }
929942 },
943 builtin.Mode.ReleaseSmall => {
944 try build_args.append("--release-small");
945 if (!code.is_inline) {
946 try out.print(" --release-small");
947 }
948 },
930949 }
931950
932951 if (maybe_error_match) |error_match| {
doc/langref.html.in+83-6
......@@ -3880,6 +3880,25 @@ pub fn main() void {
38803880 {#header_open|@ArgType#}
38813881 <p>TODO</p>
38823882 {#header_close#}
3883 {#header_open|@atomicLoad#}
3884 <pre><code class="zig">@atomicLoad(comptime T: type, ptr: &amp;const T, comptime ordering: builtin.AtomicOrder) -&gt; T</code></pre>
3885 <p>
3886 This builtin function atomically dereferences a pointer and returns the value.
3887 </p>
3888 <p>
3889 <code>T</code> must be a pointer type, a <code>bool</code>,
3890 or an integer whose bit count meets these requirements:
3891 </p>
3892 <ul>
3893 <li>At least 8</li>
3894 <li>At most the same as usize</li>
3895 <li>Power of 2</li>
3896 </ul>
3897 <p>
3898 TODO right now bool is not accepted. Also I think we could make non powers of 2 work fine, maybe
3899 we can remove this restriction
3900 </p>
3901 {#header_close#}
38833902 {#header_open|@atomicRmw#}
38843903 <pre><code class="zig">@atomicRmw(comptime T: type, ptr: &amp;T, comptime op: builtin.AtomicRmwOp, operand: T, comptime ordering: builtin.AtomicOrder) -&gt; T</code></pre>
38853904 <p>
......@@ -4046,16 +4065,60 @@ comptime {
40464065 </p>
40474066
40484067 {#header_close#}
4049 {#header_open|@cmpxchg#}
4050 <pre><code class="zig">@cmpxchg(ptr: &T, cmp: T, new: T, success_order: AtomicOrder, fail_order: AtomicOrder) -&gt; bool</code></pre>
4068 {#header_open|@cmpxchgStrong#}
4069 <pre><code class="zig">@cmpxchgStrong(comptime T: type, ptr: &T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) -&gt; ?T</code></pre>
4070 <p>
4071 This function performs a strong atomic compare exchange operation. It's the equivalent of this code,
4072 except atomic:
4073 </p>
4074 {#code_begin|syntax#}
4075fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: &T, expected_value: T, new_value: T) ?T {
4076 const old_value = *ptr;
4077 if (old_value == expected_value) {
4078 *ptr = new_value;
4079 return null;
4080 } else {
4081 return old_value;
4082 }
4083}
4084 {#code_end#}
4085 <p>
4086 If you are using cmpxchg in a loop, {#link|@cmpxchgWeak#} is the better choice, because it can be implemented
4087 more efficiently in machine instructions.
4088 </p>
4089 <p>
4090 <code>AtomicOrder</code> can be found with <code>@import("builtin").AtomicOrder</code>.
4091 </p>
4092 <p><code>@typeOf(ptr).alignment</code> must be <code>&gt;= @sizeOf(T).</code></p>
4093 {#see_also|Compile Variables|cmpxchgWeak#}
4094 {#header_close#}
4095 {#header_open|@cmpxchgWeak#}
4096 <pre><code class="zig">@cmpxchgWeak(comptime T: type, ptr: &T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) -&gt; ?T</code></pre>
4097 <p>
4098 This function performs a weak atomic compare exchange operation. It's the equivalent of this code,
4099 except atomic:
4100 </p>
4101 {#code_begin|syntax#}
4102fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: &T, expected_value: T, new_value: T) ?T {
4103 const old_value = *ptr;
4104 if (old_value == expected_value and usuallyTrueButSometimesFalse()) {
4105 *ptr = new_value;
4106 return null;
4107 } else {
4108 return old_value;
4109 }
4110}
4111 {#code_end#}
40514112 <p>
4052 This function performs an atomic compare exchange operation.
4113 If you are using cmpxchg in a loop, the sporadic failure will be no problem, and <code>cmpxchgWeak</code>
4114 is the better choice, because it can be implemented more efficiently in machine instructions.
4115 However if you need a stronger guarantee, use {#link|@cmpxchgStrong#}.
40534116 </p>
40544117 <p>
40554118 <code>AtomicOrder</code> can be found with <code>@import("builtin").AtomicOrder</code>.
40564119 </p>
40574120 <p><code>@typeOf(ptr).alignment</code> must be <code>&gt;= @sizeOf(T).</code></p>
4058 {#see_also|Compile Variables#}
4121 {#see_also|Compile Variables|cmpxchgStrong#}
40594122 {#header_close#}
40604123 {#header_open|@compileError#}
40614124 <pre><code class="zig">@compileError(comptime msg: []u8)</code></pre>
......@@ -4349,6 +4412,10 @@ fn add(a: i32, b: i32) i32 { return a + b; }
43494412 It does not include functions, variables, or constants.
43504413 </p>
43514414 {#header_close#}
4415 {#header_open|@field#}
4416 <pre><code class="zig">@field(lhs: var, comptime field_name: []const u8) -&gt; (field)</code></pre>
4417 <p>Preforms field access equivalent to <code>lhs.-&gtfield_name-&lt</code>.</p>
4418 {#header_close#}
43524419 {#header_open|@memberType#}
43534420 <pre><code class="zig">@memberType(comptime T: type, comptime index: usize) -&gt; type</code></pre>
43544421 <p>Returns the field type of a struct or union.</p>
......@@ -4669,6 +4736,16 @@ pub const FloatMode = enum {
46694736 The result is a target-specific compile time constant.
46704737 </p>
46714738 {#header_close#}
4739 {#header_open|@sqrt#}
4740 <pre><code class="zig">@sqrt(comptime T: type, value: T) -&gt; T</code></pre>
4741 <p>
4742 Performs the square root of a floating point number. Uses a dedicated hardware instruction
4743 when available. Currently only supports f32 and f64 at runtime. f128 at runtime is TODO.
4744 </p>
4745 <p>
4746 This is a low-level intrinsic. Most code can use <code>std.math.sqrt</code> instead.
4747 </p>
4748 {#header_close#}
46724749 {#header_open|@subWithOverflow#}
46734750 <pre><code class="zig">@subWithOverflow(comptime T: type, a: T, b: T, result: &T) -&gt; bool</code></pre>
46744751 <p>
......@@ -5845,7 +5922,7 @@ Defer(body) = ("defer" | "deferror") body
58455922
58465923IfExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body))
58475924
5848SuspendExpression(body) = "suspend" option(("|" Symbol "|" body))
5925SuspendExpression(body) = option(Symbol ":") "suspend" option(("|" Symbol "|" body))
58495926
58505927IfErrorExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") body "else" "|" Symbol "|" BlockExpression(body)
58515928
......@@ -5991,7 +6068,7 @@ hljs.registerLanguage("zig", function(t) {
59916068 a = t.IR + "\\s*\\(",
59926069 c = {
59936070 keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong",
5994 built_in: "breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchg fence divExact truncate atomicRmw",
6071 built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field",
59956072 literal: "true false null undefined"
59966073 },
59976074 n = [e, t.CLCM, t.CBCM, s, r];
src-self-hosted/arg.zig created+284
......@@ -0,0 +1,284 @@
1const std = @import("std");
2const debug = std.debug;
3const mem = std.mem;
4
5const Allocator = mem.Allocator;
6const ArrayList = std.ArrayList;
7const HashMap = std.HashMap;
8
9fn trimStart(slice: []const u8, ch: u8) []const u8 {
10 var i: usize = 0;
11 for (slice) |b| {
12 if (b != '-') break;
13 i += 1;
14 }
15
16 return slice[i..];
17}
18
19fn argInAllowedSet(maybe_set: ?[]const []const u8, arg: []const u8) bool {
20 if (maybe_set) |set| {
21 for (set) |possible| {
22 if (mem.eql(u8, arg, possible)) {
23 return true;
24 }
25 }
26 return false;
27 } else {
28 return true;
29 }
30}
31
32// Modifies the current argument index during iteration
33fn readFlagArguments(allocator: &Allocator, args: []const []const u8, required: usize,
34 allowed_set: ?[]const []const u8, index: &usize) !FlagArg {
35
36 switch (required) {
37 0 => return FlagArg { .None = undefined }, // TODO: Required to force non-tag but value?
38 1 => {
39 if (*index + 1 >= args.len) {
40 return error.MissingFlagArguments;
41 }
42
43 *index += 1;
44 const arg = args[*index];
45
46 if (!argInAllowedSet(allowed_set, arg)) {
47 return error.ArgumentNotInAllowedSet;
48 }
49
50 return FlagArg { .Single = arg };
51 },
52 else => |needed| {
53 var extra = ArrayList([]const u8).init(allocator);
54 errdefer extra.deinit();
55
56 var j: usize = 0;
57 while (j < needed) : (j += 1) {
58 if (*index + 1 >= args.len) {
59 return error.MissingFlagArguments;
60 }
61
62 *index += 1;
63 const arg = args[*index];
64
65 if (!argInAllowedSet(allowed_set, arg)) {
66 return error.ArgumentNotInAllowedSet;
67 }
68
69 try extra.append(arg);
70 }
71
72 return FlagArg { .Many = extra };
73 },
74 }
75}
76
77const HashMapFlags = HashMap([]const u8, FlagArg, std.hash.Fnv1a_32.hash, mem.eql_slice_u8);
78
79// A store for querying found flags and positional arguments.
80pub const Args = struct {
81 flags: HashMapFlags,
82 positionals: ArrayList([]const u8),
83
84 pub fn parse(allocator: &Allocator, comptime spec: []const Flag, args: []const []const u8) !Args {
85 var parsed = Args {
86 .flags = HashMapFlags.init(allocator),
87 .positionals = ArrayList([]const u8).init(allocator),
88 };
89
90 var i: usize = 0;
91 next: while (i < args.len) : (i += 1) {
92 const arg = args[i];
93
94 if (arg.len != 0 and arg[0] == '-') {
95 // TODO: hashmap, although the linear scan is okay for small argument sets as is
96 for (spec) |flag| {
97 if (mem.eql(u8, arg, flag.name)) {
98 const flag_name_trimmed = trimStart(flag.name, '-');
99 const flag_args = readFlagArguments(allocator, args, flag.required, flag.allowed_set, &i) catch |err| {
100 switch (err) {
101 error.ArgumentNotInAllowedSet => {
102 std.debug.warn("argument '{}' is invalid for flag '{}'\n", args[i], arg);
103 std.debug.warn("allowed options are ");
104 for (??flag.allowed_set) |possible| {
105 std.debug.warn("'{}' ", possible);
106 }
107 std.debug.warn("\n");
108 },
109 error.MissingFlagArguments => {
110 std.debug.warn("missing argument for flag: {}\n", arg);
111 },
112 else => {},
113 }
114
115 return err;
116 };
117
118 if (flag.mergable) {
119 var prev =
120 if (parsed.flags.get(flag_name_trimmed)) |entry|
121 entry.value.Many
122 else
123 ArrayList([]const u8).init(allocator);
124
125 // MergeN creation disallows 0 length flag entry (doesn't make sense)
126 switch (flag_args) {
127 FlagArg.None => unreachable,
128 FlagArg.Single => |inner| try prev.append(inner),
129 FlagArg.Many => |inner| try prev.appendSlice(inner.toSliceConst()),
130 }
131
132 _ = try parsed.flags.put(flag_name_trimmed, FlagArg { .Many = prev });
133 } else {
134 _ = try parsed.flags.put(flag_name_trimmed, flag_args);
135 }
136
137 continue :next;
138 }
139 }
140
141 // TODO: Better errors with context, global error state and return is sufficient.
142 std.debug.warn("could not match flag: {}\n", arg);
143 return error.UnknownFlag;
144 } else {
145 try parsed.positionals.append(arg);
146 }
147 }
148
149 return parsed;
150 }
151
152 pub fn deinit(self: &Args) void {
153 self.flags.deinit();
154 self.positionals.deinit();
155 }
156
157 // e.g. --help
158 pub fn present(self: &Args, name: []const u8) bool {
159 return self.flags.contains(name);
160 }
161
162 // e.g. --name value
163 pub fn single(self: &Args, name: []const u8) ?[]const u8 {
164 if (self.flags.get(name)) |entry| {
165 switch (entry.value) {
166 FlagArg.Single => |inner| { return inner; },
167 else => @panic("attempted to retrieve flag with wrong type"),
168 }
169 } else {
170 return null;
171 }
172 }
173
174 // e.g. --names value1 value2 value3
175 pub fn many(self: &Args, name: []const u8) ?[]const []const u8 {
176 if (self.flags.get(name)) |entry| {
177 switch (entry.value) {
178 FlagArg.Many => |inner| { return inner.toSliceConst(); },
179 else => @panic("attempted to retrieve flag with wrong type"),
180 }
181 } else {
182 return null;
183 }
184 }
185};
186
187// Arguments for a flag. e.g. arg1, arg2 in `--command arg1 arg2`.
188const FlagArg = union(enum) {
189 None,
190 Single: []const u8,
191 Many: ArrayList([]const u8),
192};
193
194// Specification for how a flag should be parsed.
195pub const Flag = struct {
196 name: []const u8,
197 required: usize,
198 mergable: bool,
199 allowed_set: ?[]const []const u8,
200
201 pub fn Bool(comptime name: []const u8) Flag {
202 return ArgN(name, 0);
203 }
204
205 pub fn Arg1(comptime name: []const u8) Flag {
206 return ArgN(name, 1);
207 }
208
209 pub fn ArgN(comptime name: []const u8, comptime n: usize) Flag {
210 return Flag {
211 .name = name,
212 .required = n,
213 .mergable = false,
214 .allowed_set = null,
215 };
216 }
217
218 pub fn ArgMergeN(comptime name: []const u8, comptime n: usize) Flag {
219 if (n == 0) {
220 @compileError("n must be greater than 0");
221 }
222
223 return Flag {
224 .name = name,
225 .required = n,
226 .mergable = true,
227 .allowed_set = null,
228 };
229 }
230
231 pub fn Option(comptime name: []const u8, comptime set: []const []const u8) Flag {
232 return Flag {
233 .name = name,
234 .required = 1,
235 .mergable = false,
236 .allowed_set = set,
237 };
238 }
239};
240
241test "parse arguments" {
242 const spec1 = comptime []const Flag {
243 Flag.Bool("--help"),
244 Flag.Bool("--init"),
245 Flag.Arg1("--build-file"),
246 Flag.Option("--color", []const []const u8 { "on", "off", "auto" }),
247 Flag.ArgN("--pkg-begin", 2),
248 Flag.ArgMergeN("--object", 1),
249 Flag.ArgN("--library", 1),
250 };
251
252 const cliargs = []const []const u8 {
253 "build",
254 "--help",
255 "pos1",
256 "--build-file", "build.zig",
257 "--object", "obj1",
258 "--object", "obj2",
259 "--library", "lib1",
260 "--library", "lib2",
261 "--color", "on",
262 "pos2",
263 };
264
265 var args = try Args.parse(std.debug.global_allocator, spec1, cliargs);
266
267 debug.assert(args.present("help"));
268 debug.assert(!args.present("help2"));
269 debug.assert(!args.present("init"));
270
271 debug.assert(mem.eql(u8, ??args.single("build-file"), "build.zig"));
272 debug.assert(mem.eql(u8, ??args.single("color"), "on"));
273
274 const objects = ??args.many("object");
275 debug.assert(mem.eql(u8, objects[0], "obj1"));
276 debug.assert(mem.eql(u8, objects[1], "obj2"));
277
278 debug.assert(mem.eql(u8, ??args.single("library"), "lib2"));
279
280 const pos = args.positionals.toSliceConst();
281 debug.assert(mem.eql(u8, pos[0], "build"));
282 debug.assert(mem.eql(u8, pos[1], "pos1"));
283 debug.assert(mem.eql(u8, pos[2], "pos2"));
284}
src-self-hosted/introspect.zig created+57
......@@ -0,0 +1,57 @@
1// Introspection and determination of system libraries needed by zig.
2
3const std = @import("std");
4const mem = std.mem;
5const os = std.os;
6
7const warn = std.debug.warn;
8
9/// Caller must free result
10pub fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) ![]u8 {
11 const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig");
12 errdefer allocator.free(test_zig_dir);
13
14 const test_index_file = try os.path.join(allocator, test_zig_dir, "std", "index.zig");
15 defer allocator.free(test_index_file);
16
17 var file = try os.File.openRead(allocator, test_index_file);
18 file.close();
19
20 return test_zig_dir;
21}
22
23/// Caller must free result
24pub fn findZigLibDir(allocator: &mem.Allocator) ![]u8 {
25 const self_exe_path = try os.selfExeDirPath(allocator);
26 defer allocator.free(self_exe_path);
27
28 var cur_path: []const u8 = self_exe_path;
29 while (true) {
30 const test_dir = os.path.dirname(cur_path);
31
32 if (mem.eql(u8, test_dir, cur_path)) {
33 break;
34 }
35
36 return testZigInstallPrefix(allocator, test_dir) catch |err| {
37 cur_path = test_dir;
38 continue;
39 };
40 }
41
42 return error.FileNotFound;
43}
44
45pub fn resolveZigLibDir(allocator: &mem.Allocator) ![]u8 {
46 return findZigLibDir(allocator) catch |err| {
47 warn(
48 \\Unable to find zig lib directory: {}.
49 \\Reinstall Zig or use --zig-install-prefix.
50 \\
51 ,
52 @errorName(err)
53 );
54
55 return error.ZigLibDirNotFound;
56 };
57}
src-self-hosted/main.zig+881-700
......@@ -1,613 +1,165 @@
11const std = @import("std");
2const mem = std.mem;
3const io = std.io;
4const os = std.os;
5const heap = std.heap;
6const warn = std.debug.warn;
7const assert = std.debug.assert;
8const target = @import("target.zig");
9const Target = target.Target;
10const Module = @import("module.zig").Module;
11const ErrColor = Module.ErrColor;
12const Emit = Module.Emit;
132const builtin = @import("builtin");
14const ArrayList = std.ArrayList;
15const c = @import("c.zig");
163
17const default_zig_cache_name = "zig-cache";
4const os = std.os;
5const io = std.io;
6const mem = std.mem;
7const Allocator = mem.Allocator;
8const ArrayList = std.ArrayList;
9const Buffer = std.Buffer;
1810
19const Cmd = enum {
20 None,
21 Build,
22 Test,
23 Version,
24 Zen,
25 TranslateC,
26 Targets,
11const arg = @import("arg.zig");
12const c = @import("c.zig");
13const introspect = @import("introspect.zig");
14const Args = arg.Args;
15const Flag = arg.Flag;
16const Module = @import("module.zig").Module;
17const Target = @import("target.zig").Target;
18
19var stderr: &io.OutStream(io.FileOutStream.Error) = undefined;
20var stdout: &io.OutStream(io.FileOutStream.Error) = undefined;
21
22const usage =
23 \\usage: zig [command] [options]
24 \\
25 \\Commands:
26 \\
27 \\ build Build project from build.zig
28 \\ build-exe [source] Create executable from source or object files
29 \\ build-lib [source] Create library from source or object files
30 \\ build-obj [source] Create object from source or assembly
31 \\ fmt [source] Parse file and render in canonical zig format
32 \\ run [source] Create executable and run immediately
33 \\ targets List available compilation targets
34 \\ test [source] Create and run a test build
35 \\ translate-c [source] Convert c code to zig code
36 \\ version Print version number and exit
37 \\ zen Print zen of zig and exit
38 \\
39 \\
40 ;
41
42const Command = struct {
43 name: []const u8,
44 exec: fn(&Allocator, []const []const u8) error!void,
2745};
2846
29fn badArgs(comptime format: []const u8, args: ...) noreturn {
30 var stderr = io.getStdErr() catch std.os.exit(1);
31 var stderr_stream_adapter = io.FileOutStream.init(&stderr);
32 const stderr_stream = &stderr_stream_adapter.stream;
33 stderr_stream.print(format ++ "\n\n", args) catch std.os.exit(1);
34 printUsage(&stderr_stream_adapter.stream) catch std.os.exit(1);
35 std.os.exit(1);
36}
37
3847pub fn main() !void {
39 const allocator = std.heap.c_allocator;
48 var allocator = std.heap.c_allocator;
49
50 var stdout_file = try std.io.getStdOut();
51 var stdout_out_stream = std.io.FileOutStream.init(&stdout_file);
52 stdout = &stdout_out_stream.stream;
53
54 var stderr_file = try std.io.getStdErr();
55 var stderr_out_stream = std.io.FileOutStream.init(&stderr_file);
56 stderr = &stderr_out_stream.stream;
4057
4158 const args = try os.argsAlloc(allocator);
4259 defer os.argsFree(allocator, args);
4360
44 if (args.len >= 2 and mem.eql(u8, args[1], "build")) {
45 return buildMain(allocator, args[2..]);
46 }
47
48 if (args.len >= 2 and mem.eql(u8, args[1], "fmt")) {
49 return fmtMain(allocator, args[2..]);
50 }
51
52 var cmd = Cmd.None;
53 var build_kind: Module.Kind = undefined;
54 var build_mode: builtin.Mode = builtin.Mode.Debug;
55 var color = ErrColor.Auto;
56 var emit_file_type = Emit.Binary;
57
58 var strip = false;
59 var is_static = false;
60 var verbose_tokenize = false;
61 var verbose_ast_tree = false;
62 var verbose_ast_fmt = false;
63 var verbose_link = false;
64 var verbose_ir = false;
65 var verbose_llvm_ir = false;
66 var verbose_cimport = false;
67 var mwindows = false;
68 var mconsole = false;
69 var rdynamic = false;
70 var each_lib_rpath = false;
71 var timing_info = false;
72
73 var in_file_arg: ?[]u8 = null;
74 var out_file: ?[]u8 = null;
75 var out_file_h: ?[]u8 = null;
76 var out_name_arg: ?[]u8 = null;
77 var libc_lib_dir_arg: ?[]u8 = null;
78 var libc_static_lib_dir_arg: ?[]u8 = null;
79 var libc_include_dir_arg: ?[]u8 = null;
80 var msvc_lib_dir_arg: ?[]u8 = null;
81 var kernel32_lib_dir_arg: ?[]u8 = null;
82 var zig_install_prefix: ?[]u8 = null;
83 var dynamic_linker_arg: ?[]u8 = null;
84 var cache_dir_arg: ?[]const u8 = null;
85 var target_arch: ?[]u8 = null;
86 var target_os: ?[]u8 = null;
87 var target_environ: ?[]u8 = null;
88 var mmacosx_version_min: ?[]u8 = null;
89 var mios_version_min: ?[]u8 = null;
90 var linker_script_arg: ?[]u8 = null;
91 var test_name_prefix_arg: ?[]u8 = null;
92
93 var test_filters = ArrayList([]const u8).init(allocator);
94 defer test_filters.deinit();
95
96 var lib_dirs = ArrayList([]const u8).init(allocator);
97 defer lib_dirs.deinit();
98
99 var clang_argv = ArrayList([]const u8).init(allocator);
100 defer clang_argv.deinit();
101
102 var llvm_argv = ArrayList([]const u8).init(allocator);
103 defer llvm_argv.deinit();
104
105 var link_libs = ArrayList([]const u8).init(allocator);
106 defer link_libs.deinit();
107
108 var frameworks = ArrayList([]const u8).init(allocator);
109 defer frameworks.deinit();
110
111 var objects = ArrayList([]const u8).init(allocator);
112 defer objects.deinit();
113
114 var asm_files = ArrayList([]const u8).init(allocator);
115 defer asm_files.deinit();
116
117 var rpath_list = ArrayList([]const u8).init(allocator);
118 defer rpath_list.deinit();
119
120 var ver_major: u32 = 0;
121 var ver_minor: u32 = 0;
122 var ver_patch: u32 = 0;
123
124 var arg_i: usize = 1;
125 while (arg_i < args.len) : (arg_i += 1) {
126 const arg = args[arg_i];
127
128 if (arg.len != 0 and arg[0] == '-') {
129 if (mem.eql(u8, arg, "--release-fast")) {
130 build_mode = builtin.Mode.ReleaseFast;
131 } else if (mem.eql(u8, arg, "--release-safe")) {
132 build_mode = builtin.Mode.ReleaseSafe;
133 } else if (mem.eql(u8, arg, "--strip")) {
134 strip = true;
135 } else if (mem.eql(u8, arg, "--static")) {
136 is_static = true;
137 } else if (mem.eql(u8, arg, "--verbose-tokenize")) {
138 verbose_tokenize = true;
139 } else if (mem.eql(u8, arg, "--verbose-ast-tree")) {
140 verbose_ast_tree = true;
141 } else if (mem.eql(u8, arg, "--verbose-ast-fmt")) {
142 verbose_ast_fmt = true;
143 } else if (mem.eql(u8, arg, "--verbose-link")) {
144 verbose_link = true;
145 } else if (mem.eql(u8, arg, "--verbose-ir")) {
146 verbose_ir = true;
147 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
148 verbose_llvm_ir = true;
149 } else if (mem.eql(u8, arg, "--verbose-cimport")) {
150 verbose_cimport = true;
151 } else if (mem.eql(u8, arg, "-mwindows")) {
152 mwindows = true;
153 } else if (mem.eql(u8, arg, "-mconsole")) {
154 mconsole = true;
155 } else if (mem.eql(u8, arg, "-rdynamic")) {
156 rdynamic = true;
157 } else if (mem.eql(u8, arg, "--each-lib-rpath")) {
158 each_lib_rpath = true;
159 } else if (mem.eql(u8, arg, "--enable-timing-info")) {
160 timing_info = true;
161 } else if (mem.eql(u8, arg, "--test-cmd-bin")) {
162 @panic("TODO --test-cmd-bin");
163 } else if (arg[1] == 'L' and arg.len > 2) {
164 // alias for --library-path
165 try lib_dirs.append(arg[1..]);
166 } else if (mem.eql(u8, arg, "--pkg-begin")) {
167 @panic("TODO --pkg-begin");
168 } else if (mem.eql(u8, arg, "--pkg-end")) {
169 @panic("TODO --pkg-end");
170 } else if (arg_i + 1 >= args.len) {
171 badArgs("expected another argument after {}", arg);
172 } else {
173 arg_i += 1;
174 if (mem.eql(u8, arg, "--output")) {
175 out_file = args[arg_i];
176 } else if (mem.eql(u8, arg, "--output-h")) {
177 out_file_h = args[arg_i];
178 } else if (mem.eql(u8, arg, "--color")) {
179 if (mem.eql(u8, args[arg_i], "auto")) {
180 color = ErrColor.Auto;
181 } else if (mem.eql(u8, args[arg_i], "on")) {
182 color = ErrColor.On;
183 } else if (mem.eql(u8, args[arg_i], "off")) {
184 color = ErrColor.Off;
185 } else {
186 badArgs("--color options are 'auto', 'on', or 'off'");
187 }
188 } else if (mem.eql(u8, arg, "--emit")) {
189 if (mem.eql(u8, args[arg_i], "asm")) {
190 emit_file_type = Emit.Assembly;
191 } else if (mem.eql(u8, args[arg_i], "bin")) {
192 emit_file_type = Emit.Binary;
193 } else if (mem.eql(u8, args[arg_i], "llvm-ir")) {
194 emit_file_type = Emit.LlvmIr;
195 } else {
196 badArgs("--emit options are 'asm', 'bin', or 'llvm-ir'");
197 }
198 } else if (mem.eql(u8, arg, "--name")) {
199 out_name_arg = args[arg_i];
200 } else if (mem.eql(u8, arg, "--libc-lib-dir")) {
201 libc_lib_dir_arg = args[arg_i];
202 } else if (mem.eql(u8, arg, "--libc-static-lib-dir")) {
203 libc_static_lib_dir_arg = args[arg_i];
204 } else if (mem.eql(u8, arg, "--libc-include-dir")) {
205 libc_include_dir_arg = args[arg_i];
206 } else if (mem.eql(u8, arg, "--msvc-lib-dir")) {
207 msvc_lib_dir_arg = args[arg_i];
208 } else if (mem.eql(u8, arg, "--kernel32-lib-dir")) {
209 kernel32_lib_dir_arg = args[arg_i];
210 } else if (mem.eql(u8, arg, "--zig-install-prefix")) {
211 zig_install_prefix = args[arg_i];
212 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
213 dynamic_linker_arg = args[arg_i];
214 } else if (mem.eql(u8, arg, "-isystem")) {
215 try clang_argv.append("-isystem");
216 try clang_argv.append(args[arg_i]);
217 } else if (mem.eql(u8, arg, "-dirafter")) {
218 try clang_argv.append("-dirafter");
219 try clang_argv.append(args[arg_i]);
220 } else if (mem.eql(u8, arg, "-mllvm")) {
221 try clang_argv.append("-mllvm");
222 try clang_argv.append(args[arg_i]);
223
224 try llvm_argv.append(args[arg_i]);
225 } else if (mem.eql(u8, arg, "--library-path") or mem.eql(u8, arg, "-L")) {
226 try lib_dirs.append(args[arg_i]);
227 } else if (mem.eql(u8, arg, "--library")) {
228 try link_libs.append(args[arg_i]);
229 } else if (mem.eql(u8, arg, "--object")) {
230 try objects.append(args[arg_i]);
231 } else if (mem.eql(u8, arg, "--assembly")) {
232 try asm_files.append(args[arg_i]);
233 } else if (mem.eql(u8, arg, "--cache-dir")) {
234 cache_dir_arg = args[arg_i];
235 } else if (mem.eql(u8, arg, "--target-arch")) {
236 target_arch = args[arg_i];
237 } else if (mem.eql(u8, arg, "--target-os")) {
238 target_os = args[arg_i];
239 } else if (mem.eql(u8, arg, "--target-environ")) {
240 target_environ = args[arg_i];
241 } else if (mem.eql(u8, arg, "-mmacosx-version-min")) {
242 mmacosx_version_min = args[arg_i];
243 } else if (mem.eql(u8, arg, "-mios-version-min")) {
244 mios_version_min = args[arg_i];
245 } else if (mem.eql(u8, arg, "-framework")) {
246 try frameworks.append(args[arg_i]);
247 } else if (mem.eql(u8, arg, "--linker-script")) {
248 linker_script_arg = args[arg_i];
249 } else if (mem.eql(u8, arg, "-rpath")) {
250 try rpath_list.append(args[arg_i]);
251 } else if (mem.eql(u8, arg, "--test-filter")) {
252 try test_filters.append(args[arg_i]);
253 } else if (mem.eql(u8, arg, "--test-name-prefix")) {
254 test_name_prefix_arg = args[arg_i];
255 } else if (mem.eql(u8, arg, "--ver-major")) {
256 ver_major = try std.fmt.parseUnsigned(u32, args[arg_i], 10);
257 } else if (mem.eql(u8, arg, "--ver-minor")) {
258 ver_minor = try std.fmt.parseUnsigned(u32, args[arg_i], 10);
259 } else if (mem.eql(u8, arg, "--ver-patch")) {
260 ver_patch = try std.fmt.parseUnsigned(u32, args[arg_i], 10);
261 } else if (mem.eql(u8, arg, "--test-cmd")) {
262 @panic("TODO --test-cmd");
263 } else {
264 badArgs("invalid argument: {}", arg);
265 }
266 }
267 } else if (cmd == Cmd.None) {
268 if (mem.eql(u8, arg, "build-obj")) {
269 cmd = Cmd.Build;
270 build_kind = Module.Kind.Obj;
271 } else if (mem.eql(u8, arg, "build-exe")) {
272 cmd = Cmd.Build;
273 build_kind = Module.Kind.Exe;
274 } else if (mem.eql(u8, arg, "build-lib")) {
275 cmd = Cmd.Build;
276 build_kind = Module.Kind.Lib;
277 } else if (mem.eql(u8, arg, "version")) {
278 cmd = Cmd.Version;
279 } else if (mem.eql(u8, arg, "zen")) {
280 cmd = Cmd.Zen;
281 } else if (mem.eql(u8, arg, "translate-c")) {
282 cmd = Cmd.TranslateC;
283 } else if (mem.eql(u8, arg, "test")) {
284 cmd = Cmd.Test;
285 build_kind = Module.Kind.Exe;
286 } else {
287 badArgs("unrecognized command: {}", arg);
288 }
289 } else switch (cmd) {
290 Cmd.Build, Cmd.TranslateC, Cmd.Test => {
291 if (in_file_arg == null) {
292 in_file_arg = arg;
293 } else {
294 badArgs("unexpected extra parameter: {}", arg);
295 }
296 },
297 Cmd.Version, Cmd.Zen, Cmd.Targets => {
298 badArgs("unexpected extra parameter: {}", arg);
299 },
300 Cmd.None => unreachable,
301 }
61 if (args.len <= 1) {
62 try stderr.write(usage);
63 os.exit(1);
30264 }
30365
304 target.initializeAll();
305
306 // TODO
307// ZigTarget alloc_target;
308// ZigTarget *target;
309// if (!target_arch && !target_os && !target_environ) {
310// target = nullptr;
311// } else {
312// target = &alloc_target;
313// get_unknown_target(target);
314// if (target_arch) {
315// if (parse_target_arch(target_arch, &target->arch)) {
316// fprintf(stderr, "invalid --target-arch argument\n");
317// return usage(arg0);
318// }
319// }
320// if (target_os) {
321// if (parse_target_os(target_os, &target->os)) {
322// fprintf(stderr, "invalid --target-os argument\n");
323// return usage(arg0);
324// }
325// }
326// if (target_environ) {
327// if (parse_target_environ(target_environ, &target->env_type)) {
328// fprintf(stderr, "invalid --target-environ argument\n");
329// return usage(arg0);
330// }
331// }
332// }
333
334 switch (cmd) {
335 Cmd.None => badArgs("expected command"),
336 Cmd.Zen => return printZen(),
337 Cmd.Build, Cmd.Test, Cmd.TranslateC => {
338 if (cmd == Cmd.Build and in_file_arg == null and objects.len == 0 and asm_files.len == 0) {
339 badArgs("expected source file argument or at least one --object or --assembly argument");
340 } else if ((cmd == Cmd.TranslateC or cmd == Cmd.Test) and in_file_arg == null) {
341 badArgs("expected source file argument");
342 } else if (cmd == Cmd.Build and build_kind == Module.Kind.Obj and objects.len != 0) {
343 badArgs("When building an object file, --object arguments are invalid");
344 }
345
346 const root_name = switch (cmd) {
347 Cmd.Build, Cmd.TranslateC => x: {
348 if (out_name_arg) |out_name| {
349 break :x out_name;
350 } else if (in_file_arg) |in_file_path| {
351 const basename = os.path.basename(in_file_path);
352 var it = mem.split(basename, ".");
353 break :x it.next() ?? badArgs("file name cannot be empty");
354 } else {
355 badArgs("--name [name] not provided and unable to infer");
356 }
357 },
358 Cmd.Test => "test",
359 else => unreachable,
360 };
361
362 const zig_root_source_file = if (cmd == Cmd.TranslateC) null else in_file_arg;
363
364 const chosen_cache_dir = cache_dir_arg ?? default_zig_cache_name;
365 const full_cache_dir = try os.path.resolve(allocator, ".", chosen_cache_dir);
366 defer allocator.free(full_cache_dir);
367
368 const zig_lib_dir = try resolveZigLibDir(allocator, zig_install_prefix);
369 errdefer allocator.free(zig_lib_dir);
370
371 const module = try Module.create(allocator, root_name, zig_root_source_file,
372 Target.Native, build_kind, build_mode, zig_lib_dir, full_cache_dir);
373 defer module.destroy();
374
375 module.version_major = ver_major;
376 module.version_minor = ver_minor;
377 module.version_patch = ver_patch;
378
379 module.is_test = cmd == Cmd.Test;
380 if (linker_script_arg) |linker_script| {
381 module.linker_script = linker_script;
382 }
383 module.each_lib_rpath = each_lib_rpath;
384 module.clang_argv = clang_argv.toSliceConst();
385 module.llvm_argv = llvm_argv.toSliceConst();
386 module.strip = strip;
387 module.is_static = is_static;
388
389 if (libc_lib_dir_arg) |libc_lib_dir| {
390 module.libc_lib_dir = libc_lib_dir;
391 }
392 if (libc_static_lib_dir_arg) |libc_static_lib_dir| {
393 module.libc_static_lib_dir = libc_static_lib_dir;
394 }
395 if (libc_include_dir_arg) |libc_include_dir| {
396 module.libc_include_dir = libc_include_dir;
397 }
398 if (msvc_lib_dir_arg) |msvc_lib_dir| {
399 module.msvc_lib_dir = msvc_lib_dir;
400 }
401 if (kernel32_lib_dir_arg) |kernel32_lib_dir| {
402 module.kernel32_lib_dir = kernel32_lib_dir;
403 }
404 if (dynamic_linker_arg) |dynamic_linker| {
405 module.dynamic_linker = dynamic_linker;
406 }
407 module.verbose_tokenize = verbose_tokenize;
408 module.verbose_ast_tree = verbose_ast_tree;
409 module.verbose_ast_fmt = verbose_ast_fmt;
410 module.verbose_link = verbose_link;
411 module.verbose_ir = verbose_ir;
412 module.verbose_llvm_ir = verbose_llvm_ir;
413 module.verbose_cimport = verbose_cimport;
414
415 module.err_color = color;
416
417 module.lib_dirs = lib_dirs.toSliceConst();
418 module.darwin_frameworks = frameworks.toSliceConst();
419 module.rpath_list = rpath_list.toSliceConst();
420
421 for (link_libs.toSliceConst()) |name| {
422 _ = try module.addLinkLib(name, true);
423 }
424
425 module.windows_subsystem_windows = mwindows;
426 module.windows_subsystem_console = mconsole;
427 module.linker_rdynamic = rdynamic;
428
429 if (mmacosx_version_min != null and mios_version_min != null) {
430 badArgs("-mmacosx-version-min and -mios-version-min options not allowed together");
431 }
432
433 if (mmacosx_version_min) |ver| {
434 module.darwin_version_min = Module.DarwinVersionMin { .MacOS = ver };
435 } else if (mios_version_min) |ver| {
436 module.darwin_version_min = Module.DarwinVersionMin { .Ios = ver };
437 }
438
439 module.test_filters = test_filters.toSliceConst();
440 module.test_name_prefix = test_name_prefix_arg;
441 module.out_h_path = out_file_h;
442
443 // TODO
444 //add_package(g, cur_pkg, g->root_package);
445
446 switch (cmd) {
447 Cmd.Build => {
448 module.emit_file_type = emit_file_type;
449
450 module.link_objects = objects.toSliceConst();
451 module.assembly_files = asm_files.toSliceConst();
452
453 try module.build();
454 try module.link(out_file);
455 },
456 Cmd.TranslateC => @panic("TODO translate-c"),
457 Cmd.Test => @panic("TODO test cmd"),
458 else => unreachable,
459 }
460 },
461 Cmd.Version => {
462 var stdout_file = try io.getStdErr();
463 try stdout_file.write(std.cstr.toSliceConst(c.ZIG_VERSION_STRING));
464 try stdout_file.write("\n");
465 },
466 Cmd.Targets => @panic("TODO zig targets"),
66 const commands = []Command {
67 Command { .name = "build", .exec = cmdBuild },
68 Command { .name = "build-exe", .exec = cmdBuildExe },
69 Command { .name = "build-lib", .exec = cmdBuildLib },
70 Command { .name = "build-obj", .exec = cmdBuildObj },
71 Command { .name = "fmt", .exec = cmdFmt },
72 Command { .name = "run", .exec = cmdRun },
73 Command { .name = "targets", .exec = cmdTargets },
74 Command { .name = "test", .exec = cmdTest },
75 Command { .name = "translate-c", .exec = cmdTranslateC },
76 Command { .name = "version", .exec = cmdVersion },
77 Command { .name = "zen", .exec = cmdZen },
78
79 // undocumented commands
80 Command { .name = "help", .exec = cmdHelp },
81 Command { .name = "internal", .exec = cmdInternal },
82 };
83
84 for (commands) |command| {
85 if (mem.eql(u8, command.name, args[1])) {
86 try command.exec(allocator, args[2..]);
87 return;
88 }
46789 }
468}
46990
470fn printUsage(stream: var) !void {
471 try stream.write(
472 \\Usage: zig [command] [options]
473 \\
474 \\Commands:
475 \\ build build project from build.zig
476 \\ build-exe [source] create executable from source or object files
477 \\ build-lib [source] create library from source or object files
478 \\ build-obj [source] create object from source or assembly
479 \\ fmt [file] parse file and render in canonical zig format
480 \\ translate-c [source] convert c code to zig code
481 \\ targets list available compilation targets
482 \\ test [source] create and run a test build
483 \\ version print version number and exit
484 \\ zen print zen of zig and exit
485 \\Compile Options:
486 \\ --assembly [source] add assembly file to build
487 \\ --cache-dir [path] override the cache directory
488 \\ --color [auto|off|on] enable or disable colored error messages
489 \\ --emit [filetype] emit a specific file format as compilation output
490 \\ --enable-timing-info print timing diagnostics
491 \\ --libc-include-dir [path] directory where libc stdlib.h resides
492 \\ --name [name] override output name
493 \\ --output [file] override destination path
494 \\ --output-h [file] override generated header file path
495 \\ --pkg-begin [name] [path] make package available to import and push current pkg
496 \\ --pkg-end pop current pkg
497 \\ --release-fast build with optimizations on and safety off
498 \\ --release-safe build with optimizations on and safety on
499 \\ --static output will be statically linked
500 \\ --strip exclude debug symbols
501 \\ --target-arch [name] specify target architecture
502 \\ --target-environ [name] specify target environment
503 \\ --target-os [name] specify target operating system
504 \\ --verbose-tokenize enable compiler debug info: tokenization
505 \\ --verbose-ast-tree enable compiler debug info: parsing into an AST (treeview)
506 \\ --verbose-ast-fmt enable compiler debug info: parsing into an AST (render source)
507 \\ --verbose-cimport enable compiler debug info: C imports
508 \\ --verbose-ir enable compiler debug info: Zig IR
509 \\ --verbose-llvm-ir enable compiler debug info: LLVM IR
510 \\ --verbose-link enable compiler debug info: linking
511 \\ --zig-install-prefix [path] override directory where zig thinks it is installed
512 \\ -dirafter [dir] same as -isystem but do it last
513 \\ -isystem [dir] add additional search path for other .h files
514 \\ -mllvm [arg] additional arguments to forward to LLVM's option processing
515 \\Link Options:
516 \\ --ar-path [path] set the path to ar
517 \\ --dynamic-linker [path] set the path to ld.so
518 \\ --each-lib-rpath add rpath for each used dynamic library
519 \\ --libc-lib-dir [path] directory where libc crt1.o resides
520 \\ --libc-static-lib-dir [path] directory where libc crtbegin.o resides
521 \\ --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides
522 \\ --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides
523 \\ --library [lib] link against lib
524 \\ --library-path [dir] add a directory to the library search path
525 \\ --linker-script [path] use a custom linker script
526 \\ --object [obj] add object file to build
527 \\ -L[dir] alias for --library-path
528 \\ -rdynamic add all symbols to the dynamic symbol table
529 \\ -rpath [path] add directory to the runtime library search path
530 \\ -mconsole (windows) --subsystem console to the linker
531 \\ -mwindows (windows) --subsystem windows to the linker
532 \\ -framework [name] (darwin) link against framework
533 \\ -mios-version-min [ver] (darwin) set iOS deployment target
534 \\ -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target
535 \\ --ver-major [ver] dynamic library semver major version
536 \\ --ver-minor [ver] dynamic library semver minor version
537 \\ --ver-patch [ver] dynamic library semver patch version
538 \\Test Options:
539 \\ --test-filter [text] skip tests that do not match filter
540 \\ --test-name-prefix [text] add prefix to all tests
541 \\ --test-cmd [arg] specify test execution command one arg at a time
542 \\ --test-cmd-bin appends test binary path to test cmd args
543 \\
544 );
545}
546
547fn printZen() !void {
548 var stdout_file = try io.getStdErr();
549 try stdout_file.write(
550 \\
551 \\ * Communicate intent precisely.
552 \\ * Edge cases matter.
553 \\ * Favor reading code over writing code.
554 \\ * Only one obvious way to do things.
555 \\ * Runtime crashes are better than bugs.
556 \\ * Compile errors are better than runtime crashes.
557 \\ * Incremental improvements.
558 \\ * Avoid local maximums.
559 \\ * Reduce the amount one must remember.
560 \\ * Minimize energy spent on coding style.
561 \\ * Together we serve end users.
562 \\
563 \\
564 );
91 try stderr.print("unknown command: {}\n\n", args[1]);
92 try stderr.write(usage);
56593}
56694
567fn buildMain(allocator: &mem.Allocator, argv: []const []const u8) !void {
568 var build_file: [] const u8 = "build.zig";
569 var cache_dir: ?[] const u8 = null;
570 var zig_install_prefix: ?[] const u8 = null;
571 var asked_for_help = false;
572 var asked_for_init = false;
573
574 var args = ArrayList([] const u8).init(allocator);
575 defer args.deinit();
576
577 var zig_exe_path = try os.selfExePath(allocator);
578 defer allocator.free(zig_exe_path);
579
580 try args.append(""); // Placeholder for zig-cache/build
581 try args.append(""); // Placeholder for zig_exe_path
582 try args.append(""); // Placeholder for build_file_dirname
583 try args.append(""); // Placeholder for full_cache_dir
95// cmd:build ///////////////////////////////////////////////////////////////////////////////////////
96
97const usage_build =
98 \\usage: zig build <options>
99 \\
100 \\General Options:
101 \\ --help Print this help and exit
102 \\ --init Generate a build.zig template
103 \\ --build-file [file] Override path to build.zig
104 \\ --cache-dir [path] Override path to cache directory
105 \\ --verbose Print commands before executing them
106 \\ --prefix [path] Override default install prefix
107 \\
108 \\Project-Specific Options:
109 \\
110 \\ Project-specific options become available when the build file is found.
111 \\
112 \\Advanced Options:
113 \\ --build-file [file] Override path to build.zig
114 \\ --cache-dir [path] Override path to cache directory
115 \\ --verbose-tokenize Enable compiler debug output for tokenization
116 \\ --verbose-ast Enable compiler debug output for parsing into an AST
117 \\ --verbose-link Enable compiler debug output for linking
118 \\ --verbose-ir Enable compiler debug output for Zig IR
119 \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR
120 \\ --verbose-cimport Enable compiler debug output for C imports
121 \\
122 \\
123 ;
124
125const args_build_spec = []Flag {
126 Flag.Bool("--help"),
127 Flag.Bool("--init"),
128 Flag.Arg1("--build-file"),
129 Flag.Arg1("--cache-dir"),
130 Flag.Bool("--verbose"),
131 Flag.Arg1("--prefix"),
132
133 Flag.Arg1("--build-file"),
134 Flag.Arg1("--cache-dir"),
135 Flag.Bool("--verbose-tokenize"),
136 Flag.Bool("--verbose-ast"),
137 Flag.Bool("--verbose-link"),
138 Flag.Bool("--verbose-ir"),
139 Flag.Bool("--verbose-llvm-ir"),
140 Flag.Bool("--verbose-cimport"),
141};
584142
585 var i: usize = 0;
586 while (i < argv.len) : (i += 1) {
587 var arg = argv[i];
588 if (mem.eql(u8, arg, "--help")) {
589 asked_for_help = true;
590 try args.append(argv[i]);
591 } else if (mem.eql(u8, arg, "--init")) {
592 asked_for_init = true;
593 try args.append(argv[i]);
594 } else if (i + 1 < argv.len and mem.eql(u8, arg, "--build-file")) {
595 build_file = argv[i + 1];
596 i += 1;
597 } else if (i + 1 < argv.len and mem.eql(u8, arg, "--cache-dir")) {
598 cache_dir = argv[i + 1];
599 i += 1;
600 } else if (i + 1 < argv.len and mem.eql(u8, arg, "--zig-install-prefix")) {
601 try args.append(arg);
602 i += 1;
603 zig_install_prefix = argv[i];
604 try args.append(argv[i]);
605 } else {
606 try args.append(arg);
607 }
143const missing_build_file =
144 \\No 'build.zig' file found.
145 \\
146 \\Initialize a 'build.zig' template file with `zig build --init`,
147 \\or build an executable directly with `zig build-exe $FILENAME.zig`.
148 \\
149 \\See: `zig build --help` or `zig help` for more options.
150 \\
151 ;
152
153fn cmdBuild(allocator: &Allocator, args: []const []const u8) !void {
154 var flags = try Args.parse(allocator, args_build_spec, args);
155 defer flags.deinit();
156
157 if (flags.present("help")) {
158 try stderr.write(usage_build);
159 os.exit(0);
608160 }
609161
610 const zig_lib_dir = try resolveZigLibDir(allocator, zig_install_prefix);
162 const zig_lib_dir = try introspect.resolveZigLibDir(allocator);
611163 defer allocator.free(zig_lib_dir);
612164
613165 const zig_std_dir = try os.path.join(allocator, zig_lib_dir, "std");
......@@ -619,113 +171,502 @@ fn buildMain(allocator: &mem.Allocator, argv: []const []const u8) !void {
619171 const build_runner_path = try os.path.join(allocator, special_dir, "build_runner.zig");
620172 defer allocator.free(build_runner_path);
621173
622 // g = codegen_create(build_runner_path, ...)
623 // codegen_set_out_name(g, "build")
624
174 const build_file = flags.single("build-file") ?? "build.zig";
625175 const build_file_abs = try os.path.resolve(allocator, ".", build_file);
626176 defer allocator.free(build_file_abs);
627177
628 const build_file_basename = os.path.basename(build_file_abs);
629 const build_file_dirname = os.path.dirname(build_file_abs);
178 const build_file_exists = os.File.access(allocator, build_file_abs, os.default_file_mode) catch false;
630179
631 var full_cache_dir: []u8 = undefined;
632 if (cache_dir == null) {
633 full_cache_dir = try os.path.join(allocator, build_file_dirname, "zig-cache");
634 } else {
635 full_cache_dir = try os.path.resolve(allocator, ".", ??cache_dir, full_cache_dir);
636 }
637 defer allocator.free(full_cache_dir);
180 if (flags.present("init")) {
181 if (build_file_exists) {
182 try stderr.print("build.zig already exists\n");
183 os.exit(1);
184 }
638185
639 const path_to_build_exe = try os.path.join(allocator, full_cache_dir, "build");
640 defer allocator.free(path_to_build_exe);
641 // codegen_set_cache_dir(g, full_cache_dir)
186 // need a new scope for proper defer scope finalization on exit
187 {
188 const build_template_path = try os.path.join(allocator, special_dir, "build_file_template.zig");
189 defer allocator.free(build_template_path);
642190
643 args.items[0] = path_to_build_exe;
644 args.items[1] = zig_exe_path;
645 args.items[2] = build_file_dirname;
646 args.items[3] = full_cache_dir;
191 try os.copyFile(allocator, build_template_path, build_file_abs);
192 try stderr.print("wrote build.zig template\n");
193 }
647194
648 var build_file_exists: bool = undefined;
649 if (os.File.openRead(allocator, build_file_abs)) |*file| {
650 file.close();
651 build_file_exists = true;
652 } else |_| {
653 build_file_exists = false;
195 os.exit(0);
654196 }
655197
656 if (!build_file_exists and asked_for_help) {
657 // TODO(bnoordhuis) Print help message from std/special/build_runner.zig
658 return;
198 if (!build_file_exists) {
199 try stderr.write(missing_build_file);
200 os.exit(1);
659201 }
660202
661 if (!build_file_exists and asked_for_init) {
662 const build_template_path = try os.path.join(allocator, special_dir, "build_file_template.zig");
663 defer allocator.free(build_template_path);
664
665 var srcfile = try os.File.openRead(allocator, build_template_path);
666 defer srcfile.close();
203 // TODO: Invoke build.zig entrypoint directly?
204 var zig_exe_path = try os.selfExePath(allocator);
205 defer allocator.free(zig_exe_path);
667206
668 var dstfile = try os.File.openWrite(allocator, build_file_abs);
669 defer dstfile.close();
207 var build_args = ArrayList([]const u8).init(allocator);
208 defer build_args.deinit();
670209
671 while (true) {
672 var buffer: [4096]u8 = undefined;
673 const n = try srcfile.read(buffer[0..]);
674 if (n == 0) break;
675 try dstfile.write(buffer[0..n]);
676 }
210 const build_file_basename = os.path.basename(build_file_abs);
211 const build_file_dirname = os.path.dirname(build_file_abs);
677212
678 return;
213 var full_cache_dir: []u8 = undefined;
214 if (flags.single("cache-dir")) |cache_dir| {
215 full_cache_dir = try os.path.resolve(allocator, ".", cache_dir, full_cache_dir);
216 } else {
217 full_cache_dir = try os.path.join(allocator, build_file_dirname, "zig-cache");
679218 }
219 defer allocator.free(full_cache_dir);
680220
681 if (!build_file_exists) {
682 warn(
683 \\No 'build.zig' file found.
684 \\Initialize a 'build.zig' template file with `zig build --init`,
685 \\or build an executable directly with `zig build-exe $FILENAME.zig`.
686 \\See: `zig build --help` or `zig help` for more options.
687 \\
688 );
689 os.exit(1);
690 }
221 const path_to_build_exe = try os.path.join(allocator, full_cache_dir, "build");
222 defer allocator.free(path_to_build_exe);
691223
692 // codegen_build(g)
693 // codegen_link(g, path_to_build_exe)
694 // codegen_destroy(g)
224 try build_args.append(path_to_build_exe);
225 try build_args.append(zig_exe_path);
226 try build_args.append(build_file_dirname);
227 try build_args.append(full_cache_dir);
695228
696 var proc = try os.ChildProcess.init(args.toSliceConst(), allocator);
229 var proc = try os.ChildProcess.init(build_args.toSliceConst(), allocator);
697230 defer proc.deinit();
698231
699232 var term = try proc.spawnAndWait();
700233 switch (term) {
701234 os.ChildProcess.Term.Exited => |status| {
702235 if (status != 0) {
703 warn("{} exited with status {}\n", args.at(0), status);
236 try stderr.print("{} exited with status {}\n", build_args.at(0), status);
704237 os.exit(1);
705238 }
706239 },
707240 os.ChildProcess.Term.Signal => |signal| {
708 warn("{} killed by signal {}\n", args.at(0), signal);
241 try stderr.print("{} killed by signal {}\n", build_args.at(0), signal);
709242 os.exit(1);
710243 },
711244 os.ChildProcess.Term.Stopped => |signal| {
712 warn("{} stopped by signal {}\n", args.at(0), signal);
245 try stderr.print("{} stopped by signal {}\n", build_args.at(0), signal);
713246 os.exit(1);
714247 },
715248 os.ChildProcess.Term.Unknown => |status| {
716 warn("{} encountered unknown failure {}\n", args.at(0), status);
249 try stderr.print("{} encountered unknown failure {}\n", build_args.at(0), status);
250 os.exit(1);
251 },
252 }
253}
254
255// cmd:build-exe ///////////////////////////////////////////////////////////////////////////////////
256
257const usage_build_generic =
258 \\usage: zig build-exe <options> [file]
259 \\ zig build-lib <options> [file]
260 \\ zig build-obj <options> [file]
261 \\
262 \\General Options:
263 \\ --help Print this help and exit
264 \\ --color [auto|off|on] Enable or disable colored error messages
265 \\
266 \\Compile Options:
267 \\ --assembly [source] Add assembly file to build
268 \\ --cache-dir [path] Override the cache directory
269 \\ --emit [filetype] Emit a specific file format as compilation output
270 \\ --enable-timing-info Print timing diagnostics
271 \\ --libc-include-dir [path] Directory where libc stdlib.h resides
272 \\ --name [name] Override output name
273 \\ --output [file] Override destination path
274 \\ --output-h [file] Override generated header file path
275 \\ --pkg-begin [name] [path] Make package available to import and push current pkg
276 \\ --pkg-end Pop current pkg
277 \\ --release-fast Build with optimizations on and safety off
278 \\ --release-safe Build with optimizations on and safety on
279 \\ --static Output will be statically linked
280 \\ --strip Exclude debug symbols
281 \\ --target-arch [name] Specify target architecture
282 \\ --target-environ [name] Specify target environment
283 \\ --target-os [name] Specify target operating system
284 \\ --verbose-tokenize Turn on compiler debug output for tokenization
285 \\ --verbose-ast-tree Turn on compiler debug output for parsing into an AST (tree view)
286 \\ --verbose-ast-fmt Turn on compiler debug output for parsing into an AST (render source)
287 \\ --verbose-link Turn on compiler debug output for linking
288 \\ --verbose-ir Turn on compiler debug output for Zig IR
289 \\ --verbose-llvm-ir Turn on compiler debug output for LLVM IR
290 \\ --verbose-cimport Turn on compiler debug output for C imports
291 \\ -dirafter [dir] Same as -isystem but do it last
292 \\ -isystem [dir] Add additional search path for other .h files
293 \\ -mllvm [arg] Additional arguments to forward to LLVM's option processing
294 \\
295 \\Link Options:
296 \\ --ar-path [path] Set the path to ar
297 \\ --dynamic-linker [path] Set the path to ld.so
298 \\ --each-lib-rpath Add rpath for each used dynamic library
299 \\ --libc-lib-dir [path] Directory where libc crt1.o resides
300 \\ --libc-static-lib-dir [path] Directory where libc crtbegin.o resides
301 \\ --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides
302 \\ --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides
303 \\ --library [lib] Link against lib
304 \\ --forbid-library [lib] Make it an error to link against lib
305 \\ --library-path [dir] Add a directory to the library search path
306 \\ --linker-script [path] Use a custom linker script
307 \\ --object [obj] Add object file to build
308 \\ -rdynamic Add all symbols to the dynamic symbol table
309 \\ -rpath [path] Add directory to the runtime library search path
310 \\ -mconsole (windows) --subsystem console to the linker
311 \\ -mwindows (windows) --subsystem windows to the linker
312 \\ -framework [name] (darwin) link against framework
313 \\ -mios-version-min [ver] (darwin) set iOS deployment target
314 \\ -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target
315 \\ --ver-major [ver] Dynamic library semver major version
316 \\ --ver-minor [ver] Dynamic library semver minor version
317 \\ --ver-patch [ver] Dynamic library semver patch version
318 \\
319 \\
320 ;
321
322const args_build_generic = []Flag {
323 Flag.Bool("--help"),
324 Flag.Option("--color", []const []const u8 { "auto", "off", "on" }),
325
326 Flag.ArgMergeN("--assembly", 1),
327 Flag.Arg1("--cache-dir"),
328 Flag.Option("--emit", []const []const u8 { "asm", "bin", "llvm-ir" }),
329 Flag.Bool("--enable-timing-info"),
330 Flag.Arg1("--libc-include-dir"),
331 Flag.Arg1("--name"),
332 Flag.Arg1("--output"),
333 Flag.Arg1("--output-h"),
334 // NOTE: Parsed manually after initial check
335 Flag.ArgN("--pkg-begin", 2),
336 Flag.Bool("--pkg-end"),
337 Flag.Bool("--release-fast"),
338 Flag.Bool("--release-safe"),
339 Flag.Bool("--static"),
340 Flag.Bool("--strip"),
341 Flag.Arg1("--target-arch"),
342 Flag.Arg1("--target-environ"),
343 Flag.Arg1("--target-os"),
344 Flag.Bool("--verbose-tokenize"),
345 Flag.Bool("--verbose-ast-tree"),
346 Flag.Bool("--verbose-ast-fmt"),
347 Flag.Bool("--verbose-link"),
348 Flag.Bool("--verbose-ir"),
349 Flag.Bool("--verbose-llvm-ir"),
350 Flag.Bool("--verbose-cimport"),
351 Flag.Arg1("-dirafter"),
352 Flag.ArgMergeN("-isystem", 1),
353 Flag.Arg1("-mllvm"),
354
355 Flag.Arg1("--ar-path"),
356 Flag.Arg1("--dynamic-linker"),
357 Flag.Bool("--each-lib-rpath"),
358 Flag.Arg1("--libc-lib-dir"),
359 Flag.Arg1("--libc-static-lib-dir"),
360 Flag.Arg1("--msvc-lib-dir"),
361 Flag.Arg1("--kernel32-lib-dir"),
362 Flag.ArgMergeN("--library", 1),
363 Flag.ArgMergeN("--forbid-library", 1),
364 Flag.ArgMergeN("--library-path", 1),
365 Flag.Arg1("--linker-script"),
366 Flag.ArgMergeN("--object", 1),
367 // NOTE: Removed -L since it would need to be special-cased and we have an alias in library-path
368 Flag.Bool("-rdynamic"),
369 Flag.Arg1("-rpath"),
370 Flag.Bool("-mconsole"),
371 Flag.Bool("-mwindows"),
372 Flag.ArgMergeN("-framework", 1),
373 Flag.Arg1("-mios-version-min"),
374 Flag.Arg1("-mmacosx-version-min"),
375 Flag.Arg1("--ver-major"),
376 Flag.Arg1("--ver-minor"),
377 Flag.Arg1("--ver-patch"),
378};
379
380fn buildOutputType(allocator: &Allocator, args: []const []const u8, out_type: Module.Kind) !void {
381 var flags = try Args.parse(allocator, args_build_generic, args);
382 defer flags.deinit();
383
384 if (flags.present("help")) {
385 try stderr.write(usage_build_generic);
386 os.exit(0);
387 }
388
389 var build_mode = builtin.Mode.Debug;
390 if (flags.present("release-fast")) {
391 build_mode = builtin.Mode.ReleaseFast;
392 } else if (flags.present("release-safe")) {
393 build_mode = builtin.Mode.ReleaseSafe;
394 }
395
396 var color = Module.ErrColor.Auto;
397 if (flags.single("color")) |color_flag| {
398 if (mem.eql(u8, color_flag, "auto")) {
399 color = Module.ErrColor.Auto;
400 } else if (mem.eql(u8, color_flag, "on")) {
401 color = Module.ErrColor.On;
402 } else if (mem.eql(u8, color_flag, "off")) {
403 color = Module.ErrColor.Off;
404 } else {
405 unreachable;
406 }
407 }
408
409 var emit_type = Module.Emit.Binary;
410 if (flags.single("emit")) |emit_flag| {
411 if (mem.eql(u8, emit_flag, "asm")) {
412 emit_type = Module.Emit.Assembly;
413 } else if (mem.eql(u8, emit_flag, "bin")) {
414 emit_type = Module.Emit.Binary;
415 } else if (mem.eql(u8, emit_flag, "llvm-ir")) {
416 emit_type = Module.Emit.LlvmIr;
417 } else {
418 unreachable;
419 }
420 }
421
422 var cur_pkg = try Module.CliPkg.init(allocator, "", "", null); // TODO: Need a path, name?
423 defer cur_pkg.deinit();
424
425 var i: usize = 0;
426 while (i < args.len) : (i += 1) {
427 const arg_name = args[i];
428 if (mem.eql(u8, "--pkg-begin", arg_name)) {
429 // following two arguments guaranteed to exist due to arg parsing
430 i += 1;
431 const new_pkg_name = args[i];
432 i += 1;
433 const new_pkg_path = args[i];
434
435 var new_cur_pkg = try Module.CliPkg.init(allocator, new_pkg_name, new_pkg_path, cur_pkg);
436 try cur_pkg.children.append(new_cur_pkg);
437 cur_pkg = new_cur_pkg;
438 } else if (mem.eql(u8, "--pkg-end", arg_name)) {
439 if (cur_pkg.parent == null) {
440 try stderr.print("encountered --pkg-end with no matching --pkg-begin\n");
441 os.exit(1);
442 }
443 cur_pkg = ??cur_pkg.parent;
444 }
445 }
446
447 if (cur_pkg.parent != null) {
448 try stderr.print("unmatched --pkg-begin\n");
449 os.exit(1);
450 }
451
452 var in_file: ?[]const u8 = undefined;
453 switch (flags.positionals.len) {
454 0 => {
455 try stderr.write("--name [name] not provided and unable to infer\n");
717456 os.exit(1);
718457 },
458 1 => {
459 in_file = flags.positionals.at(0);
460 },
461 else => {
462 try stderr.write("only one zig input file is accepted during build\n");
463 os.exit(1);
464 },
465 }
466
467 const basename = os.path.basename(??in_file);
468 var it = mem.split(basename, ".");
469 const root_name = it.next() ?? {
470 try stderr.write("file name cannot be empty\n");
471 os.exit(1);
472 };
473
474 const asm_a= flags.many("assembly");
475 const obj_a = flags.many("object");
476 if (in_file == null and (obj_a == null or (??obj_a).len == 0) and (asm_a == null or (??asm_a).len == 0)) {
477 try stderr.write("Expected source file argument or at least one --object or --assembly argument\n");
478 os.exit(1);
479 }
480
481 if (out_type == Module.Kind.Obj and (obj_a != null and (??obj_a).len != 0)) {
482 try stderr.write("When building an object file, --object arguments are invalid\n");
483 os.exit(1);
484 }
485
486 const zig_root_source_file = in_file;
487
488 const full_cache_dir = os.path.resolve(allocator, ".", flags.single("cache-dir") ?? "zig-cache"[0..]) catch {
489 os.exit(1);
490 };
491 defer allocator.free(full_cache_dir);
492
493 const zig_lib_dir = introspect.resolveZigLibDir(allocator) catch os.exit(1);
494 defer allocator.free(zig_lib_dir);
495
496 var module =
497 try Module.create(
498 allocator,
499 root_name,
500 zig_root_source_file,
501 Target.Native,
502 out_type,
503 build_mode,
504 zig_lib_dir,
505 full_cache_dir
506 );
507 defer module.destroy();
508
509 module.version_major = try std.fmt.parseUnsigned(u32, flags.single("ver-major") ?? "0", 10);
510 module.version_minor = try std.fmt.parseUnsigned(u32, flags.single("ver-minor") ?? "0", 10);
511 module.version_patch = try std.fmt.parseUnsigned(u32, flags.single("ver-patch") ?? "0", 10);
512
513 module.is_test = false;
514
515 if (flags.single("linker-script")) |linker_script| {
516 module.linker_script = linker_script;
517 }
518
519 module.each_lib_rpath = flags.present("each-lib-rpath");
520
521 var clang_argv_buf = ArrayList([]const u8).init(allocator);
522 defer clang_argv_buf.deinit();
523 if (flags.many("mllvm")) |mllvm_flags| {
524 for (mllvm_flags) |mllvm| {
525 try clang_argv_buf.append("-mllvm");
526 try clang_argv_buf.append(mllvm);
527 }
528
529 module.llvm_argv = mllvm_flags;
530 module.clang_argv = clang_argv_buf.toSliceConst();
531 }
532
533 module.strip = flags.present("strip");
534 module.is_static = flags.present("static");
535
536 if (flags.single("libc-lib-dir")) |libc_lib_dir| {
537 module.libc_lib_dir = libc_lib_dir;
538 }
539 if (flags.single("libc-static-lib-dir")) |libc_static_lib_dir| {
540 module.libc_static_lib_dir = libc_static_lib_dir;
541 }
542 if (flags.single("libc-include-dir")) |libc_include_dir| {
543 module.libc_include_dir = libc_include_dir;
544 }
545 if (flags.single("msvc-lib-dir")) |msvc_lib_dir| {
546 module.msvc_lib_dir = msvc_lib_dir;
547 }
548 if (flags.single("kernel32-lib-dir")) |kernel32_lib_dir| {
549 module.kernel32_lib_dir = kernel32_lib_dir;
550 }
551 if (flags.single("dynamic-linker")) |dynamic_linker| {
552 module.dynamic_linker = dynamic_linker;
553 }
554
555 module.verbose_tokenize = flags.present("verbose-tokenize");
556 module.verbose_ast_tree = flags.present("verbose-ast-tree");
557 module.verbose_ast_fmt = flags.present("verbose-ast-fmt");
558 module.verbose_link = flags.present("verbose-link");
559 module.verbose_ir = flags.present("verbose-ir");
560 module.verbose_llvm_ir = flags.present("verbose-llvm-ir");
561 module.verbose_cimport = flags.present("verbose-cimport");
562
563 module.err_color = color;
564
565 if (flags.many("library-path")) |lib_dirs| {
566 module.lib_dirs = lib_dirs;
567 }
568
569 if (flags.many("framework")) |frameworks| {
570 module.darwin_frameworks = frameworks;
571 }
572
573 if (flags.many("rpath")) |rpath_list| {
574 module.rpath_list = rpath_list;
719575 }
576
577 if (flags.single("output-h")) |output_h| {
578 module.out_h_path = output_h;
579 }
580
581 module.windows_subsystem_windows = flags.present("mwindows");
582 module.windows_subsystem_console = flags.present("mconsole");
583 module.linker_rdynamic = flags.present("rdynamic");
584
585 if (flags.single("mmacosx-version-min") != null and flags.single("mios-version-min") != null) {
586 try stderr.write("-mmacosx-version-min and -mios-version-min options not allowed together\n");
587 os.exit(1);
588 }
589
590 if (flags.single("mmacosx-version-min")) |ver| {
591 module.darwin_version_min = Module.DarwinVersionMin { .MacOS = ver };
592 }
593 if (flags.single("mios-version-min")) |ver| {
594 module.darwin_version_min = Module.DarwinVersionMin { .Ios = ver };
595 }
596
597 module.emit_file_type = emit_type;
598 if (flags.many("object")) |objects| {
599 module.link_objects = objects;
600 }
601 if (flags.many("assembly")) |assembly_files| {
602 module.assembly_files = assembly_files;
603 }
604
605 try module.build();
606 try module.link(flags.single("out-file") ?? null);
607
608 if (flags.present("print-timing-info")) {
609 // codegen_print_timing_info(g, stderr);
610 }
611
612 try stderr.print("building {}: {}\n", @tagName(out_type), in_file);
613}
614
615fn cmdBuildExe(allocator: &Allocator, args: []const []const u8) !void {
616 try buildOutputType(allocator, args, Module.Kind.Exe);
720617}
721618
722fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {
723 for (file_paths) |file_path| {
619// cmd:build-lib ///////////////////////////////////////////////////////////////////////////////////
620
621fn cmdBuildLib(allocator: &Allocator, args: []const []const u8) !void {
622 try buildOutputType(allocator, args, Module.Kind.Lib);
623}
624
625// cmd:build-obj ///////////////////////////////////////////////////////////////////////////////////
626
627fn cmdBuildObj(allocator: &Allocator, args: []const []const u8) !void {
628 try buildOutputType(allocator, args, Module.Kind.Obj);
629}
630
631// cmd:fmt /////////////////////////////////////////////////////////////////////////////////////////
632
633const usage_fmt =
634 \\usage: zig fmt [file]...
635 \\
636 \\ Formats the input files and modifies them in-place.
637 \\
638 \\Options:
639 \\ --help Print this help and exit
640 \\ --keep-backups Retain backup entries for every file
641 \\
642 \\
643 ;
644
645const args_fmt_spec = []Flag {
646 Flag.Bool("--help"),
647 Flag.Bool("--keep-backups"),
648};
649
650fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void {
651 var flags = try Args.parse(allocator, args_fmt_spec, args);
652 defer flags.deinit();
653
654 if (flags.present("help")) {
655 try stderr.write(usage_fmt);
656 os.exit(0);
657 }
658
659 if (flags.positionals.len == 0) {
660 try stderr.write("expected at least one source file argument\n");
661 os.exit(1);
662 }
663
664 for (flags.positionals.toSliceConst()) |file_path| {
724665 var file = try os.File.openRead(allocator, file_path);
725666 defer file.close();
726667
727668 const source_code = io.readFileAlloc(allocator, file_path) catch |err| {
728 warn("unable to open '{}': {}", file_path, err);
669 try stderr.print("unable to open '{}': {}", file_path, err);
729670 continue;
730671 };
731672 defer allocator.free(source_code);
......@@ -734,72 +675,312 @@ fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {
734675 var parser = std.zig.Parser.init(&tokenizer, allocator, file_path);
735676 defer parser.deinit();
736677
737 var tree = try parser.parse();
678 var tree = parser.parse() catch |err| {
679 try stderr.print("error parsing file '{}': {}\n", file_path, err);
680 continue;
681 };
738682 defer tree.deinit();
739683
740 const baf = try io.BufferedAtomicFile.create(allocator, file_path);
741 defer baf.destroy();
684 var original_file_backup = try Buffer.init(allocator, file_path);
685 defer original_file_backup.deinit();
686 try original_file_backup.append(".backup");
687
688 try os.rename(allocator, file_path, original_file_backup.toSliceConst());
742689
743 try parser.renderSource(baf.stream(), tree.root_node);
744 try baf.finish();
690 try stderr.print("{}\n", file_path);
691
692 // TODO: BufferedAtomicFile has some access problems.
693 var out_file = try os.File.openWrite(allocator, file_path);
694 defer out_file.close();
695
696 var out_file_stream = io.FileOutStream.init(&out_file);
697 try parser.renderSource(out_file_stream.stream, tree.root_node);
698
699 if (!flags.present("keep-backups")) {
700 try os.deleteFile(allocator, original_file_backup.toSliceConst());
701 }
745702 }
746703}
747704
748/// Caller must free result
749fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const u8) ![]u8 {
750 if (zig_install_prefix_arg) |zig_install_prefix| {
751 return testZigInstallPrefix(allocator, zig_install_prefix) catch |err| {
752 warn("No Zig installation found at prefix {}: {}\n", zig_install_prefix_arg, @errorName(err));
753 return error.ZigInstallationNotFound;
754 };
755 } else {
756 return findZigLibDir(allocator) catch |err| {
757 warn("Unable to find zig lib directory: {}.\nReinstall Zig or use --zig-install-prefix.\n",
758 @errorName(err));
759 return error.ZigLibDirNotFound;
760 };
705// cmd:targets /////////////////////////////////////////////////////////////////////////////////////
706
707fn cmdTargets(allocator: &Allocator, args: []const []const u8) !void {
708 try stdout.write("Architectures:\n");
709 {
710 comptime var i: usize = 0;
711 inline while (i < @memberCount(builtin.Arch)) : (i += 1) {
712 comptime const arch_tag = @memberName(builtin.Arch, i);
713 // NOTE: Cannot use empty string, see #918.
714 comptime const native_str =
715 if (comptime mem.eql(u8, arch_tag, @tagName(builtin.arch))) " (native)\n" else "\n";
716
717 try stdout.print(" {}{}", arch_tag, native_str);
718 }
719 }
720 try stdout.write("\n");
721
722 try stdout.write("Operating Systems:\n");
723 {
724 comptime var i: usize = 0;
725 inline while (i < @memberCount(builtin.Os)) : (i += 1) {
726 comptime const os_tag = @memberName(builtin.Os, i);
727 // NOTE: Cannot use empty string, see #918.
728 comptime const native_str =
729 if (comptime mem.eql(u8, os_tag, @tagName(builtin.os))) " (native)\n" else "\n";
730
731 try stdout.print(" {}{}", os_tag, native_str);
732 }
733 }
734 try stdout.write("\n");
735
736 try stdout.write("Environments:\n");
737 {
738 comptime var i: usize = 0;
739 inline while (i < @memberCount(builtin.Environ)) : (i += 1) {
740 comptime const environ_tag = @memberName(builtin.Environ, i);
741 // NOTE: Cannot use empty string, see #918.
742 comptime const native_str =
743 if (comptime mem.eql(u8, environ_tag, @tagName(builtin.environ))) " (native)\n" else "\n";
744
745 try stdout.print(" {}{}", environ_tag, native_str);
746 }
761747 }
762748}
763749
764/// Caller must free result
765fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) ![]u8 {
766 const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig");
767 errdefer allocator.free(test_zig_dir);
750// cmd:version /////////////////////////////////////////////////////////////////////////////////////
751
752fn cmdVersion(allocator: &Allocator, args: []const []const u8) !void {
753 try stdout.print("{}\n", std.cstr.toSliceConst(c.ZIG_VERSION_STRING));
754}
768755
769 const test_index_file = try os.path.join(allocator, test_zig_dir, "std", "index.zig");
770 defer allocator.free(test_index_file);
756// cmd:test ////////////////////////////////////////////////////////////////////////////////////////
771757
772 var file = try os.File.openRead(allocator, test_index_file);
773 file.close();
758const usage_test =
759 \\usage: zig test [file]...
760 \\
761 \\Options:
762 \\ --help Print this help and exit
763 \\
764 \\
765 ;
766
767const args_test_spec = []Flag {
768 Flag.Bool("--help"),
769};
770
771
772fn cmdTest(allocator: &Allocator, args: []const []const u8) !void {
773 var flags = try Args.parse(allocator, args_build_spec, args);
774 defer flags.deinit();
775
776 if (flags.present("help")) {
777 try stderr.write(usage_test);
778 os.exit(0);
779 }
774780
775 return test_zig_dir;
781 if (flags.positionals.len != 1) {
782 try stderr.write("expected exactly one zig source file\n");
783 os.exit(1);
784 }
785
786 // compile the test program into the cache and run
787
788 // NOTE: May be overlap with buildOutput, take the shared part out.
789 try stderr.print("testing file {}\n", flags.positionals.at(0));
776790}
777791
778/// Caller must free result
779fn findZigLibDir(allocator: &mem.Allocator) ![]u8 {
780 const self_exe_path = try os.selfExeDirPath(allocator);
781 defer allocator.free(self_exe_path);
792// cmd:run /////////////////////////////////////////////////////////////////////////////////////////
793
794// Run should be simple and not expose the full set of arguments provided by build-exe. If specific
795// build requirements are need, the user should `build-exe` then `run` manually.
796const usage_run =
797 \\usage: zig run [file] -- <runtime args>
798 \\
799 \\Options:
800 \\ --help Print this help and exit
801 \\
802 \\
803 ;
804
805const args_run_spec = []Flag {
806 Flag.Bool("--help"),
807};
782808
783 var cur_path: []const u8 = self_exe_path;
784 while (true) {
785 const test_dir = os.path.dirname(cur_path);
786809
787 if (mem.eql(u8, test_dir, cur_path)) {
810fn cmdRun(allocator: &Allocator, args: []const []const u8) !void {
811 var compile_args = args;
812 var runtime_args: []const []const u8 = []const []const u8 {};
813
814 for (args) |argv, i| {
815 if (mem.eql(u8, argv, "--")) {
816 compile_args = args[0..i];
817 runtime_args = args[i+1..];
788818 break;
789819 }
820 }
821 var flags = try Args.parse(allocator, args_run_spec, compile_args);
822 defer flags.deinit();
790823
791 return testZigInstallPrefix(allocator, test_dir) catch |err| {
792 cur_path = test_dir;
793 continue;
794 };
824 if (flags.present("help")) {
825 try stderr.write(usage_run);
826 os.exit(0);
827 }
828
829 if (flags.positionals.len != 1) {
830 try stderr.write("expected exactly one zig source file\n");
831 os.exit(1);
832 }
833
834 try stderr.print("runtime args:\n");
835 for (runtime_args) |cargs| {
836 try stderr.print("{}\n", cargs);
837 }
838}
839
840// cmd:translate-c /////////////////////////////////////////////////////////////////////////////////
841
842const usage_translate_c =
843 \\usage: zig translate-c [file]
844 \\
845 \\Options:
846 \\ --help Print this help and exit
847 \\ --enable-timing-info Print timing diagnostics
848 \\ --output [path] Output file to write generated zig file (default: stdout)
849 \\
850 \\
851 ;
852
853const args_translate_c_spec = []Flag {
854 Flag.Bool("--help"),
855 Flag.Bool("--enable-timing-info"),
856 Flag.Arg1("--libc-include-dir"),
857 Flag.Arg1("--output"),
858};
859
860fn cmdTranslateC(allocator: &Allocator, args: []const []const u8) !void {
861 var flags = try Args.parse(allocator, args_translate_c_spec, args);
862 defer flags.deinit();
863
864 if (flags.present("help")) {
865 try stderr.write(usage_translate_c);
866 os.exit(0);
867 }
868
869 if (flags.positionals.len != 1) {
870 try stderr.write("expected exactly one c source file\n");
871 os.exit(1);
872 }
873
874 // set up codegen
875
876 const zig_root_source_file = null;
877
878 // NOTE: translate-c shouldn't require setting up the full codegen instance as it does in
879 // the C++ compiler.
880
881 // codegen_create(g);
882 // codegen_set_out_name(g, null);
883 // codegen_translate_c(g, flags.positional.at(0))
884
885 var output_stream = stdout;
886 if (flags.single("output")) |output_file| {
887 var file = try os.File.openWrite(allocator, output_file);
888 defer file.close();
889
890 var file_stream = io.FileOutStream.init(&file);
891 // TODO: Not being set correctly, still stdout
892 output_stream = &file_stream.stream;
795893 }
796894
797 // TODO look in hard coded installation path from configuration
798 //if (ZIG_INSTALL_PREFIX != nullptr) {
799 // if (test_zig_install_prefix(buf_create_from_str(ZIG_INSTALL_PREFIX), out_path)) {
800 // return 0;
801 // }
802 //}
895 // ast_render(g, output_stream, g->root_import->root, 4);
896 try output_stream.write("pub const example = 10;\n");
897
898 if (flags.present("enable-timing-info")) {
899 // codegen_print_timing_info(g, stdout);
900 try stderr.write("printing timing info for translate-c\n");
901 }
902}
903
904// cmd:help ////////////////////////////////////////////////////////////////////////////////////////
803905
804 return error.FileNotFound;
906fn cmdHelp(allocator: &Allocator, args: []const []const u8) !void {
907 try stderr.write(usage);
908}
909
910// cmd:zen /////////////////////////////////////////////////////////////////////////////////////////
911
912const info_zen =
913 \\
914 \\ * Communicate intent precisely.
915 \\ * Edge cases matter.
916 \\ * Favor reading code over writing code.
917 \\ * Only one obvious way to do things.
918 \\ * Runtime crashes are better than bugs.
919 \\ * Compile errors are better than runtime crashes.
920 \\ * Incremental improvements.
921 \\ * Avoid local maximums.
922 \\ * Reduce the amount one must remember.
923 \\ * Minimize energy spent on coding style.
924 \\ * Together we serve end users.
925 \\
926 \\
927 ;
928
929fn cmdZen(allocator: &Allocator, args: []const []const u8) !void {
930 try stdout.write(info_zen);
931}
932
933// cmd:internal ////////////////////////////////////////////////////////////////////////////////////
934
935const usage_internal =
936 \\usage: zig internal [subcommand]
937 \\
938 \\Sub-Commands:
939 \\ build-info Print static compiler build-info
940 \\
941 \\
942 ;
943
944fn cmdInternal(allocator: &Allocator, args: []const []const u8) !void {
945 if (args.len == 0) {
946 try stderr.write(usage_internal);
947 os.exit(1);
948 }
949
950 const sub_commands = []Command {
951 Command { .name = "build-info", .exec = cmdInternalBuildInfo },
952 };
953
954 for (sub_commands) |sub_command| {
955 if (mem.eql(u8, sub_command.name, args[0])) {
956 try sub_command.exec(allocator, args[1..]);
957 return;
958 }
959 }
960
961 try stderr.print("unknown sub command: {}\n\n", args[0]);
962 try stderr.write(usage_internal);
963}
964
965fn cmdInternalBuildInfo(allocator: &Allocator, args: []const []const u8) !void {
966 try stdout.print(
967 \\ZIG_CMAKE_BINARY_DIR {}
968 \\ZIG_CXX_COMPILER {}
969 \\ZIG_LLVM_CONFIG_EXE {}
970 \\ZIG_LLD_INCLUDE_PATH {}
971 \\ZIG_LLD_LIBRARIES {}
972 \\ZIG_STD_FILES {}
973 \\ZIG_C_HEADER_FILES {}
974 \\ZIG_DIA_GUIDS_LIB {}
975 \\
976 ,
977 std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR),
978 std.cstr.toSliceConst(c.ZIG_CXX_COMPILER),
979 std.cstr.toSliceConst(c.ZIG_LLVM_CONFIG_EXE),
980 std.cstr.toSliceConst(c.ZIG_LLD_INCLUDE_PATH),
981 std.cstr.toSliceConst(c.ZIG_LLD_LIBRARIES),
982 std.cstr.toSliceConst(c.ZIG_STD_FILES),
983 std.cstr.toSliceConst(c.ZIG_C_HEADER_FILES),
984 std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),
985 );
805986}
src-self-hosted/module.zig+23
......@@ -109,6 +109,29 @@ pub const Module = struct {
109109 LlvmIr,
110110 };
111111
112 pub const CliPkg = struct {
113 name: []const u8,
114 path: []const u8,
115 children: ArrayList(&CliPkg),
116 parent: ?&CliPkg,
117
118 pub fn init(allocator: &mem.Allocator, name: []const u8, path: []const u8, parent: ?&CliPkg) !&CliPkg {
119 var pkg = try allocator.create(CliPkg);
120 pkg.name = name;
121 pkg.path = path;
122 pkg.children = ArrayList(&CliPkg).init(allocator);
123 pkg.parent = parent;
124 return pkg;
125 }
126
127 pub fn deinit(self: &CliPkg) void {
128 for (self.children.toSliceConst()) |child| {
129 child.deinit();
130 }
131 self.children.deinit();
132 }
133 };
134
112135 pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target,
113136 kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) !&Module
114137 {
src/all_types.hpp+49-3
......@@ -867,6 +867,7 @@ struct AstNodeAwaitExpr {
867867};
868868
869869struct AstNodeSuspend {
870 Buf *name;
870871 AstNode *block;
871872 AstNode *promise_symbol;
872873};
......@@ -1291,6 +1292,7 @@ enum BuiltinFnId {
12911292 BuiltinFnIdMemberCount,
12921293 BuiltinFnIdMemberType,
12931294 BuiltinFnIdMemberName,
1295 BuiltinFnIdField,
12941296 BuiltinFnIdTypeof,
12951297 BuiltinFnIdAddWithOverflow,
12961298 BuiltinFnIdSubWithOverflow,
......@@ -1310,13 +1312,15 @@ enum BuiltinFnId {
13101312 BuiltinFnIdReturnAddress,
13111313 BuiltinFnIdFrameAddress,
13121314 BuiltinFnIdEmbedFile,
1313 BuiltinFnIdCmpExchange,
1315 BuiltinFnIdCmpxchgWeak,
1316 BuiltinFnIdCmpxchgStrong,
13141317 BuiltinFnIdFence,
13151318 BuiltinFnIdDivExact,
13161319 BuiltinFnIdDivTrunc,
13171320 BuiltinFnIdDivFloor,
13181321 BuiltinFnIdRem,
13191322 BuiltinFnIdMod,
1323 BuiltinFnIdSqrt,
13201324 BuiltinFnIdTruncate,
13211325 BuiltinFnIdIntType,
13221326 BuiltinFnIdSetCold,
......@@ -1346,6 +1350,7 @@ enum BuiltinFnId {
13461350 BuiltinFnIdExport,
13471351 BuiltinFnIdErrorReturnTrace,
13481352 BuiltinFnIdAtomicRmw,
1353 BuiltinFnIdAtomicLoad,
13491354};
13501355
13511356struct BuiltinFnEntry {
......@@ -1413,6 +1418,7 @@ enum ZigLLVMFnId {
14131418 ZigLLVMFnIdOverflowArithmetic,
14141419 ZigLLVMFnIdFloor,
14151420 ZigLLVMFnIdCeil,
1421 ZigLLVMFnIdSqrt,
14161422};
14171423
14181424enum AddSubMul {
......@@ -1433,7 +1439,7 @@ struct ZigLLVMFnKey {
14331439 } clz;
14341440 struct {
14351441 uint32_t bit_count;
1436 } floor_ceil;
1442 } floating;
14371443 struct {
14381444 AddSubMul add_sub_mul;
14391445 uint32_t bit_count;
......@@ -1454,6 +1460,7 @@ enum BuildMode {
14541460 BuildModeDebug,
14551461 BuildModeFastRelease,
14561462 BuildModeSafeRelease,
1463 BuildModeSmallRelease,
14571464};
14581465
14591466enum EmitFileType {
......@@ -1698,6 +1705,8 @@ struct CodeGen {
16981705 ZigList<ZigLLVMDIType **> error_di_types;
16991706
17001707 ZigList<Buf *> forbidden_libs;
1708
1709 bool no_rosegment_workaround;
17011710};
17021711
17031712enum VarLinkage {
......@@ -1748,6 +1757,7 @@ enum ScopeId {
17481757 ScopeIdVarDecl,
17491758 ScopeIdCImport,
17501759 ScopeIdLoop,
1760 ScopeIdSuspend,
17511761 ScopeIdFnDef,
17521762 ScopeIdCompTime,
17531763 ScopeIdCoroPrelude,
......@@ -1843,6 +1853,17 @@ struct ScopeLoop {
18431853 ZigList<IrBasicBlock *> *incoming_blocks;
18441854};
18451855
1856// This scope is created for a suspend block in order to have labeled
1857// suspend for breaking out of a suspend and for detecting if a suspend
1858// block is inside a suspend block.
1859struct ScopeSuspend {
1860 Scope base;
1861
1862 Buf *name;
1863 IrBasicBlock *resume_block;
1864 bool reported_err;
1865};
1866
18461867// This scope is created for a comptime expression.
18471868// NodeTypeCompTime, NodeTypeSwitchExpr
18481869struct ScopeCompTime {
......@@ -2039,12 +2060,14 @@ enum IrInstructionId {
20392060 IrInstructionIdCoroPromise,
20402061 IrInstructionIdCoroAllocHelper,
20412062 IrInstructionIdAtomicRmw,
2063 IrInstructionIdAtomicLoad,
20422064 IrInstructionIdPromiseResultType,
20432065 IrInstructionIdAwaitBookkeeping,
20442066 IrInstructionIdSaveErrRetAddr,
20452067 IrInstructionIdAddImplicitReturnType,
20462068 IrInstructionIdMergeErrRetTraces,
20472069 IrInstructionIdMarkErrRetTracePtr,
2070 IrInstructionIdSqrt,
20482071};
20492072
20502073struct IrInstruction {
......@@ -2201,7 +2224,8 @@ struct IrInstructionFieldPtr {
22012224 IrInstruction base;
22022225
22032226 IrInstruction *container_ptr;
2204 Buf *field_name;
2227 Buf *field_name_buffer;
2228 IrInstruction *field_name_expr;
22052229 bool is_const;
22062230};
22072231
......@@ -2520,6 +2544,7 @@ struct IrInstructionEmbedFile {
25202544struct IrInstructionCmpxchg {
25212545 IrInstruction base;
25222546
2547 IrInstruction *type_value;
25232548 IrInstruction *ptr;
25242549 IrInstruction *cmp_value;
25252550 IrInstruction *new_value;
......@@ -2527,8 +2552,13 @@ struct IrInstructionCmpxchg {
25272552 IrInstruction *failure_order_value;
25282553
25292554 // if this instruction gets to runtime then we know these values:
2555 TypeTableEntry *type;
25302556 AtomicOrder success_order;
25312557 AtomicOrder failure_order;
2558
2559 bool is_weak;
2560
2561 LLVMValueRef tmp_ptr;
25322562};
25332563
25342564struct IrInstructionFence {
......@@ -2998,6 +3028,15 @@ struct IrInstructionAtomicRmw {
29983028 AtomicOrder resolved_ordering;
29993029};
30003030
3031struct IrInstructionAtomicLoad {
3032 IrInstruction base;
3033
3034 IrInstruction *operand_type;
3035 IrInstruction *ptr;
3036 IrInstruction *ordering;
3037 AtomicOrder resolved_ordering;
3038};
3039
30013040struct IrInstructionPromiseResultType {
30023041 IrInstruction base;
30033042
......@@ -3034,6 +3073,13 @@ struct IrInstructionMarkErrRetTracePtr {
30343073 IrInstruction *err_ret_trace_ptr;
30353074};
30363075
3076struct IrInstructionSqrt {
3077 IrInstruction base;
3078
3079 IrInstruction *type;
3080 IrInstruction *op;
3081};
3082
30373083static const size_t slice_ptr_index = 0;
30383084static const size_t slice_len_index = 1;
30393085
src/analyze.cpp+40-17
......@@ -156,6 +156,14 @@ ScopeLoop *create_loop_scope(AstNode *node, Scope *parent) {
156156 return scope;
157157}
158158
159ScopeSuspend *create_suspend_scope(AstNode *node, Scope *parent) {
160 assert(node->type == NodeTypeSuspend);
161 ScopeSuspend *scope = allocate<ScopeSuspend>(1);
162 init_scope(&scope->base, ScopeIdSuspend, node, parent);
163 scope->name = node->data.suspend.name;
164 return scope;
165}
166
159167ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry) {
160168 ScopeFnDef *scope = allocate<ScopeFnDef>(1);
161169 init_scope(&scope->base, ScopeIdFnDef, node, parent);
......@@ -3616,6 +3624,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) {
36163624 case ScopeIdVarDecl:
36173625 case ScopeIdCImport:
36183626 case ScopeIdLoop:
3627 case ScopeIdSuspend:
36193628 case ScopeIdCompTime:
36203629 case ScopeIdCoroPrelude:
36213630 scope = scope->parent;
......@@ -4297,7 +4306,8 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
42974306static ZigWindowsSDK *get_windows_sdk(CodeGen *g) {
42984307 if (g->win_sdk == nullptr) {
42994308 if (os_find_windows_sdk(&g->win_sdk)) {
4300 zig_panic("Unable to determine Windows SDK path.");
4309 fprintf(stderr, "unable to determine windows sdk path\n");
4310 exit(1);
43014311 }
43024312 }
43034313 assert(g->win_sdk != nullptr);
......@@ -4399,7 +4409,8 @@ void find_libc_include_path(CodeGen *g) {
43994409 ZigWindowsSDK *sdk = get_windows_sdk(g);
44004410 g->libc_include_dir = buf_alloc();
44014411 if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) {
4402 zig_panic("Unable to determine libc include path.");
4412 fprintf(stderr, "Unable to determine libc include path. --libc-include-dir");
4413 exit(1);
44034414 }
44044415 } else if (g->zig_target.os == OsLinux) {
44054416 g->libc_include_dir = get_linux_libc_include_path();
......@@ -4421,24 +4432,33 @@ void find_libc_lib_path(CodeGen *g) {
44214432 if (g->zig_target.os == OsWindows) {
44224433 ZigWindowsSDK *sdk = get_windows_sdk(g);
44234434
4424 Buf* vc_lib_dir = buf_alloc();
4425 if (os_get_win32_vcruntime_path(vc_lib_dir, g->zig_target.arch.arch)) {
4426 zig_panic("Unable to determine vcruntime path.");
4435 if (g->msvc_lib_dir == nullptr) {
4436 Buf* vc_lib_dir = buf_alloc();
4437 if (os_get_win32_vcruntime_path(vc_lib_dir, g->zig_target.arch.arch)) {
4438 fprintf(stderr, "Unable to determine vcruntime path. --msvc-lib-dir");
4439 exit(1);
4440 }
4441 g->msvc_lib_dir = vc_lib_dir;
44274442 }
44284443
4429 Buf* ucrt_lib_path = buf_alloc();
4430 if (os_get_win32_ucrt_lib_path(sdk, ucrt_lib_path, g->zig_target.arch.arch)) {
4431 zig_panic("Unable to determine ucrt path.");
4444 if (g->libc_lib_dir == nullptr) {
4445 Buf* ucrt_lib_path = buf_alloc();
4446 if (os_get_win32_ucrt_lib_path(sdk, ucrt_lib_path, g->zig_target.arch.arch)) {
4447 fprintf(stderr, "Unable to determine ucrt path. --libc-lib-dir");
4448 exit(1);
4449 }
4450 g->libc_lib_dir = ucrt_lib_path;
44324451 }
44334452
4434 Buf* kern_lib_path = buf_alloc();
4435 if (os_get_win32_kern32_path(sdk, kern_lib_path, g->zig_target.arch.arch)) {
4436 zig_panic("Unable to determine kernel32 path.");
4453 if (g->kernel32_lib_dir == nullptr) {
4454 Buf* kern_lib_path = buf_alloc();
4455 if (os_get_win32_kern32_path(sdk, kern_lib_path, g->zig_target.arch.arch)) {
4456 fprintf(stderr, "Unable to determine kernel32 path. --kernel32-lib-dir");
4457 exit(1);
4458 }
4459 g->kernel32_lib_dir = kern_lib_path;
44374460 }
44384461
4439 g->msvc_lib_dir = vc_lib_dir;
4440 g->libc_lib_dir = ucrt_lib_path;
4441 g->kernel32_lib_dir = kern_lib_path;
44424462 } else if (g->zig_target.os == OsLinux) {
44434463 g->libc_lib_dir = get_linux_libc_lib_path("crt1.o");
44444464 } else {
......@@ -5801,9 +5821,11 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) {
58015821 case ZigLLVMFnIdClz:
58025822 return (uint32_t)(x.data.clz.bit_count) * (uint32_t)2428952817;
58035823 case ZigLLVMFnIdFloor:
5804 return (uint32_t)(x.data.floor_ceil.bit_count) * (uint32_t)1899859168;
5824 return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1899859168;
58055825 case ZigLLVMFnIdCeil:
5806 return (uint32_t)(x.data.floor_ceil.bit_count) * (uint32_t)1953839089;
5826 return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1953839089;
5827 case ZigLLVMFnIdSqrt:
5828 return (uint32_t)(x.data.floating.bit_count) * (uint32_t)2225366385;
58075829 case ZigLLVMFnIdOverflowArithmetic:
58085830 return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) +
58095831 ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) +
......@@ -5822,7 +5844,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {
58225844 return a.data.clz.bit_count == b.data.clz.bit_count;
58235845 case ZigLLVMFnIdFloor:
58245846 case ZigLLVMFnIdCeil:
5825 return a.data.floor_ceil.bit_count == b.data.floor_ceil.bit_count;
5847 case ZigLLVMFnIdSqrt:
5848 return a.data.floating.bit_count == b.data.floating.bit_count;
58265849 case ZigLLVMFnIdOverflowArithmetic:
58275850 return (a.data.overflow_arithmetic.bit_count == b.data.overflow_arithmetic.bit_count) &&
58285851 (a.data.overflow_arithmetic.add_sub_mul == b.data.overflow_arithmetic.add_sub_mul) &&
src/analyze.hpp+1
......@@ -104,6 +104,7 @@ ScopeDeferExpr *create_defer_expr_scope(AstNode *node, Scope *parent);
104104Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var);
105105ScopeCImport *create_cimport_scope(AstNode *node, Scope *parent);
106106ScopeLoop *create_loop_scope(AstNode *node, Scope *parent);
107ScopeSuspend *create_suspend_scope(AstNode *node, Scope *parent);
107108ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry);
108109ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import);
109110Scope *create_comptime_scope(AstNode *node, Scope *parent);
src/bigfloat.cpp+4
......@@ -181,3 +181,7 @@ bool bigfloat_has_fraction(const BigFloat *bigfloat) {
181181 f128M_roundToInt(&bigfloat->value, softfloat_round_minMag, false, &floored);
182182 return !f128M_eq(&floored, &bigfloat->value);
183183}
184
185void bigfloat_sqrt(BigFloat *dest, const BigFloat *op) {
186 f128M_sqrt(&op->value, &dest->value);
187}
src/bigfloat.hpp+1
......@@ -42,6 +42,7 @@ void bigfloat_div_trunc(BigFloat *dest, const BigFloat *op1, const BigFloat *op2
4242void bigfloat_div_floor(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
4343void bigfloat_rem(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
4444void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
45void bigfloat_sqrt(BigFloat *dest, const BigFloat *op);
4546void bigfloat_append_buf(Buf *buf, const BigFloat *op);
4647Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2);
4748
src/bigint.cpp+5
......@@ -86,6 +86,11 @@ static void to_twos_complement(BigInt *dest, const BigInt *op, size_t bit_count)
8686 size_t digits_to_copy = bit_count / 64;
8787 size_t leftover_bits = bit_count % 64;
8888 dest->digit_count = digits_to_copy + ((leftover_bits == 0) ? 0 : 1);
89 if (dest->digit_count == 1 && leftover_bits == 0) {
90 dest->data.digit = op_digits[0];
91 if (dest->data.digit == 0) dest->digit_count = 0;
92 return;
93 }
8994 dest->data.digits = allocate_nonzero<uint64_t>(dest->digit_count);
9095 for (size_t i = 0; i < digits_to_copy; i += 1) {
9196 uint64_t digit = (i < op->digit_count) ? op_digits[i] : 0;
src/codegen.cpp+81-19
......@@ -471,7 +471,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
471471 fn_table_entry->llvm_value, buf_ptr(&fn_export->name));
472472 }
473473 }
474 fn_table_entry->llvm_name = LLVMGetValueName(fn_table_entry->llvm_value);
474 fn_table_entry->llvm_name = strdup(LLVMGetValueName(fn_table_entry->llvm_value));
475475
476476 switch (fn_table_entry->fn_inline) {
477477 case FnInlineAlways:
......@@ -516,7 +516,9 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
516516 }
517517
518518 if (fn_table_entry->body_node != nullptr) {
519 bool want_fn_safety = g->build_mode != BuildModeFastRelease && !fn_table_entry->def_scope->safety_off;
519 bool want_fn_safety = g->build_mode != BuildModeFastRelease &&
520 g->build_mode != BuildModeSmallRelease &&
521 !fn_table_entry->def_scope->safety_off;
520522 if (want_fn_safety) {
521523 if (g->libc_link_lib != nullptr) {
522524 addLLVMFnAttr(fn_table_entry->llvm_value, "sspstrong");
......@@ -656,6 +658,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
656658 }
657659 case ScopeIdDeferExpr:
658660 case ScopeIdLoop:
661 case ScopeIdSuspend:
659662 case ScopeIdCompTime:
660663 case ScopeIdCoroPrelude:
661664 return get_di_scope(g, scope->parent);
......@@ -721,12 +724,12 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, TypeTableEntry *type_entry,
721724 return fn_val;
722725}
723726
724static LLVMValueRef get_floor_ceil_fn(CodeGen *g, TypeTableEntry *type_entry, ZigLLVMFnId fn_id) {
727static LLVMValueRef get_float_fn(CodeGen *g, TypeTableEntry *type_entry, ZigLLVMFnId fn_id) {
725728 assert(type_entry->id == TypeTableEntryIdFloat);
726729
727730 ZigLLVMFnKey key = {};
728731 key.id = fn_id;
729 key.data.floor_ceil.bit_count = (uint32_t)type_entry->data.floating.bit_count;
732 key.data.floating.bit_count = (uint32_t)type_entry->data.floating.bit_count;
730733
731734 auto existing_entry = g->llvm_fn_table.maybe_get(key);
732735 if (existing_entry)
......@@ -737,6 +740,8 @@ static LLVMValueRef get_floor_ceil_fn(CodeGen *g, TypeTableEntry *type_entry, Zi
737740 name = "floor";
738741 } else if (fn_id == ZigLLVMFnIdCeil) {
739742 name = "ceil";
743 } else if (fn_id == ZigLLVMFnIdSqrt) {
744 name = "sqrt";
740745 } else {
741746 zig_unreachable();
742747 }
......@@ -819,7 +824,7 @@ static bool ir_want_fast_math(CodeGen *g, IrInstruction *instruction) {
819824}
820825
821826static bool ir_want_runtime_safety(CodeGen *g, IrInstruction *instruction) {
822 if (g->build_mode == BuildModeFastRelease)
827 if (g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease)
823828 return false;
824829
825830 // TODO memoize
......@@ -1867,7 +1872,7 @@ static LLVMValueRef gen_floor(CodeGen *g, LLVMValueRef val, TypeTableEntry *type
18671872 if (type_entry->id == TypeTableEntryIdInt)
18681873 return val;
18691874
1870 LLVMValueRef floor_fn = get_floor_ceil_fn(g, type_entry, ZigLLVMFnIdFloor);
1875 LLVMValueRef floor_fn = get_float_fn(g, type_entry, ZigLLVMFnIdFloor);
18711876 return LLVMBuildCall(g->builder, floor_fn, &val, 1, "");
18721877}
18731878
......@@ -1875,7 +1880,7 @@ static LLVMValueRef gen_ceil(CodeGen *g, LLVMValueRef val, TypeTableEntry *type_
18751880 if (type_entry->id == TypeTableEntryIdInt)
18761881 return val;
18771882
1878 LLVMValueRef ceil_fn = get_floor_ceil_fn(g, type_entry, ZigLLVMFnIdCeil);
1883 LLVMValueRef ceil_fn = get_float_fn(g, type_entry, ZigLLVMFnIdCeil);
18791884 return LLVMBuildCall(g->builder, ceil_fn, &val, 1, "");
18801885}
18811886
......@@ -3186,10 +3191,12 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, Bui
31863191 fn_name = "cttz";
31873192 key.id = ZigLLVMFnIdCtz;
31883193 key.data.ctz.bit_count = (uint32_t)int_type->data.integral.bit_count;
3189 } else {
3194 } else if (fn_id == BuiltinFnIdClz) {
31903195 fn_name = "ctlz";
31913196 key.id = ZigLLVMFnIdClz;
31923197 key.data.clz.bit_count = (uint32_t)int_type->data.integral.bit_count;
3198 } else {
3199 zig_unreachable();
31933200 }
31943201
31953202 auto existing_entry = g->llvm_fn_table.maybe_get(key);
......@@ -3491,9 +3498,30 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn
34913498 LLVMAtomicOrdering failure_order = to_LLVMAtomicOrdering(instruction->failure_order);
34923499
34933500 LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val,
3494 success_order, failure_order);
3501 success_order, failure_order, instruction->is_weak);
34953502
3496 return LLVMBuildExtractValue(g->builder, result_val, 1, "");
3503 TypeTableEntry *maybe_type = instruction->base.value.type;
3504 assert(maybe_type->id == TypeTableEntryIdMaybe);
3505 TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
3506
3507 if (type_is_codegen_pointer(child_type)) {
3508 LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
3509 LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
3510 return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(child_type->type_ref), payload_val, "");
3511 }
3512
3513 assert(instruction->tmp_ptr != nullptr);
3514 assert(type_has_bits(instruction->type));
3515
3516 LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
3517 LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");
3518 gen_assign_raw(g, val_ptr, get_pointer_to_type(g, instruction->type, false), payload_val);
3519
3520 LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
3521 LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, "");
3522 LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");
3523 gen_store_untyped(g, nonnull_bit, maybe_ptr, 0, false);
3524 return instruction->tmp_ptr;
34973525}
34983526
34993527static LLVMValueRef ir_render_fence(CodeGen *g, IrExecutable *executable, IrInstructionFence *instruction) {
......@@ -4296,6 +4324,16 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
42964324 return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, "");
42974325}
42984326
4327static LLVMValueRef ir_render_atomic_load(CodeGen *g, IrExecutable *executable,
4328 IrInstructionAtomicLoad *instruction)
4329{
4330 LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->resolved_ordering);
4331 LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
4332 LLVMValueRef load_inst = gen_load(g, ptr, instruction->ptr->value.type, "");
4333 LLVMSetOrdering(load_inst, ordering);
4334 return load_inst;
4335}
4336
42994337static LLVMValueRef ir_render_merge_err_ret_traces(CodeGen *g, IrExecutable *executable,
43004338 IrInstructionMergeErrRetTraces *instruction)
43014339{
......@@ -4317,6 +4355,13 @@ static LLVMValueRef ir_render_mark_err_ret_trace_ptr(CodeGen *g, IrExecutable *e
43174355 return nullptr;
43184356}
43194357
4358static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstructionSqrt *instruction) {
4359 LLVMValueRef op = ir_llvm_value(g, instruction->op);
4360 assert(instruction->base.value.type->id == TypeTableEntryIdFloat);
4361 LLVMValueRef fn_val = get_float_fn(g, instruction->base.value.type, ZigLLVMFnIdSqrt);
4362 return LLVMBuildCall(g->builder, fn_val, &op, 1, "");
4363}
4364
43204365static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
43214366 AstNode *source_node = instruction->source_node;
43224367 Scope *scope = instruction->scope;
......@@ -4532,12 +4577,16 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
45324577 return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);
45334578 case IrInstructionIdAtomicRmw:
45344579 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
4580 case IrInstructionIdAtomicLoad:
4581 return ir_render_atomic_load(g, executable, (IrInstructionAtomicLoad *)instruction);
45354582 case IrInstructionIdSaveErrRetAddr:
45364583 return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);
45374584 case IrInstructionIdMergeErrRetTraces:
45384585 return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction);
45394586 case IrInstructionIdMarkErrRetTracePtr:
45404587 return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction);
4588 case IrInstructionIdSqrt:
4589 return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction);
45414590 }
45424591 zig_unreachable();
45434592}
......@@ -5476,6 +5525,9 @@ static void do_code_gen(CodeGen *g) {
54765525 } else if (instruction->id == IrInstructionIdErrWrapCode) {
54775526 IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction;
54785527 slot = &err_wrap_code_instruction->tmp_ptr;
5528 } else if (instruction->id == IrInstructionIdCmpxchg) {
5529 IrInstructionCmpxchg *cmpxchg_instruction = (IrInstructionCmpxchg *)instruction;
5530 slot = &cmpxchg_instruction->tmp_ptr;
54795531 } else {
54805532 zig_unreachable();
54815533 }
......@@ -5637,10 +5689,12 @@ static void do_code_gen(CodeGen *g) {
56375689 os_path_join(g->cache_dir, o_basename, output_path);
56385690 ensure_cache_dir(g);
56395691
5692 bool is_small = g->build_mode == BuildModeSmallRelease;
5693
56405694 switch (g->emit_file_type) {
56415695 case EmitFileTypeBinary:
56425696 if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
5643 ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug))
5697 ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug, is_small))
56445698 {
56455699 zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg);
56465700 }
......@@ -5650,7 +5704,7 @@ static void do_code_gen(CodeGen *g) {
56505704
56515705 case EmitFileTypeAssembly:
56525706 if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
5653 ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug))
5707 ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug, is_small))
56545708 {
56555709 zig_panic("unable to write assembly file %s: %s", buf_ptr(output_path), err_msg);
56565710 }
......@@ -5659,7 +5713,7 @@ static void do_code_gen(CodeGen *g) {
56595713
56605714 case EmitFileTypeLLVMIr:
56615715 if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
5662 ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug))
5716 ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug, is_small))
56635717 {
56645718 zig_panic("unable to write llvm-ir file %s: %s", buf_ptr(output_path), err_msg);
56655719 }
......@@ -5985,6 +6039,7 @@ static void define_builtin_fns(CodeGen *g) {
59856039 create_builtin_fn(g, BuiltinFnIdMemberCount, "memberCount", 1);
59866040 create_builtin_fn(g, BuiltinFnIdMemberType, "memberType", 2);
59876041 create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2);
6042 create_builtin_fn(g, BuiltinFnIdField, "field", 2);
59886043 create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf
59896044 create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4);
59906045 create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4);
......@@ -6001,7 +6056,8 @@ static void define_builtin_fns(CodeGen *g) {
60016056 create_builtin_fn(g, BuiltinFnIdTypeName, "typeName", 1);
60026057 create_builtin_fn(g, BuiltinFnIdCanImplicitCast, "canImplicitCast", 2);
60036058 create_builtin_fn(g, BuiltinFnIdEmbedFile, "embedFile", 1);
6004 create_builtin_fn(g, BuiltinFnIdCmpExchange, "cmpxchg", 5);
6059 create_builtin_fn(g, BuiltinFnIdCmpxchgWeak, "cmpxchgWeak", 6);
6060 create_builtin_fn(g, BuiltinFnIdCmpxchgStrong, "cmpxchgStrong", 6);
60056061 create_builtin_fn(g, BuiltinFnIdFence, "fence", 1);
60066062 create_builtin_fn(g, BuiltinFnIdTruncate, "truncate", 2);
60076063 create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1);
......@@ -6024,6 +6080,7 @@ static void define_builtin_fns(CodeGen *g) {
60246080 create_builtin_fn(g, BuiltinFnIdDivFloor, "divFloor", 2);
60256081 create_builtin_fn(g, BuiltinFnIdRem, "rem", 2);
60266082 create_builtin_fn(g, BuiltinFnIdMod, "mod", 2);
6083 create_builtin_fn(g, BuiltinFnIdSqrt, "sqrt", 2);
60276084 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
60286085 create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);
60296086 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
......@@ -6037,6 +6094,7 @@ static void define_builtin_fns(CodeGen *g) {
60376094 create_builtin_fn(g, BuiltinFnIdExport, "export", 3);
60386095 create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0);
60396096 create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5);
6097 create_builtin_fn(g, BuiltinFnIdAtomicLoad, "atomicLoad", 3);
60406098}
60416099
60426100static const char *bool_to_str(bool b) {
......@@ -6048,6 +6106,7 @@ static const char *build_mode_to_str(BuildMode build_mode) {
60486106 case BuildModeDebug: return "Mode.Debug";
60496107 case BuildModeSafeRelease: return "Mode.ReleaseSafe";
60506108 case BuildModeFastRelease: return "Mode.ReleaseFast";
6109 case BuildModeSmallRelease: return "Mode.ReleaseSmall";
60516110 }
60526111 zig_unreachable();
60536112}
......@@ -6188,6 +6247,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
61886247 " Debug,\n"
61896248 " ReleaseSafe,\n"
61906249 " ReleaseFast,\n"
6250 " ReleaseSmall,\n"
61916251 "};\n\n");
61926252 }
61936253 {
......@@ -6238,7 +6298,8 @@ static void define_builtin_compile_vars(CodeGen *g) {
62386298 int err;
62396299 Buf *abs_full_path = buf_alloc();
62406300 if ((err = os_path_real(builtin_zig_path, abs_full_path))) {
6241 zig_panic("unable to open '%s': %s", buf_ptr(builtin_zig_path), err_str(err));
6301 fprintf(stderr, "unable to open '%s': %s", buf_ptr(builtin_zig_path), err_str(err));
6302 exit(1);
62426303 }
62436304
62446305 assert(g->root_package);
......@@ -6358,7 +6419,7 @@ static void init(CodeGen *g) {
63586419 }
63596420 }
63606421
6361 g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease;
6422 g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease && g->build_mode != BuildModeSmallRelease;
63626423
63636424 define_builtin_fns(g);
63646425 define_builtin_compile_vars(g);
......@@ -6492,12 +6553,14 @@ static void gen_root_source(CodeGen *g) {
64926553 Buf *abs_full_path = buf_alloc();
64936554 int err;
64946555 if ((err = os_path_real(rel_full_path, abs_full_path))) {
6495 zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));
6556 fprintf(stderr, "unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));
6557 exit(1);
64966558 }
64976559
64986560 Buf *source_code = buf_alloc();
64996561 if ((err = os_fetch_file_path(rel_full_path, source_code, true))) {
6500 zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));
6562 fprintf(stderr, "unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));
6563 exit(1);
65016564 }
65026565
65036566 g->root_import = add_source_file(g, g->root_package, abs_full_path, source_code);
......@@ -7050,4 +7113,3 @@ PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir,
70507113 }
70517114 return pkg;
70527115}
7053
src/ir.cpp+499-137
......@@ -110,6 +110,8 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
110110 IrInstruction *source_instr, IrInstruction *container_ptr, TypeTableEntry *container_type);
111111static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
112112 VariableTableEntry *var, bool is_const_ptr, bool is_volatile_ptr);
113static TypeTableEntry *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op);
114static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval);
113115
114116ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
115117 assert(const_val->type->id == TypeTableEntryIdPointer);
......@@ -709,6 +711,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicRmw *) {
709711 return IrInstructionIdAtomicRmw;
710712}
711713
714static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicLoad *) {
715 return IrInstructionIdAtomicLoad;
716}
717
712718static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseResultType *) {
713719 return IrInstructionIdPromiseResultType;
714720}
......@@ -733,6 +739,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTraceP
733739 return IrInstructionIdMarkErrRetTracePtr;
734740}
735741
742static constexpr IrInstructionId ir_instruction_id(IrInstructionSqrt *) {
743 return IrInstructionIdSqrt;
744}
745
736746template<typename T>
737747static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
738748 T *special_instruction = allocate<T>(1);
......@@ -1024,12 +1034,27 @@ static IrInstruction *ir_build_elem_ptr_from(IrBuilder *irb, IrInstruction *old_
10241034 return new_instruction;
10251035}
10261036
1037static IrInstruction *ir_build_field_ptr_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node,
1038 IrInstruction *container_ptr, IrInstruction *field_name_expr)
1039{
1040 IrInstructionFieldPtr *instruction = ir_build_instruction<IrInstructionFieldPtr>(irb, scope, source_node);
1041 instruction->container_ptr = container_ptr;
1042 instruction->field_name_buffer = nullptr;
1043 instruction->field_name_expr = field_name_expr;
1044
1045 ir_ref_instruction(container_ptr, irb->current_basic_block);
1046 ir_ref_instruction(field_name_expr, irb->current_basic_block);
1047
1048 return &instruction->base;
1049}
1050
10271051static IrInstruction *ir_build_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
10281052 IrInstruction *container_ptr, Buf *field_name)
10291053{
10301054 IrInstructionFieldPtr *instruction = ir_build_instruction<IrInstructionFieldPtr>(irb, scope, source_node);
10311055 instruction->container_ptr = container_ptr;
1032 instruction->field_name = field_name;
1056 instruction->field_name_buffer = field_name;
1057 instruction->field_name_expr = nullptr;
10331058
10341059 ir_ref_instruction(container_ptr, irb->current_basic_block);
10351060
......@@ -1824,38 +1849,34 @@ static IrInstruction *ir_build_embed_file(IrBuilder *irb, Scope *scope, AstNode
18241849 return &instruction->base;
18251850}
18261851
1827static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr,
1828 IrInstruction *cmp_value, IrInstruction *new_value, IrInstruction *success_order_value, IrInstruction *failure_order_value,
1829 AtomicOrder success_order, AtomicOrder failure_order)
1852static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value,
1853 IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value,
1854 IrInstruction *success_order_value, IrInstruction *failure_order_value,
1855 bool is_weak,
1856 TypeTableEntry *type, AtomicOrder success_order, AtomicOrder failure_order)
18301857{
18311858 IrInstructionCmpxchg *instruction = ir_build_instruction<IrInstructionCmpxchg>(irb, scope, source_node);
1859 instruction->type_value = type_value;
18321860 instruction->ptr = ptr;
18331861 instruction->cmp_value = cmp_value;
18341862 instruction->new_value = new_value;
18351863 instruction->success_order_value = success_order_value;
18361864 instruction->failure_order_value = failure_order_value;
1865 instruction->is_weak = is_weak;
1866 instruction->type = type;
18371867 instruction->success_order = success_order;
18381868 instruction->failure_order = failure_order;
18391869
1870 if (type_value != nullptr) ir_ref_instruction(type_value, irb->current_basic_block);
18401871 ir_ref_instruction(ptr, irb->current_basic_block);
18411872 ir_ref_instruction(cmp_value, irb->current_basic_block);
18421873 ir_ref_instruction(new_value, irb->current_basic_block);
1843 ir_ref_instruction(success_order_value, irb->current_basic_block);
1844 ir_ref_instruction(failure_order_value, irb->current_basic_block);
1874 if (type_value != nullptr) ir_ref_instruction(success_order_value, irb->current_basic_block);
1875 if (type_value != nullptr) ir_ref_instruction(failure_order_value, irb->current_basic_block);
18451876
18461877 return &instruction->base;
18471878}
18481879
1849static IrInstruction *ir_build_cmpxchg_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *ptr,
1850 IrInstruction *cmp_value, IrInstruction *new_value, IrInstruction *success_order_value, IrInstruction *failure_order_value,
1851 AtomicOrder success_order, AtomicOrder failure_order)
1852{
1853 IrInstruction *new_instruction = ir_build_cmpxchg(irb, old_instruction->scope, old_instruction->source_node,
1854 ptr, cmp_value, new_value, success_order_value, failure_order_value, success_order, failure_order);
1855 ir_link_new_instruction(new_instruction, old_instruction);
1856 return new_instruction;
1857}
1858
18591880static IrInstruction *ir_build_fence(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *order_value, AtomicOrder order) {
18601881 IrInstructionFence *instruction = ir_build_instruction<IrInstructionFence>(irb, scope, source_node);
18611882 instruction->order_value = order_value;
......@@ -2669,6 +2690,23 @@ static IrInstruction *ir_build_atomic_rmw(IrBuilder *irb, Scope *scope, AstNode
26692690 return &instruction->base;
26702691}
26712692
2693static IrInstruction *ir_build_atomic_load(IrBuilder *irb, Scope *scope, AstNode *source_node,
2694 IrInstruction *operand_type, IrInstruction *ptr,
2695 IrInstruction *ordering, AtomicOrder resolved_ordering)
2696{
2697 IrInstructionAtomicLoad *instruction = ir_build_instruction<IrInstructionAtomicLoad>(irb, scope, source_node);
2698 instruction->operand_type = operand_type;
2699 instruction->ptr = ptr;
2700 instruction->ordering = ordering;
2701 instruction->resolved_ordering = resolved_ordering;
2702
2703 if (operand_type != nullptr) ir_ref_instruction(operand_type, irb->current_basic_block);
2704 ir_ref_instruction(ptr, irb->current_basic_block);
2705 if (ordering != nullptr) ir_ref_instruction(ordering, irb->current_basic_block);
2706
2707 return &instruction->base;
2708}
2709
26722710static IrInstruction *ir_build_promise_result_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
26732711 IrInstruction *promise_type)
26742712{
......@@ -2731,6 +2769,17 @@ static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *sco
27312769 return &instruction->base;
27322770}
27332771
2772static IrInstruction *ir_build_sqrt(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type, IrInstruction *op) {
2773 IrInstructionSqrt *instruction = ir_build_instruction<IrInstructionSqrt>(irb, scope, source_node);
2774 instruction->type = type;
2775 instruction->op = op;
2776
2777 if (type != nullptr) ir_ref_instruction(type, irb->current_basic_block);
2778 ir_ref_instruction(op, irb->current_basic_block);
2779
2780 return &instruction->base;
2781}
2782
27342783static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
27352784 results[ReturnKindUnconditional] = 0;
27362785 results[ReturnKindError] = 0;
......@@ -2796,6 +2845,18 @@ static void ir_set_cursor_at_end_and_append_block(IrBuilder *irb, IrBasicBlock *
27962845 ir_set_cursor_at_end(irb, basic_block);
27972846}
27982847
2848static ScopeSuspend *get_scope_suspend(Scope *scope) {
2849 while (scope) {
2850 if (scope->id == ScopeIdSuspend)
2851 return (ScopeSuspend *)scope;
2852 if (scope->id == ScopeIdFnDef)
2853 return nullptr;
2854
2855 scope = scope->parent;
2856 }
2857 return nullptr;
2858}
2859
27992860static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {
28002861 while (scope) {
28012862 if (scope->id == ScopeIdDeferExpr)
......@@ -3086,6 +3147,9 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
30863147 if (block_node->data.block.name == nullptr || incoming_blocks.length == 0) {
30873148 return noreturn_return_value;
30883149 }
3150
3151 ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block);
3152 return ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
30893153 } else {
30903154 incoming_blocks.append(irb->current_basic_block);
30913155 incoming_values.append(ir_mark_gen(ir_build_const_void(irb, parent_scope, block_node)));
......@@ -3479,7 +3543,7 @@ static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode
34793543 return ir_build_load_ptr(irb, scope, node, ptr_instruction);
34803544}
34813545
3482static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
3546static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode *node) {
34833547 assert(node->type == NodeTypeFieldAccessExpr);
34843548
34853549 AstNode *container_ref_node = node->data.field_access_expr.struct_expr;
......@@ -3489,11 +3553,7 @@ static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode
34893553 if (container_ref_instruction == irb->codegen->invalid_instruction)
34903554 return container_ref_instruction;
34913555
3492 IrInstruction *ptr_instruction = ir_build_field_ptr(irb, scope, node, container_ref_instruction, field_name);
3493 if (lval.is_ptr)
3494 return ptr_instruction;
3495
3496 return ir_build_load_ptr(irb, scope, node, ptr_instruction);
3556 return ir_build_field_ptr(irb, scope, node, container_ref_instruction, field_name);
34973557}
34983558
34993559static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *node, IrOverflowOp op) {
......@@ -3524,7 +3584,7 @@ static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *
35243584 return ir_build_overflow_op(irb, scope, node, op, type_value, op1, op2, result_ptr, nullptr);
35253585}
35263586
3527static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node) {
3587static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
35283588 assert(node->type == NodeTypeFnCallExpr);
35293589
35303590 AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
......@@ -3556,7 +3616,9 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
35563616 IrInstruction *arg = ir_gen_node(irb, arg_node, scope);
35573617 if (arg == irb->codegen->invalid_instruction)
35583618 return arg;
3559 return ir_build_typeof(irb, scope, node, arg);
3619
3620 IrInstruction *type_of = ir_build_typeof(irb, scope, node, arg);
3621 return ir_lval_wrap(irb, scope, type_of, lval);
35603622 }
35613623 case BuiltinFnIdSetCold:
35623624 {
......@@ -3565,7 +3627,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
35653627 if (arg0_value == irb->codegen->invalid_instruction)
35663628 return arg0_value;
35673629
3568 return ir_build_set_cold(irb, scope, node, arg0_value);
3630 IrInstruction *set_cold = ir_build_set_cold(irb, scope, node, arg0_value);
3631 return ir_lval_wrap(irb, scope, set_cold, lval);
35693632 }
35703633 case BuiltinFnIdSetRuntimeSafety:
35713634 {
......@@ -3574,7 +3637,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
35743637 if (arg0_value == irb->codegen->invalid_instruction)
35753638 return arg0_value;
35763639
3577 return ir_build_set_runtime_safety(irb, scope, node, arg0_value);
3640 IrInstruction *set_safety = ir_build_set_runtime_safety(irb, scope, node, arg0_value);
3641 return ir_lval_wrap(irb, scope, set_safety, lval);
35783642 }
35793643 case BuiltinFnIdSetFloatMode:
35803644 {
......@@ -3588,7 +3652,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
35883652 if (arg1_value == irb->codegen->invalid_instruction)
35893653 return arg1_value;
35903654
3591 return ir_build_set_float_mode(irb, scope, node, arg0_value, arg1_value);
3655 IrInstruction *set_float_mode = ir_build_set_float_mode(irb, scope, node, arg0_value, arg1_value);
3656 return ir_lval_wrap(irb, scope, set_float_mode, lval);
35923657 }
35933658 case BuiltinFnIdSizeof:
35943659 {
......@@ -3597,7 +3662,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
35973662 if (arg0_value == irb->codegen->invalid_instruction)
35983663 return arg0_value;
35993664
3600 return ir_build_size_of(irb, scope, node, arg0_value);
3665 IrInstruction *size_of = ir_build_size_of(irb, scope, node, arg0_value);
3666 return ir_lval_wrap(irb, scope, size_of, lval);
36013667 }
36023668 case BuiltinFnIdCtz:
36033669 {
......@@ -3606,7 +3672,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
36063672 if (arg0_value == irb->codegen->invalid_instruction)
36073673 return arg0_value;
36083674
3609 return ir_build_ctz(irb, scope, node, arg0_value);
3675 IrInstruction *ctz = ir_build_ctz(irb, scope, node, arg0_value);
3676 return ir_lval_wrap(irb, scope, ctz, lval);
36103677 }
36113678 case BuiltinFnIdClz:
36123679 {
......@@ -3615,7 +3682,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
36153682 if (arg0_value == irb->codegen->invalid_instruction)
36163683 return arg0_value;
36173684
3618 return ir_build_clz(irb, scope, node, arg0_value);
3685 IrInstruction *clz = ir_build_clz(irb, scope, node, arg0_value);
3686 return ir_lval_wrap(irb, scope, clz, lval);
36193687 }
36203688 case BuiltinFnIdImport:
36213689 {
......@@ -3624,11 +3692,13 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
36243692 if (arg0_value == irb->codegen->invalid_instruction)
36253693 return arg0_value;
36263694
3627 return ir_build_import(irb, scope, node, arg0_value);
3695 IrInstruction *import = ir_build_import(irb, scope, node, arg0_value);
3696 return ir_lval_wrap(irb, scope, import, lval);
36283697 }
36293698 case BuiltinFnIdCImport:
36303699 {
3631 return ir_build_c_import(irb, scope, node);
3700 IrInstruction *c_import = ir_build_c_import(irb, scope, node);
3701 return ir_lval_wrap(irb, scope, c_import, lval);
36323702 }
36333703 case BuiltinFnIdCInclude:
36343704 {
......@@ -3642,7 +3712,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
36423712 return irb->codegen->invalid_instruction;
36433713 }
36443714
3645 return ir_build_c_include(irb, scope, node, arg0_value);
3715 IrInstruction *c_include = ir_build_c_include(irb, scope, node, arg0_value);
3716 return ir_lval_wrap(irb, scope, c_include, lval);
36463717 }
36473718 case BuiltinFnIdCDefine:
36483719 {
......@@ -3661,7 +3732,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
36613732 return irb->codegen->invalid_instruction;
36623733 }
36633734
3664 return ir_build_c_define(irb, scope, node, arg0_value, arg1_value);
3735 IrInstruction *c_define = ir_build_c_define(irb, scope, node, arg0_value, arg1_value);
3736 return ir_lval_wrap(irb, scope, c_define, lval);
36653737 }
36663738 case BuiltinFnIdCUndef:
36673739 {
......@@ -3675,7 +3747,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
36753747 return irb->codegen->invalid_instruction;
36763748 }
36773749
3678 return ir_build_c_undef(irb, scope, node, arg0_value);
3750 IrInstruction *c_undef = ir_build_c_undef(irb, scope, node, arg0_value);
3751 return ir_lval_wrap(irb, scope, c_undef, lval);
36793752 }
36803753 case BuiltinFnIdMaxValue:
36813754 {
......@@ -3684,7 +3757,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
36843757 if (arg0_value == irb->codegen->invalid_instruction)
36853758 return arg0_value;
36863759
3687 return ir_build_max_value(irb, scope, node, arg0_value);
3760 IrInstruction *max_value = ir_build_max_value(irb, scope, node, arg0_value);
3761 return ir_lval_wrap(irb, scope, max_value, lval);
36883762 }
36893763 case BuiltinFnIdMinValue:
36903764 {
......@@ -3693,7 +3767,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
36933767 if (arg0_value == irb->codegen->invalid_instruction)
36943768 return arg0_value;
36953769
3696 return ir_build_min_value(irb, scope, node, arg0_value);
3770 IrInstruction *min_value = ir_build_min_value(irb, scope, node, arg0_value);
3771 return ir_lval_wrap(irb, scope, min_value, lval);
36973772 }
36983773 case BuiltinFnIdCompileErr:
36993774 {
......@@ -3702,7 +3777,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37023777 if (arg0_value == irb->codegen->invalid_instruction)
37033778 return arg0_value;
37043779
3705 return ir_build_compile_err(irb, scope, node, arg0_value);
3780 IrInstruction *compile_err = ir_build_compile_err(irb, scope, node, arg0_value);
3781 return ir_lval_wrap(irb, scope, compile_err, lval);
37063782 }
37073783 case BuiltinFnIdCompileLog:
37083784 {
......@@ -3715,7 +3791,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37153791 return irb->codegen->invalid_instruction;
37163792 }
37173793
3718 return ir_build_compile_log(irb, scope, node, actual_param_count, args);
3794 IrInstruction *compile_log = ir_build_compile_log(irb, scope, node, actual_param_count, args);
3795 return ir_lval_wrap(irb, scope, compile_log, lval);
37193796 }
37203797 case BuiltinFnIdErrName:
37213798 {
......@@ -3724,7 +3801,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37243801 if (arg0_value == irb->codegen->invalid_instruction)
37253802 return arg0_value;
37263803
3727 return ir_build_err_name(irb, scope, node, arg0_value);
3804 IrInstruction *err_name = ir_build_err_name(irb, scope, node, arg0_value);
3805 return ir_lval_wrap(irb, scope, err_name, lval);
37283806 }
37293807 case BuiltinFnIdEmbedFile:
37303808 {
......@@ -3733,9 +3811,11 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37333811 if (arg0_value == irb->codegen->invalid_instruction)
37343812 return arg0_value;
37353813
3736 return ir_build_embed_file(irb, scope, node, arg0_value);
3814 IrInstruction *embed_file = ir_build_embed_file(irb, scope, node, arg0_value);
3815 return ir_lval_wrap(irb, scope, embed_file, lval);
37373816 }
3738 case BuiltinFnIdCmpExchange:
3817 case BuiltinFnIdCmpxchgWeak:
3818 case BuiltinFnIdCmpxchgStrong:
37393819 {
37403820 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
37413821 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
......@@ -3762,9 +3842,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37623842 if (arg4_value == irb->codegen->invalid_instruction)
37633843 return arg4_value;
37643844
3765 return ir_build_cmpxchg(irb, scope, node, arg0_value, arg1_value,
3766 arg2_value, arg3_value, arg4_value,
3767 AtomicOrderUnordered, AtomicOrderUnordered);
3845 AstNode *arg5_node = node->data.fn_call_expr.params.at(5);
3846 IrInstruction *arg5_value = ir_gen_node(irb, arg5_node, scope);
3847 if (arg5_value == irb->codegen->invalid_instruction)
3848 return arg5_value;
3849
3850 IrInstruction *cmpxchg = ir_build_cmpxchg(irb, scope, node, arg0_value, arg1_value,
3851 arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak),
3852 nullptr, AtomicOrderUnordered, AtomicOrderUnordered);
3853 return ir_lval_wrap(irb, scope, cmpxchg, lval);
37683854 }
37693855 case BuiltinFnIdFence:
37703856 {
......@@ -3773,7 +3859,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37733859 if (arg0_value == irb->codegen->invalid_instruction)
37743860 return arg0_value;
37753861
3776 return ir_build_fence(irb, scope, node, arg0_value, AtomicOrderUnordered);
3862 IrInstruction *fence = ir_build_fence(irb, scope, node, arg0_value, AtomicOrderUnordered);
3863 return ir_lval_wrap(irb, scope, fence, lval);
37773864 }
37783865 case BuiltinFnIdDivExact:
37793866 {
......@@ -3787,7 +3874,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37873874 if (arg1_value == irb->codegen->invalid_instruction)
37883875 return arg1_value;
37893876
3790 return ir_build_bin_op(irb, scope, node, IrBinOpDivExact, arg0_value, arg1_value, true);
3877 IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivExact, arg0_value, arg1_value, true);
3878 return ir_lval_wrap(irb, scope, bin_op, lval);
37913879 }
37923880 case BuiltinFnIdDivTrunc:
37933881 {
......@@ -3801,7 +3889,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
38013889 if (arg1_value == irb->codegen->invalid_instruction)
38023890 return arg1_value;
38033891
3804 return ir_build_bin_op(irb, scope, node, IrBinOpDivTrunc, arg0_value, arg1_value, true);
3892 IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivTrunc, arg0_value, arg1_value, true);
3893 return ir_lval_wrap(irb, scope, bin_op, lval);
38053894 }
38063895 case BuiltinFnIdDivFloor:
38073896 {
......@@ -3815,7 +3904,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
38153904 if (arg1_value == irb->codegen->invalid_instruction)
38163905 return arg1_value;
38173906
3818 return ir_build_bin_op(irb, scope, node, IrBinOpDivFloor, arg0_value, arg1_value, true);
3907 IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivFloor, arg0_value, arg1_value, true);
3908 return ir_lval_wrap(irb, scope, bin_op, lval);
38193909 }
38203910 case BuiltinFnIdRem:
38213911 {
......@@ -3829,7 +3919,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
38293919 if (arg1_value == irb->codegen->invalid_instruction)
38303920 return arg1_value;
38313921
3832 return ir_build_bin_op(irb, scope, node, IrBinOpRemRem, arg0_value, arg1_value, true);
3922 IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpRemRem, arg0_value, arg1_value, true);
3923 return ir_lval_wrap(irb, scope, bin_op, lval);
38333924 }
38343925 case BuiltinFnIdMod:
38353926 {
......@@ -3843,7 +3934,23 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
38433934 if (arg1_value == irb->codegen->invalid_instruction)
38443935 return arg1_value;
38453936
3846 return ir_build_bin_op(irb, scope, node, IrBinOpRemMod, arg0_value, arg1_value, true);
3937 IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpRemMod, arg0_value, arg1_value, true);
3938 return ir_lval_wrap(irb, scope, bin_op, lval);
3939 }
3940 case BuiltinFnIdSqrt:
3941 {
3942 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
3943 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
3944 if (arg0_value == irb->codegen->invalid_instruction)
3945 return arg0_value;
3946
3947 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
3948 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
3949 if (arg1_value == irb->codegen->invalid_instruction)
3950 return arg1_value;
3951
3952 IrInstruction *ir_sqrt = ir_build_sqrt(irb, scope, node, arg0_value, arg1_value);
3953 return ir_lval_wrap(irb, scope, ir_sqrt, lval);
38473954 }
38483955 case BuiltinFnIdTruncate:
38493956 {
......@@ -3857,7 +3964,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
38573964 if (arg1_value == irb->codegen->invalid_instruction)
38583965 return arg1_value;
38593966
3860 return ir_build_truncate(irb, scope, node, arg0_value, arg1_value);
3967 IrInstruction *truncate = ir_build_truncate(irb, scope, node, arg0_value, arg1_value);
3968 return ir_lval_wrap(irb, scope, truncate, lval);
38613969 }
38623970 case BuiltinFnIdIntType:
38633971 {
......@@ -3871,7 +3979,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
38713979 if (arg1_value == irb->codegen->invalid_instruction)
38723980 return arg1_value;
38733981
3874 return ir_build_int_type(irb, scope, node, arg0_value, arg1_value);
3982 IrInstruction *int_type = ir_build_int_type(irb, scope, node, arg0_value, arg1_value);
3983 return ir_lval_wrap(irb, scope, int_type, lval);
38753984 }
38763985 case BuiltinFnIdMemcpy:
38773986 {
......@@ -3890,7 +3999,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
38903999 if (arg2_value == irb->codegen->invalid_instruction)
38914000 return arg2_value;
38924001
3893 return ir_build_memcpy(irb, scope, node, arg0_value, arg1_value, arg2_value);
4002 IrInstruction *ir_memcpy = ir_build_memcpy(irb, scope, node, arg0_value, arg1_value, arg2_value);
4003 return ir_lval_wrap(irb, scope, ir_memcpy, lval);
38944004 }
38954005 case BuiltinFnIdMemset:
38964006 {
......@@ -3909,7 +4019,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
39094019 if (arg2_value == irb->codegen->invalid_instruction)
39104020 return arg2_value;
39114021
3912 return ir_build_memset(irb, scope, node, arg0_value, arg1_value, arg2_value);
4022 IrInstruction *ir_memset = ir_build_memset(irb, scope, node, arg0_value, arg1_value, arg2_value);
4023 return ir_lval_wrap(irb, scope, ir_memset, lval);
39134024 }
39144025 case BuiltinFnIdMemberCount:
39154026 {
......@@ -3918,7 +4029,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
39184029 if (arg0_value == irb->codegen->invalid_instruction)
39194030 return arg0_value;
39204031
3921 return ir_build_member_count(irb, scope, node, arg0_value);
4032 IrInstruction *member_count = ir_build_member_count(irb, scope, node, arg0_value);
4033 return ir_lval_wrap(irb, scope, member_count, lval);
39224034 }
39234035 case BuiltinFnIdMemberType:
39244036 {
......@@ -3933,7 +4045,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
39334045 return arg1_value;
39344046
39354047
3936 return ir_build_member_type(irb, scope, node, arg0_value, arg1_value);
4048 IrInstruction *member_type = ir_build_member_type(irb, scope, node, arg0_value, arg1_value);
4049 return ir_lval_wrap(irb, scope, member_type, lval);
39374050 }
39384051 case BuiltinFnIdMemberName:
39394052 {
......@@ -3948,14 +4061,34 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
39484061 return arg1_value;
39494062
39504063
3951 return ir_build_member_name(irb, scope, node, arg0_value, arg1_value);
4064 IrInstruction *member_name = ir_build_member_name(irb, scope, node, arg0_value, arg1_value);
4065 return ir_lval_wrap(irb, scope, member_name, lval);
4066 }
4067 case BuiltinFnIdField:
4068 {
4069 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4070 IrInstruction *arg0_value = ir_gen_node_extra(irb, arg0_node, scope, LVAL_PTR);
4071 if (arg0_value == irb->codegen->invalid_instruction)
4072 return arg0_value;
4073
4074 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4075 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4076 if (arg1_value == irb->codegen->invalid_instruction)
4077 return arg1_value;
4078
4079 IrInstruction *ptr_instruction = ir_build_field_ptr_instruction(irb, scope, node, arg0_value, arg1_value);
4080
4081 if (lval.is_ptr)
4082 return ptr_instruction;
4083
4084 return ir_build_load_ptr(irb, scope, node, ptr_instruction);
39524085 }
39534086 case BuiltinFnIdBreakpoint:
3954 return ir_build_breakpoint(irb, scope, node);
4087 return ir_lval_wrap(irb, scope, ir_build_breakpoint(irb, scope, node), lval);
39554088 case BuiltinFnIdReturnAddress:
3956 return ir_build_return_address(irb, scope, node);
4089 return ir_lval_wrap(irb, scope, ir_build_return_address(irb, scope, node), lval);
39574090 case BuiltinFnIdFrameAddress:
3958 return ir_build_frame_address(irb, scope, node);
4091 return ir_lval_wrap(irb, scope, ir_build_frame_address(irb, scope, node), lval);
39594092 case BuiltinFnIdAlignOf:
39604093 {
39614094 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -3963,16 +4096,17 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
39634096 if (arg0_value == irb->codegen->invalid_instruction)
39644097 return arg0_value;
39654098
3966 return ir_build_align_of(irb, scope, node, arg0_value);
4099 IrInstruction *align_of = ir_build_align_of(irb, scope, node, arg0_value);
4100 return ir_lval_wrap(irb, scope, align_of, lval);
39674101 }
39684102 case BuiltinFnIdAddWithOverflow:
3969 return ir_gen_overflow_op(irb, scope, node, IrOverflowOpAdd);
4103 return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpAdd), lval);
39704104 case BuiltinFnIdSubWithOverflow:
3971 return ir_gen_overflow_op(irb, scope, node, IrOverflowOpSub);
4105 return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpSub), lval);
39724106 case BuiltinFnIdMulWithOverflow:
3973 return ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul);
4107 return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul), lval);
39744108 case BuiltinFnIdShlWithOverflow:
3975 return ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl);
4109 return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl), lval);
39764110 case BuiltinFnIdTypeName:
39774111 {
39784112 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -3980,7 +4114,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
39804114 if (arg0_value == irb->codegen->invalid_instruction)
39814115 return arg0_value;
39824116
3983 return ir_build_type_name(irb, scope, node, arg0_value);
4117 IrInstruction *type_name = ir_build_type_name(irb, scope, node, arg0_value);
4118 return ir_lval_wrap(irb, scope, type_name, lval);
39844119 }
39854120 case BuiltinFnIdCanImplicitCast:
39864121 {
......@@ -3994,7 +4129,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
39944129 if (arg1_value == irb->codegen->invalid_instruction)
39954130 return arg1_value;
39964131
3997 return ir_build_can_implicit_cast(irb, scope, node, arg0_value, arg1_value);
4132 IrInstruction *can_implicit_cast = ir_build_can_implicit_cast(irb, scope, node, arg0_value, arg1_value);
4133 return ir_lval_wrap(irb, scope, can_implicit_cast, lval);
39984134 }
39994135 case BuiltinFnIdPanic:
40004136 {
......@@ -4003,7 +4139,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40034139 if (arg0_value == irb->codegen->invalid_instruction)
40044140 return arg0_value;
40054141
4006 return ir_build_panic(irb, scope, node, arg0_value);
4142 IrInstruction *panic = ir_build_panic(irb, scope, node, arg0_value);
4143 return ir_lval_wrap(irb, scope, panic, lval);
40074144 }
40084145 case BuiltinFnIdPtrCast:
40094146 {
......@@ -4017,7 +4154,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40174154 if (arg1_value == irb->codegen->invalid_instruction)
40184155 return arg1_value;
40194156
4020 return ir_build_ptr_cast(irb, scope, node, arg0_value, arg1_value);
4157 IrInstruction *ptr_cast = ir_build_ptr_cast(irb, scope, node, arg0_value, arg1_value);
4158 return ir_lval_wrap(irb, scope, ptr_cast, lval);
40214159 }
40224160 case BuiltinFnIdBitCast:
40234161 {
......@@ -4031,7 +4169,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40314169 if (arg1_value == irb->codegen->invalid_instruction)
40324170 return arg1_value;
40334171
4034 return ir_build_bit_cast(irb, scope, node, arg0_value, arg1_value);
4172 IrInstruction *bit_cast = ir_build_bit_cast(irb, scope, node, arg0_value, arg1_value);
4173 return ir_lval_wrap(irb, scope, bit_cast, lval);
40354174 }
40364175 case BuiltinFnIdIntToPtr:
40374176 {
......@@ -4045,7 +4184,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40454184 if (arg1_value == irb->codegen->invalid_instruction)
40464185 return arg1_value;
40474186
4048 return ir_build_int_to_ptr(irb, scope, node, arg0_value, arg1_value);
4187 IrInstruction *int_to_ptr = ir_build_int_to_ptr(irb, scope, node, arg0_value, arg1_value);
4188 return ir_lval_wrap(irb, scope, int_to_ptr, lval);
40494189 }
40504190 case BuiltinFnIdPtrToInt:
40514191 {
......@@ -4054,7 +4194,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40544194 if (arg0_value == irb->codegen->invalid_instruction)
40554195 return arg0_value;
40564196
4057 return ir_build_ptr_to_int(irb, scope, node, arg0_value);
4197 IrInstruction *ptr_to_int = ir_build_ptr_to_int(irb, scope, node, arg0_value);
4198 return ir_lval_wrap(irb, scope, ptr_to_int, lval);
40584199 }
40594200 case BuiltinFnIdTagName:
40604201 {
......@@ -4064,7 +4205,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40644205 return arg0_value;
40654206
40664207 IrInstruction *actual_tag = ir_build_union_tag(irb, scope, node, arg0_value);
4067 return ir_build_tag_name(irb, scope, node, actual_tag);
4208 IrInstruction *tag_name = ir_build_tag_name(irb, scope, node, actual_tag);
4209 return ir_lval_wrap(irb, scope, tag_name, lval);
40684210 }
40694211 case BuiltinFnIdTagType:
40704212 {
......@@ -4073,7 +4215,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40734215 if (arg0_value == irb->codegen->invalid_instruction)
40744216 return arg0_value;
40754217
4076 return ir_build_tag_type(irb, scope, node, arg0_value);
4218 IrInstruction *tag_type = ir_build_tag_type(irb, scope, node, arg0_value);
4219 return ir_lval_wrap(irb, scope, tag_type, lval);
40774220 }
40784221 case BuiltinFnIdFieldParentPtr:
40794222 {
......@@ -4092,7 +4235,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40924235 if (arg2_value == irb->codegen->invalid_instruction)
40934236 return arg2_value;
40944237
4095 return ir_build_field_parent_ptr(irb, scope, node, arg0_value, arg1_value, arg2_value, nullptr);
4238 IrInstruction *field_parent_ptr = ir_build_field_parent_ptr(irb, scope, node, arg0_value, arg1_value, arg2_value, nullptr);
4239 return ir_lval_wrap(irb, scope, field_parent_ptr, lval);
40964240 }
40974241 case BuiltinFnIdOffsetOf:
40984242 {
......@@ -4106,7 +4250,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
41064250 if (arg1_value == irb->codegen->invalid_instruction)
41074251 return arg1_value;
41084252
4109 return ir_build_offset_of(irb, scope, node, arg0_value, arg1_value);
4253 IrInstruction *offset_of = ir_build_offset_of(irb, scope, node, arg0_value, arg1_value);
4254 return ir_lval_wrap(irb, scope, offset_of, lval);
41104255 }
41114256 case BuiltinFnIdInlineCall:
41124257 case BuiltinFnIdNoInlineCall:
......@@ -4132,7 +4277,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
41324277 }
41334278 FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
41344279
4135 return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr);
4280 IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr);
4281 return ir_lval_wrap(irb, scope, call, lval);
41364282 }
41374283 case BuiltinFnIdTypeId:
41384284 {
......@@ -4141,7 +4287,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
41414287 if (arg0_value == irb->codegen->invalid_instruction)
41424288 return arg0_value;
41434289
4144 return ir_build_type_id(irb, scope, node, arg0_value);
4290 IrInstruction *type_id = ir_build_type_id(irb, scope, node, arg0_value);
4291 return ir_lval_wrap(irb, scope, type_id, lval);
41454292 }
41464293 case BuiltinFnIdShlExact:
41474294 {
......@@ -4155,7 +4302,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
41554302 if (arg1_value == irb->codegen->invalid_instruction)
41564303 return arg1_value;
41574304
4158 return ir_build_bin_op(irb, scope, node, IrBinOpBitShiftLeftExact, arg0_value, arg1_value, true);
4305 IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftLeftExact, arg0_value, arg1_value, true);
4306 return ir_lval_wrap(irb, scope, bin_op, lval);
41594307 }
41604308 case BuiltinFnIdShrExact:
41614309 {
......@@ -4169,7 +4317,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
41694317 if (arg1_value == irb->codegen->invalid_instruction)
41704318 return arg1_value;
41714319
4172 return ir_build_bin_op(irb, scope, node, IrBinOpBitShiftRightExact, arg0_value, arg1_value, true);
4320 IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftRightExact, arg0_value, arg1_value, true);
4321 return ir_lval_wrap(irb, scope, bin_op, lval);
41734322 }
41744323 case BuiltinFnIdSetEvalBranchQuota:
41754324 {
......@@ -4178,7 +4327,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
41784327 if (arg0_value == irb->codegen->invalid_instruction)
41794328 return arg0_value;
41804329
4181 return ir_build_set_eval_branch_quota(irb, scope, node, arg0_value);
4330 IrInstruction *set_eval_branch_quota = ir_build_set_eval_branch_quota(irb, scope, node, arg0_value);
4331 return ir_lval_wrap(irb, scope, set_eval_branch_quota, lval);
41824332 }
41834333 case BuiltinFnIdAlignCast:
41844334 {
......@@ -4192,10 +4342,14 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
41924342 if (arg1_value == irb->codegen->invalid_instruction)
41934343 return arg1_value;
41944344
4195 return ir_build_align_cast(irb, scope, node, arg0_value, arg1_value);
4345 IrInstruction *align_cast = ir_build_align_cast(irb, scope, node, arg0_value, arg1_value);
4346 return ir_lval_wrap(irb, scope, align_cast, lval);
41964347 }
41974348 case BuiltinFnIdOpaqueType:
4198 return ir_build_opaque_type(irb, scope, node);
4349 {
4350 IrInstruction *opaque_type = ir_build_opaque_type(irb, scope, node);
4351 return ir_lval_wrap(irb, scope, opaque_type, lval);
4352 }
41994353 case BuiltinFnIdSetAlignStack:
42004354 {
42014355 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -4203,7 +4357,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
42034357 if (arg0_value == irb->codegen->invalid_instruction)
42044358 return arg0_value;
42054359
4206 return ir_build_set_align_stack(irb, scope, node, arg0_value);
4360 IrInstruction *set_align_stack = ir_build_set_align_stack(irb, scope, node, arg0_value);
4361 return ir_lval_wrap(irb, scope, set_align_stack, lval);
42074362 }
42084363 case BuiltinFnIdArgType:
42094364 {
......@@ -4217,7 +4372,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
42174372 if (arg1_value == irb->codegen->invalid_instruction)
42184373 return arg1_value;
42194374
4220 return ir_build_arg_type(irb, scope, node, arg0_value, arg1_value);
4375 IrInstruction *arg_type = ir_build_arg_type(irb, scope, node, arg0_value, arg1_value);
4376 return ir_lval_wrap(irb, scope, arg_type, lval);
42214377 }
42224378 case BuiltinFnIdExport:
42234379 {
......@@ -4236,11 +4392,13 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
42364392 if (arg2_value == irb->codegen->invalid_instruction)
42374393 return arg2_value;
42384394
4239 return ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value);
4395 IrInstruction *ir_export = ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value);
4396 return ir_lval_wrap(irb, scope, ir_export, lval);
42404397 }
42414398 case BuiltinFnIdErrorReturnTrace:
42424399 {
4243 return ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::Null);
4400 IrInstruction *error_return_trace = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::Null);
4401 return ir_lval_wrap(irb, scope, error_return_trace, lval);
42444402 }
42454403 case BuiltinFnIdAtomicRmw:
42464404 {
......@@ -4274,15 +4432,36 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
42744432 // these 2 values don't mean anything since we passed non-null values for other args
42754433 AtomicRmwOp_xchg, AtomicOrderMonotonic);
42764434 }
4435 case BuiltinFnIdAtomicLoad:
4436 {
4437 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4438 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4439 if (arg0_value == irb->codegen->invalid_instruction)
4440 return arg0_value;
4441
4442 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4443 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4444 if (arg1_value == irb->codegen->invalid_instruction)
4445 return arg1_value;
4446
4447 AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
4448 IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
4449 if (arg2_value == irb->codegen->invalid_instruction)
4450 return arg2_value;
4451
4452 return ir_build_atomic_load(irb, scope, node, arg0_value, arg1_value, arg2_value,
4453 // this value does not mean anything since we passed non-null values for other arg
4454 AtomicOrderMonotonic);
4455 }
42774456 }
42784457 zig_unreachable();
42794458}
42804459
4281static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node) {
4460static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
42824461 assert(node->type == NodeTypeFnCallExpr);
42834462
42844463 if (node->data.fn_call_expr.is_builtin)
4285 return ir_gen_builtin_fn_call(irb, scope, node);
4464 return ir_gen_builtin_fn_call(irb, scope, node, lval);
42864465
42874466 AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
42884467 IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
......@@ -4308,7 +4487,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
43084487 }
43094488 }
43104489
4311 return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator);
4490 IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator);
4491 return ir_lval_wrap(irb, scope, fn_call, lval);
43124492}
43134493
43144494static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
......@@ -5591,6 +5771,15 @@ static IrInstruction *ir_gen_return_from_block(IrBuilder *irb, Scope *break_scop
55915771 return ir_build_br(irb, break_scope, node, dest_block, is_comptime);
55925772}
55935773
5774static IrInstruction *ir_gen_break_from_suspend(IrBuilder *irb, Scope *break_scope, AstNode *node, ScopeSuspend *suspend_scope) {
5775 IrInstruction *is_comptime = ir_build_const_bool(irb, break_scope, node, false);
5776
5777 IrBasicBlock *dest_block = suspend_scope->resume_block;
5778 ir_gen_defers_for_block(irb, break_scope, dest_block->scope, false);
5779
5780 return ir_build_br(irb, break_scope, node, dest_block, is_comptime);
5781}
5782
55945783static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *node) {
55955784 assert(node->type == NodeTypeBreak);
55965785
......@@ -5630,6 +5819,13 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *
56305819 assert(this_block_scope->end_block != nullptr);
56315820 return ir_gen_return_from_block(irb, break_scope, node, this_block_scope);
56325821 }
5822 } else if (search_scope->id == ScopeIdSuspend) {
5823 ScopeSuspend *this_suspend_scope = (ScopeSuspend *)search_scope;
5824 if (node->data.break_expr.name != nullptr &&
5825 (this_suspend_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_suspend_scope->name)))
5826 {
5827 return ir_gen_break_from_suspend(irb, break_scope, node, this_suspend_scope);
5828 }
56335829 }
56345830 search_scope = search_scope->parent;
56355831 }
......@@ -6216,14 +6412,26 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
62166412 ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(parent_scope);
62176413 if (scope_defer_expr) {
62186414 if (!scope_defer_expr->reported_err) {
6219 add_node_error(irb->codegen, node, buf_sprintf("cannot suspend inside defer expression"));
6415 ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot suspend inside defer expression"));
6416 add_error_note(irb->codegen, msg, scope_defer_expr->base.source_node, buf_sprintf("defer here"));
62206417 scope_defer_expr->reported_err = true;
62216418 }
62226419 return irb->codegen->invalid_instruction;
62236420 }
6421 ScopeSuspend *existing_suspend_scope = get_scope_suspend(parent_scope);
6422 if (existing_suspend_scope) {
6423 if (!existing_suspend_scope->reported_err) {
6424 ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot suspend inside suspend block"));
6425 add_error_note(irb->codegen, msg, existing_suspend_scope->base.source_node, buf_sprintf("other suspend block here"));
6426 existing_suspend_scope->reported_err = true;
6427 }
6428 return irb->codegen->invalid_instruction;
6429 }
62246430
62256431 Scope *outer_scope = irb->exec->begin_scope;
62266432
6433 IrBasicBlock *cleanup_block = ir_create_basic_block(irb, parent_scope, "SuspendCleanup");
6434 IrBasicBlock *resume_block = ir_create_basic_block(irb, parent_scope, "SuspendResume");
62276435
62286436 IrInstruction *suspend_code;
62296437 IrInstruction *const_bool_false = ir_build_const_bool(irb, parent_scope, node, false);
......@@ -6242,28 +6450,28 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
62426450 } else {
62436451 child_scope = parent_scope;
62446452 }
6453 ScopeSuspend *suspend_scope = create_suspend_scope(node, child_scope);
6454 suspend_scope->resume_block = resume_block;
6455 child_scope = &suspend_scope->base;
62456456 IrInstruction *save_token = ir_build_coro_save(irb, child_scope, node, irb->exec->coro_handle);
62466457 ir_gen_node(irb, node->data.suspend.block, child_scope);
6247 suspend_code = ir_build_coro_suspend(irb, parent_scope, node, save_token, const_bool_false);
6458 suspend_code = ir_mark_gen(ir_build_coro_suspend(irb, parent_scope, node, save_token, const_bool_false));
62486459 }
62496460
6250 IrBasicBlock *cleanup_block = ir_create_basic_block(irb, parent_scope, "SuspendCleanup");
6251 IrBasicBlock *resume_block = ir_create_basic_block(irb, parent_scope, "SuspendResume");
6252
62536461 IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2);
6254 cases[0].value = ir_build_const_u8(irb, parent_scope, node, 0);
6462 cases[0].value = ir_mark_gen(ir_build_const_u8(irb, parent_scope, node, 0));
62556463 cases[0].block = resume_block;
6256 cases[1].value = ir_build_const_u8(irb, parent_scope, node, 1);
6464 cases[1].value = ir_mark_gen(ir_build_const_u8(irb, parent_scope, node, 1));
62576465 cases[1].block = cleanup_block;
6258 ir_build_switch_br(irb, parent_scope, node, suspend_code, irb->exec->coro_suspend_block,
6259 2, cases, const_bool_false);
6466 ir_mark_gen(ir_build_switch_br(irb, parent_scope, node, suspend_code, irb->exec->coro_suspend_block,
6467 2, cases, const_bool_false));
62606468
62616469 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
62626470 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
62636471 ir_mark_gen(ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false));
62646472
62656473 ir_set_cursor_at_end_and_append_block(irb, resume_block);
6266 return ir_build_const_void(irb, parent_scope, node);
6474 return ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
62676475}
62686476
62696477static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,
......@@ -6296,7 +6504,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
62966504 case NodeTypeSymbol:
62976505 return ir_gen_symbol(irb, scope, node, lval);
62986506 case NodeTypeFnCallExpr:
6299 return ir_lval_wrap(irb, scope, ir_gen_fn_call(irb, scope, node), lval);
6507 return ir_gen_fn_call(irb, scope, node, lval);
63006508 case NodeTypeIfBoolExpr:
63016509 return ir_lval_wrap(irb, scope, ir_gen_if_bool_expr(irb, scope, node), lval);
63026510 case NodeTypePrefixOpExpr:
......@@ -6316,7 +6524,15 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
63166524 case NodeTypeReturnExpr:
63176525 return ir_gen_return(irb, scope, node, lval);
63186526 case NodeTypeFieldAccessExpr:
6319 return ir_gen_field_access(irb, scope, node, lval);
6527 {
6528 IrInstruction *ptr_instruction = ir_gen_field_access(irb, scope, node);
6529 if (ptr_instruction == irb->codegen->invalid_instruction)
6530 return ptr_instruction;
6531 if (lval.is_ptr)
6532 return ptr_instruction;
6533
6534 return ir_build_load_ptr(irb, scope, node, ptr_instruction);
6535 }
63206536 case NodeTypeThisLiteral:
63216537 return ir_lval_wrap(irb, scope, ir_gen_this_literal(irb, scope, node), lval);
63226538 case NodeTypeBoolLiteral:
......@@ -11395,7 +11611,19 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
1139511611 }
1139611612 break;
1139711613 case VarClassRequiredAny:
11398 // OK
11614 if (casted_init_value->value.special == ConstValSpecialStatic &&
11615 casted_init_value->value.type->id == TypeTableEntryIdFn &&
11616 casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways)
11617 {
11618 var_class_requires_const = true;
11619 if (!var->src_is_const && !is_comptime_var) {
11620 ErrorMsg *msg = ir_add_error_node(ira, source_node,
11621 buf_sprintf("functions marked inline must be stored in const or comptime var"));
11622 AstNode *proto_node = casted_init_value->value.data.x_ptr.data.fn.fn_entry->proto_node;
11623 add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here"));
11624 result_type = ira->codegen->builtin_types.entry_invalid;
11625 }
11626 }
1139911627 break;
1140011628 }
1140111629 }
......@@ -13332,7 +13560,15 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1333213560 zig_unreachable();
1333313561 }
1333413562
13335 Buf *field_name = field_ptr_instruction->field_name;
13563 Buf *field_name = field_ptr_instruction->field_name_buffer;
13564 if (!field_name) {
13565 IrInstruction *field_name_expr = field_ptr_instruction->field_name_expr->other;
13566 field_name = ir_resolve_str(ira, field_name_expr);
13567 if (!field_name)
13568 return ira->codegen->builtin_types.entry_invalid;
13569 }
13570
13571
1333613572 AstNode *source_node = field_ptr_instruction->base.source_node;
1333713573
1333813574 if (type_is_invalid(container_type)) {
......@@ -14549,7 +14785,10 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
1454914785 return out_val->type;
1455014786 }
1455114787
14552 assert(target_value_ptr->value.type->id == TypeTableEntryIdPointer);
14788 if (target_value_ptr->value.type->id != TypeTableEntryIdPointer) {
14789 ir_add_error(ira, target_value_ptr, buf_sprintf("invalid deref on switch target"));
14790 return ira->codegen->builtin_types.entry_invalid;
14791 }
1455314792
1455414793 TypeTableEntry *target_type = target_value_ptr->value.type->data.pointer.child_type;
1455514794 ConstExprValue *pointee_val = nullptr;
......@@ -15325,6 +15564,8 @@ static TypeTableEntry *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira,
1532515564 }
1532615565
1532715566 ensure_complete_type(ira->codegen, container_type);
15567 if (type_is_invalid(container_type))
15568 return ira->codegen->builtin_types.entry_invalid;
1532815569
1532915570 TypeStructField *field = find_struct_type_field(container_type, field_name);
1533015571 if (field == nullptr) {
......@@ -15647,10 +15888,20 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr
1564715888}
1564815889
1564915890static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchg *instruction) {
15891 TypeTableEntry *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->other);
15892 if (type_is_invalid(operand_type))
15893 return ira->codegen->builtin_types.entry_invalid;
15894
1565015895 IrInstruction *ptr = instruction->ptr->other;
1565115896 if (type_is_invalid(ptr->value.type))
1565215897 return ira->codegen->builtin_types.entry_invalid;
1565315898
15899 // TODO let this be volatile
15900 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false);
15901 IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr, ptr_type);
15902 if (type_is_invalid(casted_ptr->value.type))
15903 return ira->codegen->builtin_types.entry_invalid;
15904
1565415905 IrInstruction *cmp_value = instruction->cmp_value->other;
1565515906 if (type_is_invalid(cmp_value->value.type))
1565615907 return ira->codegen->builtin_types.entry_invalid;
......@@ -15675,28 +15926,11 @@ static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstruct
1567515926 if (!ir_resolve_atomic_order(ira, failure_order_value, &failure_order))
1567615927 return ira->codegen->builtin_types.entry_invalid;
1567715928
15678 if (ptr->value.type->id != TypeTableEntryIdPointer) {
15679 ir_add_error(ira, instruction->ptr,
15680 buf_sprintf("expected pointer argument, found '%s'", buf_ptr(&ptr->value.type->name)));
15681 return ira->codegen->builtin_types.entry_invalid;
15682 }
15683
15684 TypeTableEntry *child_type = ptr->value.type->data.pointer.child_type;
15685
15686 uint32_t align_bytes = ptr->value.type->data.pointer.alignment;
15687 uint64_t size_bytes = type_size(ira->codegen, child_type);
15688 if (align_bytes < size_bytes) {
15689 ir_add_error(ira, instruction->ptr,
15690 buf_sprintf("expected pointer alignment of at least %" ZIG_PRI_u64 ", found %" PRIu32,
15691 size_bytes, align_bytes));
15692 return ira->codegen->builtin_types.entry_invalid;
15693 }
15694
15695 IrInstruction *casted_cmp_value = ir_implicit_cast(ira, cmp_value, child_type);
15929 IrInstruction *casted_cmp_value = ir_implicit_cast(ira, cmp_value, operand_type);
1569615930 if (type_is_invalid(casted_cmp_value->value.type))
1569715931 return ira->codegen->builtin_types.entry_invalid;
1569815932
15699 IrInstruction *casted_new_value = ir_implicit_cast(ira, new_value, child_type);
15933 IrInstruction *casted_new_value = ir_implicit_cast(ira, new_value, operand_type);
1570015934 if (type_is_invalid(casted_new_value->value.type))
1570115935 return ira->codegen->builtin_types.entry_invalid;
1570215936
......@@ -15721,9 +15955,17 @@ static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstruct
1572115955 return ira->codegen->builtin_types.entry_invalid;
1572215956 }
1572315957
15724 ir_build_cmpxchg_from(&ira->new_irb, &instruction->base, ptr, casted_cmp_value, casted_new_value,
15725 success_order_value, failure_order_value, success_order, failure_order);
15726 return ira->codegen->builtin_types.entry_bool;
15958 if (instr_is_comptime(casted_ptr) && instr_is_comptime(casted_cmp_value) && instr_is_comptime(casted_new_value)) {
15959 zig_panic("TODO compile-time execution of cmpxchg");
15960 }
15961
15962 IrInstruction *result = ir_build_cmpxchg(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
15963 nullptr, casted_ptr, casted_cmp_value, casted_new_value, nullptr, nullptr, instruction->is_weak,
15964 operand_type, success_order, failure_order);
15965 result->value.type = get_maybe_type(ira->codegen, operand_type);
15966 ir_link_new_instruction(result, &instruction->base);
15967 ir_add_alloca(ira, result, result->value.type);
15968 return result->value.type;
1572715969}
1572815970
1572915971static TypeTableEntry *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstructionFence *instruction) {
......@@ -17857,39 +18099,48 @@ static TypeTableEntry *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira,
1785718099 return result->value.type;
1785818100}
1785918101
17860static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstructionAtomicRmw *instruction) {
17861 TypeTableEntry *operand_type = ir_resolve_type(ira, instruction->operand_type->other);
17862 if (type_is_invalid(operand_type)) {
18102static TypeTableEntry *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op) {
18103 TypeTableEntry *operand_type = ir_resolve_type(ira, op);
18104 if (type_is_invalid(operand_type))
1786318105 return ira->codegen->builtin_types.entry_invalid;
17864 }
18106
1786518107 if (operand_type->id == TypeTableEntryIdInt) {
1786618108 if (operand_type->data.integral.bit_count < 8) {
17867 ir_add_error(ira, &instruction->base,
18109 ir_add_error(ira, op,
1786818110 buf_sprintf("expected integer type 8 bits or larger, found %" PRIu32 "-bit integer type",
1786918111 operand_type->data.integral.bit_count));
1787018112 return ira->codegen->builtin_types.entry_invalid;
1787118113 }
1787218114 if (operand_type->data.integral.bit_count > ira->codegen->pointer_size_bytes * 8) {
17873 ir_add_error(ira, &instruction->base,
18115 ir_add_error(ira, op,
1787418116 buf_sprintf("expected integer type pointer size or smaller, found %" PRIu32 "-bit integer type",
1787518117 operand_type->data.integral.bit_count));
1787618118 return ira->codegen->builtin_types.entry_invalid;
1787718119 }
1787818120 if (!is_power_of_2(operand_type->data.integral.bit_count)) {
17879 ir_add_error(ira, &instruction->base,
18121 ir_add_error(ira, op,
1788018122 buf_sprintf("%" PRIu32 "-bit integer type is not a power of 2", operand_type->data.integral.bit_count));
1788118123 return ira->codegen->builtin_types.entry_invalid;
1788218124 }
1788318125 } else if (get_codegen_ptr_type(operand_type) == nullptr) {
17884 ir_add_error(ira, &instruction->base,
18126 ir_add_error(ira, op,
1788518127 buf_sprintf("expected integer or pointer type, found '%s'", buf_ptr(&operand_type->name)));
1788618128 return ira->codegen->builtin_types.entry_invalid;
1788718129 }
1788818130
18131 return operand_type;
18132}
18133
18134static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstructionAtomicRmw *instruction) {
18135 TypeTableEntry *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->other);
18136 if (type_is_invalid(operand_type))
18137 return ira->codegen->builtin_types.entry_invalid;
18138
1788918139 IrInstruction *ptr_inst = instruction->ptr->other;
1789018140 if (type_is_invalid(ptr_inst->value.type))
1789118141 return ira->codegen->builtin_types.entry_invalid;
1789218142
18143 // TODO let this be volatile
1789318144 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false);
1789418145 IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr_inst, ptr_type);
1789518146 if (type_is_invalid(casted_ptr->value.type))
......@@ -17933,6 +18184,49 @@ static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstr
1793318184 return result->value.type;
1793418185}
1793518186
18187static TypeTableEntry *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstructionAtomicLoad *instruction) {
18188 TypeTableEntry *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->other);
18189 if (type_is_invalid(operand_type))
18190 return ira->codegen->builtin_types.entry_invalid;
18191
18192 IrInstruction *ptr_inst = instruction->ptr->other;
18193 if (type_is_invalid(ptr_inst->value.type))
18194 return ira->codegen->builtin_types.entry_invalid;
18195
18196 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, operand_type, true);
18197 IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr_inst, ptr_type);
18198 if (type_is_invalid(casted_ptr->value.type))
18199 return ira->codegen->builtin_types.entry_invalid;
18200
18201 AtomicOrder ordering;
18202 if (instruction->ordering == nullptr) {
18203 ordering = instruction->resolved_ordering;
18204 } else {
18205 if (!ir_resolve_atomic_order(ira, instruction->ordering->other, &ordering))
18206 return ira->codegen->builtin_types.entry_invalid;
18207 }
18208
18209 if (ordering == AtomicOrderRelease || ordering == AtomicOrderAcqRel) {
18210 assert(instruction->ordering != nullptr);
18211 ir_add_error(ira, instruction->ordering,
18212 buf_sprintf("@atomicLoad atomic ordering must not be Release or AcqRel"));
18213 return ira->codegen->builtin_types.entry_invalid;
18214 }
18215
18216 if (instr_is_comptime(casted_ptr)) {
18217 IrInstruction *result = ir_get_deref(ira, &instruction->base, casted_ptr);
18218 ir_link_new_instruction(result, &instruction->base);
18219 assert(result->value.type != nullptr);
18220 return result->value.type;
18221 }
18222
18223 IrInstruction *result = ir_build_atomic_load(&ira->new_irb, instruction->base.scope,
18224 instruction->base.source_node, nullptr, casted_ptr, nullptr, ordering);
18225 ir_link_new_instruction(result, &instruction->base);
18226 result->value.type = operand_type;
18227 return result->value.type;
18228}
18229
1793618230static TypeTableEntry *ir_analyze_instruction_promise_result_type(IrAnalyze *ira, IrInstructionPromiseResultType *instruction) {
1793718231 TypeTableEntry *promise_type = ir_resolve_type(ira, instruction->promise_type->other);
1793818232 if (type_is_invalid(promise_type))
......@@ -18019,6 +18313,68 @@ static TypeTableEntry *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *
1801918313 return result->value.type;
1802018314}
1802118315
18316static TypeTableEntry *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionSqrt *instruction) {
18317 TypeTableEntry *float_type = ir_resolve_type(ira, instruction->type->other);
18318 if (type_is_invalid(float_type))
18319 return ira->codegen->builtin_types.entry_invalid;
18320
18321 IrInstruction *op = instruction->op->other;
18322 if (type_is_invalid(op->value.type))
18323 return ira->codegen->builtin_types.entry_invalid;
18324
18325 bool ok_type = float_type->id == TypeTableEntryIdNumLitFloat || float_type->id == TypeTableEntryIdFloat;
18326 if (!ok_type) {
18327 ir_add_error(ira, instruction->type, buf_sprintf("@sqrt does not support type '%s'", buf_ptr(&float_type->name)));
18328 return ira->codegen->builtin_types.entry_invalid;
18329 }
18330
18331 IrInstruction *casted_op = ir_implicit_cast(ira, op, float_type);
18332 if (type_is_invalid(casted_op->value.type))
18333 return ira->codegen->builtin_types.entry_invalid;
18334
18335 if (instr_is_comptime(casted_op)) {
18336 ConstExprValue *val = ir_resolve_const(ira, casted_op, UndefBad);
18337 if (!val)
18338 return ira->codegen->builtin_types.entry_invalid;
18339
18340 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
18341
18342 if (float_type->id == TypeTableEntryIdNumLitFloat) {
18343 bigfloat_sqrt(&out_val->data.x_bigfloat, &val->data.x_bigfloat);
18344 } else if (float_type->id == TypeTableEntryIdFloat) {
18345 switch (float_type->data.floating.bit_count) {
18346 case 32:
18347 out_val->data.x_f32 = sqrtf(val->data.x_f32);
18348 break;
18349 case 64:
18350 out_val->data.x_f64 = sqrt(val->data.x_f64);
18351 break;
18352 case 128:
18353 f128M_sqrt(&val->data.x_f128, &out_val->data.x_f128);
18354 break;
18355 default:
18356 zig_unreachable();
18357 }
18358 } else {
18359 zig_unreachable();
18360 }
18361
18362 return float_type;
18363 }
18364
18365 assert(float_type->id == TypeTableEntryIdFloat);
18366 if (float_type->data.floating.bit_count != 32 && float_type->data.floating.bit_count != 64) {
18367 ir_add_error(ira, instruction->type, buf_sprintf("compiler TODO: add implementation of sqrt for '%s'", buf_ptr(&float_type->name)));
18368 return ira->codegen->builtin_types.entry_invalid;
18369 }
18370
18371 IrInstruction *result = ir_build_sqrt(&ira->new_irb, instruction->base.scope,
18372 instruction->base.source_node, nullptr, casted_op);
18373 ir_link_new_instruction(result, &instruction->base);
18374 result->value.type = float_type;
18375 return result->value.type;
18376}
18377
1802218378static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
1802318379 switch (instruction->id) {
1802418380 case IrInstructionIdInvalid:
......@@ -18254,6 +18610,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1825418610 return ir_analyze_instruction_coro_alloc_helper(ira, (IrInstructionCoroAllocHelper *)instruction);
1825518611 case IrInstructionIdAtomicRmw:
1825618612 return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction);
18613 case IrInstructionIdAtomicLoad:
18614 return ir_analyze_instruction_atomic_load(ira, (IrInstructionAtomicLoad *)instruction);
1825718615 case IrInstructionIdPromiseResultType:
1825818616 return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction);
1825918617 case IrInstructionIdAwaitBookkeeping:
......@@ -18266,6 +18624,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1826618624 return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction);
1826718625 case IrInstructionIdMarkErrRetTracePtr:
1826818626 return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction);
18627 case IrInstructionIdSqrt:
18628 return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction);
1826918629 }
1827018630 zig_unreachable();
1827118631}
......@@ -18395,6 +18755,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1839518755 case IrInstructionIdAddImplicitReturnType:
1839618756 case IrInstructionIdMergeErrRetTraces:
1839718757 case IrInstructionIdMarkErrRetTracePtr:
18758 case IrInstructionIdAtomicRmw:
1839818759 return true;
1839918760
1840018761 case IrInstructionIdPhi:
......@@ -18475,9 +18836,10 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1847518836 case IrInstructionIdCoroSize:
1847618837 case IrInstructionIdCoroSuspend:
1847718838 case IrInstructionIdCoroFree:
18478 case IrInstructionIdAtomicRmw:
1847918839 case IrInstructionIdCoroPromise:
1848018840 case IrInstructionIdPromiseResultType:
18841 case IrInstructionIdSqrt:
18842 case IrInstructionIdAtomicLoad:
1848118843 return false;
1848218844
1848318845 case IrInstructionIdAsm:
src/ir_print.cpp+48-3
......@@ -358,9 +358,18 @@ static void ir_print_ptr_type_child(IrPrint *irp, IrInstructionPtrTypeChild *ins
358358}
359359
360360static void ir_print_field_ptr(IrPrint *irp, IrInstructionFieldPtr *instruction) {
361 fprintf(irp->f, "fieldptr ");
362 ir_print_other_instruction(irp, instruction->container_ptr);
363 fprintf(irp->f, ".%s", buf_ptr(instruction->field_name));
361 if (instruction->field_name_buffer) {
362 fprintf(irp->f, "fieldptr ");
363 ir_print_other_instruction(irp, instruction->container_ptr);
364 fprintf(irp->f, ".%s", buf_ptr(instruction->field_name_buffer));
365 } else {
366 assert(instruction->field_name_expr);
367 fprintf(irp->f, "@field(");
368 ir_print_other_instruction(irp, instruction->container_ptr);
369 fprintf(irp->f, ", ");
370 ir_print_other_instruction(irp, instruction->field_name_expr);
371 fprintf(irp->f, ")");
372 }
364373}
365374
366375static void ir_print_struct_field_ptr(IrPrint *irp, IrInstructionStructFieldPtr *instruction) {
......@@ -1172,6 +1181,24 @@ static void ir_print_atomic_rmw(IrPrint *irp, IrInstructionAtomicRmw *instructio
11721181 fprintf(irp->f, ")");
11731182}
11741183
1184static void ir_print_atomic_load(IrPrint *irp, IrInstructionAtomicLoad *instruction) {
1185 fprintf(irp->f, "@atomicLoad(");
1186 if (instruction->operand_type != nullptr) {
1187 ir_print_other_instruction(irp, instruction->operand_type);
1188 } else {
1189 fprintf(irp->f, "[TODO print]");
1190 }
1191 fprintf(irp->f, ",");
1192 ir_print_other_instruction(irp, instruction->ptr);
1193 fprintf(irp->f, ",");
1194 if (instruction->ordering != nullptr) {
1195 ir_print_other_instruction(irp, instruction->ordering);
1196 } else {
1197 fprintf(irp->f, "[TODO print]");
1198 }
1199 fprintf(irp->f, ")");
1200}
1201
11751202static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeeping *instruction) {
11761203 fprintf(irp->f, "@awaitBookkeeping(");
11771204 ir_print_other_instruction(irp, instruction->promise_result_type);
......@@ -1204,6 +1231,18 @@ static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRe
12041231 fprintf(irp->f, ")");
12051232}
12061233
1234static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) {
1235 fprintf(irp->f, "@sqrt(");
1236 if (instruction->type != nullptr) {
1237 ir_print_other_instruction(irp, instruction->type);
1238 } else {
1239 fprintf(irp->f, "null");
1240 }
1241 fprintf(irp->f, ",");
1242 ir_print_other_instruction(irp, instruction->op);
1243 fprintf(irp->f, ")");
1244}
1245
12071246static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
12081247 ir_print_prefix(irp, instruction);
12091248 switch (instruction->id) {
......@@ -1590,6 +1629,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
15901629 case IrInstructionIdMarkErrRetTracePtr:
15911630 ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction);
15921631 break;
1632 case IrInstructionIdSqrt:
1633 ir_print_sqrt(irp, (IrInstructionSqrt *)instruction);
1634 break;
1635 case IrInstructionIdAtomicLoad:
1636 ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction);
1637 break;
15931638 }
15941639 fprintf(irp->f, "\n");
15951640}
src/link.cpp+3
......@@ -217,6 +217,9 @@ static void construct_linker_job_elf(LinkJob *lj) {
217217 lj->args.append(g->linker_script);
218218 }
219219
220 if (g->no_rosegment_workaround) {
221 lj->args.append("--no-rosegment");
222 }
220223 lj->args.append("--gc-sections");
221224
222225 lj->args.append("-m");
src/main.cpp+16-25
......@@ -43,6 +43,7 @@ static int usage(const char *arg0) {
4343 " --pkg-end pop current pkg\n"
4444 " --release-fast build with optimizations on and safety off\n"
4545 " --release-safe build with optimizations on and safety on\n"
46 " --release-small build with size optimizations on and safety off\n"
4647 " --static output will be statically linked\n"
4748 " --strip exclude debug symbols\n"
4849 " --target-arch [name] specify target architecture\n"
......@@ -54,7 +55,6 @@ static int usage(const char *arg0) {
5455 " --verbose-ir turn on compiler debug output for Zig IR\n"
5556 " --verbose-llvm-ir turn on compiler debug output for LLVM IR\n"
5657 " --verbose-cimport turn on compiler debug output for C imports\n"
57 " --zig-install-prefix [path] override directory where zig thinks it is installed\n"
5858 " -dirafter [dir] same as -isystem but do it last\n"
5959 " -isystem [dir] add additional search path for other .h files\n"
6060 " -mllvm [arg] additional arguments to forward to LLVM's option processing\n"
......@@ -74,6 +74,7 @@ static int usage(const char *arg0) {
7474 " -L[dir] alias for --library-path\n"
7575 " -rdynamic add all symbols to the dynamic symbol table\n"
7676 " -rpath [path] add directory to the runtime library search path\n"
77 " --no-rosegment compromise security to workaround valgrind bug\n"
7778 " -mconsole (windows) --subsystem console to the linker\n"
7879 " -mwindows (windows) --subsystem windows to the linker\n"
7980 " -framework [name] (darwin) link against framework\n"
......@@ -177,6 +178,7 @@ static int find_zig_lib_dir(Buf *out_path) {
177178 int err;
178179
179180 Buf self_exe_path = BUF_INIT;
181 buf_resize(&self_exe_path, 0);
180182 if (!(err = os_self_exe_path(&self_exe_path))) {
181183 Buf *cur_path = &self_exe_path;
182184
......@@ -199,23 +201,14 @@ static int find_zig_lib_dir(Buf *out_path) {
199201 return ErrorFileNotFound;
200202}
201203
202static Buf *resolve_zig_lib_dir(const char *zig_install_prefix_arg) {
204static Buf *resolve_zig_lib_dir(void) {
203205 int err;
204206 Buf *result = buf_alloc();
205 if (zig_install_prefix_arg == nullptr) {
206 if ((err = find_zig_lib_dir(result))) {
207 fprintf(stderr, "Unable to find zig lib directory. Reinstall Zig or use --zig-install-prefix.\n");
208 exit(EXIT_FAILURE);
209 }
210 return result;
211 }
212 Buf *zig_lib_dir_buf = buf_create_from_str(zig_install_prefix_arg);
213 if (test_zig_install_prefix(zig_lib_dir_buf, result)) {
214 return result;
207 if ((err = find_zig_lib_dir(result))) {
208 fprintf(stderr, "Unable to find zig lib directory\n");
209 exit(EXIT_FAILURE);
215210 }
216
217 fprintf(stderr, "No Zig installation found at prefix: %s\n", zig_install_prefix_arg);
218 exit(EXIT_FAILURE);
211 return result;
219212}
220213
221214enum Cmd {
......@@ -299,7 +292,6 @@ int main(int argc, char **argv) {
299292 const char *libc_include_dir = nullptr;
300293 const char *msvc_lib_dir = nullptr;
301294 const char *kernel32_lib_dir = nullptr;
302 const char *zig_install_prefix = nullptr;
303295 const char *dynamic_linker = nullptr;
304296 ZigList<const char *> clang_argv = {0};
305297 ZigList<const char *> llvm_argv = {0};
......@@ -333,6 +325,7 @@ int main(int argc, char **argv) {
333325 ZigList<const char *> test_exec_args = {0};
334326 int comptime_args_end = 0;
335327 int runtime_args_start = argc;
328 bool no_rosegment_workaround = false;
336329
337330 if (argc >= 2 && strcmp(argv[1], "build") == 0) {
338331 const char *zig_exe_path = arg0;
......@@ -359,17 +352,12 @@ int main(int argc, char **argv) {
359352 } else if (i + 1 < argc && strcmp(argv[i], "--cache-dir") == 0) {
360353 cache_dir = argv[i + 1];
361354 i += 1;
362 } else if (i + 1 < argc && strcmp(argv[i], "--zig-install-prefix") == 0) {
363 args.append(argv[i]);
364 i += 1;
365 zig_install_prefix = argv[i];
366 args.append(zig_install_prefix);
367355 } else {
368356 args.append(argv[i]);
369357 }
370358 }
371359
372 Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);
360 Buf *zig_lib_dir_buf = resolve_zig_lib_dir();
373361
374362 Buf *zig_std_dir = buf_alloc();
375363 os_path_join(zig_lib_dir_buf, buf_create_from_str("std"), zig_std_dir);
......@@ -497,6 +485,8 @@ int main(int argc, char **argv) {
497485 build_mode = BuildModeFastRelease;
498486 } else if (strcmp(arg, "--release-safe") == 0) {
499487 build_mode = BuildModeSafeRelease;
488 } else if (strcmp(arg, "--release-small") == 0) {
489 build_mode = BuildModeSmallRelease;
500490 } else if (strcmp(arg, "--strip") == 0) {
501491 strip = true;
502492 } else if (strcmp(arg, "--static") == 0) {
......@@ -519,6 +509,8 @@ int main(int argc, char **argv) {
519509 mconsole = true;
520510 } else if (strcmp(arg, "-rdynamic") == 0) {
521511 rdynamic = true;
512 } else if (strcmp(arg, "--no-rosegment") == 0) {
513 no_rosegment_workaround = true;
522514 } else if (strcmp(arg, "--each-lib-rpath") == 0) {
523515 each_lib_rpath = true;
524516 } else if (strcmp(arg, "--enable-timing-info") == 0) {
......@@ -590,8 +582,6 @@ int main(int argc, char **argv) {
590582 msvc_lib_dir = argv[i];
591583 } else if (strcmp(arg, "--kernel32-lib-dir") == 0) {
592584 kernel32_lib_dir = argv[i];
593 } else if (strcmp(arg, "--zig-install-prefix") == 0) {
594 zig_install_prefix = argv[i];
595585 } else if (strcmp(arg, "--dynamic-linker") == 0) {
596586 dynamic_linker = argv[i];
597587 } else if (strcmp(arg, "-isystem") == 0) {
......@@ -803,7 +793,7 @@ int main(int argc, char **argv) {
803793 full_cache_dir);
804794 }
805795
806 Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);
796 Buf *zig_lib_dir_buf = resolve_zig_lib_dir();
807797
808798 CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, zig_lib_dir_buf);
809799 codegen_set_out_name(g, buf_out_name);
......@@ -858,6 +848,7 @@ int main(int argc, char **argv) {
858848
859849 codegen_set_windows_subsystem(g, mwindows, mconsole);
860850 codegen_set_rdynamic(g, rdynamic);
851 g->no_rosegment_workaround = no_rosegment_workaround;
861852 if (mmacosx_version_min && mios_version_min) {
862853 fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n");
863854 return EXIT_FAILURE;
src/os.cpp+1
......@@ -1007,6 +1007,7 @@ int os_self_exe_path(Buf *out_path) {
10071007 buf_resize(out_path, buf_len(out_path) * 2);
10081008 continue;
10091009 }
1010 buf_resize(out_path, amt);
10101011 return 0;
10111012 }
10121013#endif
src/parser.cpp+23-2
......@@ -648,12 +648,30 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, size_t *token_index, bool m
648648}
649649
650650/*
651SuspendExpression(body) = "suspend" "|" Symbol "|" body
651SuspendExpression(body) = option(Symbol ":") "suspend" option(("|" Symbol "|" body))
652652*/
653653static AstNode *ast_parse_suspend_block(ParseContext *pc, size_t *token_index, bool mandatory) {
654654 size_t orig_token_index = *token_index;
655655
656 Token *suspend_token = &pc->tokens->at(*token_index);
656 Token *name_token = nullptr;
657 Token *token = &pc->tokens->at(*token_index);
658 if (token->id == TokenIdSymbol) {
659 *token_index += 1;
660 Token *colon_token = &pc->tokens->at(*token_index);
661 if (colon_token->id == TokenIdColon) {
662 *token_index += 1;
663 name_token = token;
664 token = &pc->tokens->at(*token_index);
665 } else if (mandatory) {
666 ast_expect_token(pc, colon_token, TokenIdColon);
667 zig_unreachable();
668 } else {
669 *token_index = orig_token_index;
670 return nullptr;
671 }
672 }
673
674 Token *suspend_token = token;
657675 if (suspend_token->id == TokenIdKeywordSuspend) {
658676 *token_index += 1;
659677 } else if (mandatory) {
......@@ -675,6 +693,9 @@ static AstNode *ast_parse_suspend_block(ParseContext *pc, size_t *token_index, b
675693 }
676694
677695 AstNode *node = ast_create_node(pc, NodeTypeSuspend, suspend_token);
696 if (name_token != nullptr) {
697 node->data.suspend.name = token_buf(name_token);
698 }
678699 node->data.suspend.promise_symbol = ast_parse_symbol(pc, token_index);
679700 ast_eat_token(pc, token_index, TokenIdBinOr);
680701 node->data.suspend.block = ast_parse_block(pc, token_index, true);
src/zig_llvm.cpp+7-5
......@@ -82,7 +82,7 @@ static const bool assertions_on = false;
8282#endif
8383
8484bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
85 const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug)
85 const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, bool is_small)
8686{
8787 std::error_code EC;
8888 raw_fd_ostream dest(filename, EC, sys::fs::F_None);
......@@ -101,7 +101,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
101101 return true;
102102 }
103103 PMBuilder->OptLevel = target_machine->getOptLevel();
104 PMBuilder->SizeLevel = 0;
104 PMBuilder->SizeLevel = is_small ? 2 : 0;
105105
106106 PMBuilder->DisableTailCalls = is_debug;
107107 PMBuilder->DisableUnitAtATime = is_debug;
......@@ -780,10 +780,12 @@ static AtomicOrdering mapFromLLVMOrdering(LLVMAtomicOrdering Ordering) {
780780
781781LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,
782782 LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,
783 LLVMAtomicOrdering failure_ordering)
783 LLVMAtomicOrdering failure_ordering, bool is_weak)
784784{
785 return wrap(unwrap(builder)->CreateAtomicCmpXchg(unwrap(ptr), unwrap(cmp), unwrap(new_val),
786 mapFromLLVMOrdering(success_ordering), mapFromLLVMOrdering(failure_ordering)));
785 AtomicCmpXchgInst *inst = unwrap(builder)->CreateAtomicCmpXchg(unwrap(ptr), unwrap(cmp),
786 unwrap(new_val), mapFromLLVMOrdering(success_ordering), mapFromLLVMOrdering(failure_ordering));
787 inst->setWeak(is_weak);
788 return wrap(inst);
787789}
788790
789791LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
src/zig_llvm.h+2-2
......@@ -52,7 +52,7 @@ enum ZigLLVM_EmitOutputType {
5252};
5353
5454ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
55 const char *filename, enum ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug);
55 const char *filename, enum ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, bool is_small);
5656
5757ZIG_EXTERN_C LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref);
5858
......@@ -72,7 +72,7 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemSet(LLVMBuilderRef B, LLVMValueRef Ptr,
7272
7373ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,
7474 LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,
75 LLVMAtomicOrdering failure_ordering);
75 LLVMAtomicOrdering failure_ordering, bool is_weak);
7676
7777ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
7878 const char *name);
std/build.zig+10-5
......@@ -426,15 +426,18 @@ pub const Builder = struct {
426426
427427 const release_safe = self.option(bool, "release-safe", "optimizations on and safety on") ?? false;
428428 const release_fast = self.option(bool, "release-fast", "optimizations on and safety off") ?? false;
429 const release_small = self.option(bool, "release-small", "size optimizations on and safety off") ?? false;
429430
430 const mode = if (release_safe and !release_fast)
431 const mode = if (release_safe and !release_fast and !release_small)
431432 builtin.Mode.ReleaseSafe
432 else if (release_fast and !release_safe)
433 else if (release_fast and !release_safe and !release_small)
433434 builtin.Mode.ReleaseFast
434 else if (!release_fast and !release_safe)
435 else if (release_small and !release_fast and !release_safe)
436 builtin.Mode.ReleaseSmall
437 else if (!release_fast and !release_safe and !release_small)
435438 builtin.Mode.Debug
436439 else x: {
437 warn("Both -Drelease-safe and -Drelease-fast specified");
440 warn("Multiple release modes (of -Drelease-safe, -Drelease-fast and -Drelease-small)");
438441 self.markInvalidUserInput();
439442 break :x builtin.Mode.Debug;
440443 };
......@@ -1229,6 +1232,7 @@ pub const LibExeObjStep = struct {
12291232 builtin.Mode.Debug => {},
12301233 builtin.Mode.ReleaseSafe => zig_args.append("--release-safe") catch unreachable,
12311234 builtin.Mode.ReleaseFast => zig_args.append("--release-fast") catch unreachable,
1235 builtin.Mode.ReleaseSmall => zig_args.append("--release-small") catch unreachable,
12321236 }
12331237
12341238 zig_args.append("--cache-dir") catch unreachable;
......@@ -1369,7 +1373,7 @@ pub const LibExeObjStep = struct {
13691373 args.append("ssp-buffer-size=4") catch unreachable;
13701374 }
13711375 },
1372 builtin.Mode.ReleaseFast => {
1376 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {
13731377 args.append("-O2") catch unreachable;
13741378 args.append("-fno-stack-protector") catch unreachable;
13751379 },
......@@ -1706,6 +1710,7 @@ pub const TestStep = struct {
17061710 builtin.Mode.Debug => {},
17071711 builtin.Mode.ReleaseSafe => try zig_args.append("--release-safe"),
17081712 builtin.Mode.ReleaseFast => try zig_args.append("--release-fast"),
1713 builtin.Mode.ReleaseSmall => try zig_args.append("--release-small"),
17091714 }
17101715
17111716 switch (self.target) {
std/c/darwin.zig+18
......@@ -3,10 +3,28 @@ pub extern "c" fn _NSGetExecutablePath(buf: &u8, bufsize: &u32) c_int;
33
44pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: &u8, buf_len: usize, basep: &i64) usize;
55
6pub extern "c" fn mach_absolute_time() u64;
7pub extern "c" fn mach_timebase_info(tinfo: ?&mach_timebase_info_data) void;
8
69pub use @import("../os/darwin_errno.zig");
710
811pub const _errno = __error;
912
13pub const timeval = extern struct {
14 tv_sec: isize,
15 tv_usec: isize,
16};
17
18pub const timezone = extern struct {
19 tz_minuteswest: i32,
20 tz_dsttime: i32,
21};
22
23pub const mach_timebase_info_data = struct {
24 numer: u32,
25 denom: u32,
26};
27
1028/// Renamed to Stat to not conflict with the stat function.
1129pub const Stat = extern struct {
1230 dev: i32,
std/c/index.zig+2
......@@ -28,6 +28,7 @@ pub extern "c" fn unlink(path: &const u8) c_int;
2828pub extern "c" fn getcwd(buf: &u8, size: usize) ?&u8;
2929pub extern "c" fn waitpid(pid: c_int, stat_loc: &c_int, options: c_int) c_int;
3030pub extern "c" fn fork() c_int;
31pub extern "c" fn access(path: &const u8, mode: c_uint) c_int;
3132pub extern "c" fn pipe(fds: &c_int) c_int;
3233pub extern "c" fn mkdir(path: &const u8, mode: c_uint) c_int;
3334pub extern "c" fn symlink(existing: &const u8, new: &const u8) c_int;
......@@ -40,6 +41,7 @@ pub extern "c" fn dup2(old_fd: c_int, new_fd: c_int) c_int;
4041pub extern "c" fn readlink(noalias path: &const u8, noalias buf: &u8, bufsize: usize) isize;
4142pub extern "c" fn realpath(noalias file_name: &const u8, noalias resolved_name: &u8) ?&u8;
4243pub extern "c" fn sigprocmask(how: c_int, noalias set: &const sigset_t, noalias oset: ?&sigset_t) c_int;
44pub extern "c" fn gettimeofday(tv: ?&timeval, tz: ?&timezone) c_int;
4345pub extern "c" fn sigaction(sig: c_int, noalias act: &const Sigaction, noalias oact: ?&Sigaction) c_int;
4446pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?&timespec) c_int;
4547pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
std/crypto/throughput_test.zig+11-16
......@@ -1,22 +1,17 @@
11// Modify the HashFunction variable to the one wanted to test.
22//
3// NOTE: The throughput measurement may be slightly lower than other measurements since we run
4// through our block alignment functions as well. Be aware when comparing against other tests.
5//
63// ```
7// zig build-exe --release-fast --library c throughput_test.zig
4// zig build-exe --release-fast throughput_test.zig
85// ./throughput_test
96// ```
10const HashFunction = @import("md5.zig").Md5;
11const BytesToHash = 1024 * Mb;
127
138const std = @import("std");
9const time = std.os.time;
10const Timer = time.Timer;
11const HashFunction = @import("md5.zig").Md5;
1412
15const c = @cImport({
16 @cInclude("time.h");
17});
18
19const Mb = 1024 * 1024;
13const MiB = 1024 * 1024;
14const BytesToHash = 1024 * MiB;
2015
2116pub fn main() !void {
2217 var stdout_file = try std.io.getStdOut();
......@@ -29,15 +24,15 @@ pub fn main() !void {
2924 var h = HashFunction.init();
3025 var offset: usize = 0;
3126
32 const start = c.clock();
27 var timer = try Timer.start();
28 const start = timer.lap();
3329 while (offset < BytesToHash) : (offset += block.len) {
3430 h.update(block[0..]);
3531 }
36 const end = c.clock();
32 const end = timer.read();
3733
38 const elapsed_s = f64((end - start) * c.CLOCKS_PER_SEC) / 1000000;
34 const elapsed_s = f64(end - start) / time.ns_per_s;
3935 const throughput = u64(BytesToHash / elapsed_s);
4036
41 try stdout.print("{}: ", @typeName(HashFunction));
42 try stdout.print("{} Mb/s\n", throughput);
37 try stdout.print("{}: {} MiB/s\n", @typeName(HashFunction), throughput / (1 * MiB));
4338}
std/debug/index.zig+20-5
......@@ -38,7 +38,7 @@ pub fn getSelfDebugInfo() !&ElfStackTrace {
3838 if (self_debug_info) |info| {
3939 return info;
4040 } else {
41 const info = try openSelfDebugInfo(global_allocator);
41 const info = try openSelfDebugInfo(getDebugInfoAllocator());
4242 self_debug_info = info;
4343 return info;
4444 }
......@@ -51,7 +51,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
5151 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
5252 return;
5353 };
54 writeCurrentStackTrace(stderr, global_allocator, debug_info, stderr_file.isTty(), start_addr) catch |err| {
54 writeCurrentStackTrace(stderr, getDebugInfoAllocator(), debug_info, stderr_file.isTty(), start_addr) catch |err| {
5555 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
5656 return;
5757 };
......@@ -64,7 +64,7 @@ pub fn dumpStackTrace(stack_trace: &const builtin.StackTrace) void {
6464 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
6565 return;
6666 };
67 writeStackTrace(stack_trace, stderr, global_allocator, debug_info, stderr_file.isTty()) catch |err| {
67 writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, stderr_file.isTty()) catch |err| {
6868 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
6969 return;
7070 };
......@@ -592,8 +592,8 @@ fn getString(st: &ElfStackTrace, offset: u64) ![]u8 {
592592}
593593
594594fn readAllocBytes(allocator: &mem.Allocator, in_stream: var, size: usize) ![]u8 {
595 const buf = try global_allocator.alloc(u8, size);
596 errdefer global_allocator.free(buf);
595 const buf = try allocator.alloc(u8, size);
596 errdefer allocator.free(buf);
597597 if ((try in_stream.read(buf)) < size) return error.EndOfFile;
598598 return buf;
599599}
......@@ -1126,6 +1126,21 @@ fn readILeb128(in_stream: var) !i64 {
11261126 }
11271127}
11281128
1129/// This should only be used in temporary test programs.
11291130pub const global_allocator = &global_fixed_allocator.allocator;
11301131var global_fixed_allocator = std.heap.FixedBufferAllocator.init(global_allocator_mem[0..]);
11311132var global_allocator_mem: [100 * 1024]u8 = undefined;
1133
1134
1135// TODO make thread safe
1136var debug_info_allocator: ?&mem.Allocator = null;
1137var debug_info_direct_allocator: std.heap.DirectAllocator = undefined;
1138var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined;
1139fn getDebugInfoAllocator() &mem.Allocator {
1140 if (debug_info_allocator) |a| return a;
1141
1142 debug_info_direct_allocator = std.heap.DirectAllocator.init();
1143 debug_info_arena_allocator = std.heap.ArenaAllocator.init(&debug_info_direct_allocator.allocator);
1144 debug_info_allocator = &debug_info_arena_allocator.allocator;
1145 return &debug_info_arena_allocator.allocator;
1146}
std/elf.zig+611
......@@ -7,6 +7,246 @@ const mem = std.mem;
77const debug = std.debug;
88const InStream = std.stream.InStream;
99
10pub const AT_NULL = 0;
11pub const AT_IGNORE = 1;
12pub const AT_EXECFD = 2;
13pub const AT_PHDR = 3;
14pub const AT_PHENT = 4;
15pub const AT_PHNUM = 5;
16pub const AT_PAGESZ = 6;
17pub const AT_BASE = 7;
18pub const AT_FLAGS = 8;
19pub const AT_ENTRY = 9;
20pub const AT_NOTELF = 10;
21pub const AT_UID = 11;
22pub const AT_EUID = 12;
23pub const AT_GID = 13;
24pub const AT_EGID = 14;
25pub const AT_CLKTCK = 17;
26pub const AT_PLATFORM = 15;
27pub const AT_HWCAP = 16;
28pub const AT_FPUCW = 18;
29pub const AT_DCACHEBSIZE = 19;
30pub const AT_ICACHEBSIZE = 20;
31pub const AT_UCACHEBSIZE = 21;
32pub const AT_IGNOREPPC = 22;
33pub const AT_SECURE = 23;
34pub const AT_BASE_PLATFORM = 24;
35pub const AT_RANDOM = 25;
36pub const AT_HWCAP2 = 26;
37pub const AT_EXECFN = 31;
38pub const AT_SYSINFO = 32;
39pub const AT_SYSINFO_EHDR = 33;
40pub const AT_L1I_CACHESHAPE = 34;
41pub const AT_L1D_CACHESHAPE = 35;
42pub const AT_L2_CACHESHAPE = 36;
43pub const AT_L3_CACHESHAPE = 37;
44pub const AT_L1I_CACHESIZE = 40;
45pub const AT_L1I_CACHEGEOMETRY = 41;
46pub const AT_L1D_CACHESIZE = 42;
47pub const AT_L1D_CACHEGEOMETRY = 43;
48pub const AT_L2_CACHESIZE = 44;
49pub const AT_L2_CACHEGEOMETRY = 45;
50pub const AT_L3_CACHESIZE = 46;
51pub const AT_L3_CACHEGEOMETRY = 47;
52
53pub const DT_NULL = 0;
54pub const DT_NEEDED = 1;
55pub const DT_PLTRELSZ = 2;
56pub const DT_PLTGOT = 3;
57pub const DT_HASH = 4;
58pub const DT_STRTAB = 5;
59pub const DT_SYMTAB = 6;
60pub const DT_RELA = 7;
61pub const DT_RELASZ = 8;
62pub const DT_RELAENT = 9;
63pub const DT_STRSZ = 10;
64pub const DT_SYMENT = 11;
65pub const DT_INIT = 12;
66pub const DT_FINI = 13;
67pub const DT_SONAME = 14;
68pub const DT_RPATH = 15;
69pub const DT_SYMBOLIC = 16;
70pub const DT_REL = 17;
71pub const DT_RELSZ = 18;
72pub const DT_RELENT = 19;
73pub const DT_PLTREL = 20;
74pub const DT_DEBUG = 21;
75pub const DT_TEXTREL = 22;
76pub const DT_JMPREL = 23;
77pub const DT_BIND_NOW = 24;
78pub const DT_INIT_ARRAY = 25;
79pub const DT_FINI_ARRAY = 26;
80pub const DT_INIT_ARRAYSZ = 27;
81pub const DT_FINI_ARRAYSZ = 28;
82pub const DT_RUNPATH = 29;
83pub const DT_FLAGS = 30;
84pub const DT_ENCODING = 32;
85pub const DT_PREINIT_ARRAY = 32;
86pub const DT_PREINIT_ARRAYSZ = 33;
87pub const DT_SYMTAB_SHNDX = 34;
88pub const DT_NUM = 35;
89pub const DT_LOOS = 0x6000000d;
90pub const DT_HIOS = 0x6ffff000;
91pub const DT_LOPROC = 0x70000000;
92pub const DT_HIPROC = 0x7fffffff;
93pub const DT_PROCNUM = DT_MIPS_NUM;
94
95pub const DT_VALRNGLO = 0x6ffffd00;
96pub const DT_GNU_PRELINKED = 0x6ffffdf5;
97pub const DT_GNU_CONFLICTSZ = 0x6ffffdf6;
98pub const DT_GNU_LIBLISTSZ = 0x6ffffdf7;
99pub const DT_CHECKSUM = 0x6ffffdf8;
100pub const DT_PLTPADSZ = 0x6ffffdf9;
101pub const DT_MOVEENT = 0x6ffffdfa;
102pub const DT_MOVESZ = 0x6ffffdfb;
103pub const DT_FEATURE_1 = 0x6ffffdfc;
104pub const DT_POSFLAG_1 = 0x6ffffdfd;
105
106pub const DT_SYMINSZ = 0x6ffffdfe;
107pub const DT_SYMINENT = 0x6ffffdff;
108pub const DT_VALRNGHI = 0x6ffffdff;
109pub const DT_VALNUM = 12;
110
111pub const DT_ADDRRNGLO = 0x6ffffe00;
112pub const DT_GNU_HASH = 0x6ffffef5;
113pub const DT_TLSDESC_PLT = 0x6ffffef6;
114pub const DT_TLSDESC_GOT = 0x6ffffef7;
115pub const DT_GNU_CONFLICT = 0x6ffffef8;
116pub const DT_GNU_LIBLIST = 0x6ffffef9;
117pub const DT_CONFIG = 0x6ffffefa;
118pub const DT_DEPAUDIT = 0x6ffffefb;
119pub const DT_AUDIT = 0x6ffffefc;
120pub const DT_PLTPAD = 0x6ffffefd;
121pub const DT_MOVETAB = 0x6ffffefe;
122pub const DT_SYMINFO = 0x6ffffeff;
123pub const DT_ADDRRNGHI = 0x6ffffeff;
124pub const DT_ADDRNUM = 11;
125
126
127pub const DT_VERSYM = 0x6ffffff0;
128
129pub const DT_RELACOUNT = 0x6ffffff9;
130pub const DT_RELCOUNT = 0x6ffffffa;
131
132
133pub const DT_FLAGS_1 = 0x6ffffffb;
134pub const DT_VERDEF = 0x6ffffffc;
135
136pub const DT_VERDEFNUM = 0x6ffffffd;
137pub const DT_VERNEED = 0x6ffffffe;
138
139pub const DT_VERNEEDNUM = 0x6fffffff;
140pub const DT_VERSIONTAGNUM = 16;
141
142
143
144pub const DT_AUXILIARY = 0x7ffffffd;
145pub const DT_FILTER = 0x7fffffff;
146pub const DT_EXTRANUM = 3;
147
148
149pub const DT_SPARC_REGISTER = 0x70000001;
150pub const DT_SPARC_NUM = 2;
151
152pub const DT_MIPS_RLD_VERSION = 0x70000001;
153pub const DT_MIPS_TIME_STAMP = 0x70000002;
154pub const DT_MIPS_ICHECKSUM = 0x70000003;
155pub const DT_MIPS_IVERSION = 0x70000004;
156pub const DT_MIPS_FLAGS = 0x70000005;
157pub const DT_MIPS_BASE_ADDRESS = 0x70000006;
158pub const DT_MIPS_MSYM = 0x70000007;
159pub const DT_MIPS_CONFLICT = 0x70000008;
160pub const DT_MIPS_LIBLIST = 0x70000009;
161pub const DT_MIPS_LOCAL_GOTNO = 0x7000000a;
162pub const DT_MIPS_CONFLICTNO = 0x7000000b;
163pub const DT_MIPS_LIBLISTNO = 0x70000010;
164pub const DT_MIPS_SYMTABNO = 0x70000011;
165pub const DT_MIPS_UNREFEXTNO = 0x70000012;
166pub const DT_MIPS_GOTSYM = 0x70000013;
167pub const DT_MIPS_HIPAGENO = 0x70000014;
168pub const DT_MIPS_RLD_MAP = 0x70000016;
169pub const DT_MIPS_DELTA_CLASS = 0x70000017;
170pub const DT_MIPS_DELTA_CLASS_NO = 0x70000018;
171
172pub const DT_MIPS_DELTA_INSTANCE = 0x70000019;
173pub const DT_MIPS_DELTA_INSTANCE_NO = 0x7000001a;
174
175pub const DT_MIPS_DELTA_RELOC = 0x7000001b;
176pub const DT_MIPS_DELTA_RELOC_NO = 0x7000001c;
177
178pub const DT_MIPS_DELTA_SYM = 0x7000001d;
179
180pub const DT_MIPS_DELTA_SYM_NO = 0x7000001e;
181
182pub const DT_MIPS_DELTA_CLASSSYM = 0x70000020;
183
184pub const DT_MIPS_DELTA_CLASSSYM_NO = 0x70000021;
185
186pub const DT_MIPS_CXX_FLAGS = 0x70000022;
187pub const DT_MIPS_PIXIE_INIT = 0x70000023;
188pub const DT_MIPS_SYMBOL_LIB = 0x70000024;
189pub const DT_MIPS_LOCALPAGE_GOTIDX = 0x70000025;
190pub const DT_MIPS_LOCAL_GOTIDX = 0x70000026;
191pub const DT_MIPS_HIDDEN_GOTIDX = 0x70000027;
192pub const DT_MIPS_PROTECTED_GOTIDX = 0x70000028;
193pub const DT_MIPS_OPTIONS = 0x70000029;
194pub const DT_MIPS_INTERFACE = 0x7000002a;
195pub const DT_MIPS_DYNSTR_ALIGN = 0x7000002b;
196pub const DT_MIPS_INTERFACE_SIZE = 0x7000002c;
197pub const DT_MIPS_RLD_TEXT_RESOLVE_ADDR = 0x7000002d;
198
199pub const DT_MIPS_PERF_SUFFIX = 0x7000002e;
200
201pub const DT_MIPS_COMPACT_SIZE = 0x7000002f;
202pub const DT_MIPS_GP_VALUE = 0x70000030;
203pub const DT_MIPS_AUX_DYNAMIC = 0x70000031;
204
205pub const DT_MIPS_PLTGOT = 0x70000032;
206
207pub const DT_MIPS_RWPLT = 0x70000034;
208pub const DT_MIPS_RLD_MAP_REL = 0x70000035;
209pub const DT_MIPS_NUM = 0x36;
210
211pub const DT_ALPHA_PLTRO = (DT_LOPROC + 0);
212pub const DT_ALPHA_NUM = 1;
213
214pub const DT_PPC_GOT = (DT_LOPROC + 0);
215pub const DT_PPC_OPT = (DT_LOPROC + 1);
216pub const DT_PPC_NUM = 2;
217
218pub const DT_PPC64_GLINK = (DT_LOPROC + 0);
219pub const DT_PPC64_OPD = (DT_LOPROC + 1);
220pub const DT_PPC64_OPDSZ = (DT_LOPROC + 2);
221pub const DT_PPC64_OPT = (DT_LOPROC + 3);
222pub const DT_PPC64_NUM = 4;
223
224pub const DT_IA_64_PLT_RESERVE = (DT_LOPROC + 0);
225pub const DT_IA_64_NUM = 1;
226
227pub const DT_NIOS2_GP = 0x70000002;
228
229pub const PT_NULL = 0;
230pub const PT_LOAD = 1;
231pub const PT_DYNAMIC = 2;
232pub const PT_INTERP = 3;
233pub const PT_NOTE = 4;
234pub const PT_SHLIB = 5;
235pub const PT_PHDR = 6;
236pub const PT_TLS = 7;
237pub const PT_NUM = 8;
238pub const PT_LOOS = 0x60000000;
239pub const PT_GNU_EH_FRAME = 0x6474e550;
240pub const PT_GNU_STACK = 0x6474e551;
241pub const PT_GNU_RELRO = 0x6474e552;
242pub const PT_LOSUNW = 0x6ffffffa;
243pub const PT_SUNWBSS = 0x6ffffffa;
244pub const PT_SUNWSTACK = 0x6ffffffb;
245pub const PT_HISUNW = 0x6fffffff;
246pub const PT_HIOS = 0x6fffffff;
247pub const PT_LOPROC = 0x70000000;
248pub const PT_HIPROC = 0x7fffffff;
249
10250pub const SHT_NULL = 0;
11251pub const SHT_PROGBITS = 1;
12252pub const SHT_SYMTAB = 2;
......@@ -31,6 +271,45 @@ pub const SHT_HIPROC = 0x7fffffff;
31271pub const SHT_LOUSER = 0x80000000;
32272pub const SHT_HIUSER = 0xffffffff;
33273
274pub const STB_LOCAL = 0;
275pub const STB_GLOBAL = 1;
276pub const STB_WEAK = 2;
277pub const STB_NUM = 3;
278pub const STB_LOOS = 10;
279pub const STB_GNU_UNIQUE = 10;
280pub const STB_HIOS = 12;
281pub const STB_LOPROC = 13;
282pub const STB_HIPROC = 15;
283
284pub const STB_MIPS_SPLIT_COMMON = 13;
285
286pub const STT_NOTYPE = 0;
287pub const STT_OBJECT = 1;
288pub const STT_FUNC = 2;
289pub const STT_SECTION = 3;
290pub const STT_FILE = 4;
291pub const STT_COMMON = 5;
292pub const STT_TLS = 6;
293pub const STT_NUM = 7;
294pub const STT_LOOS = 10;
295pub const STT_GNU_IFUNC = 10;
296pub const STT_HIOS = 12;
297pub const STT_LOPROC = 13;
298pub const STT_HIPROC = 15;
299
300pub const STT_SPARC_REGISTER = 13;
301
302pub const STT_PARISC_MILLICODE = 13;
303
304pub const STT_HP_OPAQUE = (STT_LOOS + 0x1);
305pub const STT_HP_STUB = (STT_LOOS + 0x2);
306
307pub const STT_ARM_TFUNC = STT_LOPROC;
308pub const STT_ARM_16BIT = STT_HIPROC;
309
310pub const VER_FLG_BASE = 0x1;
311pub const VER_FLG_WEAK = 0x2;
312
34313pub const FileType = enum {
35314 Relocatable,
36315 Executable,
......@@ -266,3 +545,335 @@ pub const Elf = struct {
266545 try elf.in_file.seekTo(elf_section.offset);
267546 }
268547};
548
549pub const EI_NIDENT = 16;
550pub const Elf32_Half = u16;
551pub const Elf64_Half = u16;
552pub const Elf32_Word = u32;
553pub const Elf32_Sword = i32;
554pub const Elf64_Word = u32;
555pub const Elf64_Sword = i32;
556pub const Elf32_Xword = u64;
557pub const Elf32_Sxword = i64;
558pub const Elf64_Xword = u64;
559pub const Elf64_Sxword = i64;
560pub const Elf32_Addr = u32;
561pub const Elf64_Addr = u64;
562pub const Elf32_Off = u32;
563pub const Elf64_Off = u64;
564pub const Elf32_Section = u16;
565pub const Elf64_Section = u16;
566pub const Elf32_Versym = Elf32_Half;
567pub const Elf64_Versym = Elf64_Half;
568pub const Elf32_Ehdr = extern struct {
569 e_ident: [EI_NIDENT]u8,
570 e_type: Elf32_Half,
571 e_machine: Elf32_Half,
572 e_version: Elf32_Word,
573 e_entry: Elf32_Addr,
574 e_phoff: Elf32_Off,
575 e_shoff: Elf32_Off,
576 e_flags: Elf32_Word,
577 e_ehsize: Elf32_Half,
578 e_phentsize: Elf32_Half,
579 e_phnum: Elf32_Half,
580 e_shentsize: Elf32_Half,
581 e_shnum: Elf32_Half,
582 e_shstrndx: Elf32_Half,
583};
584pub const Elf64_Ehdr = extern struct {
585 e_ident: [EI_NIDENT]u8,
586 e_type: Elf64_Half,
587 e_machine: Elf64_Half,
588 e_version: Elf64_Word,
589 e_entry: Elf64_Addr,
590 e_phoff: Elf64_Off,
591 e_shoff: Elf64_Off,
592 e_flags: Elf64_Word,
593 e_ehsize: Elf64_Half,
594 e_phentsize: Elf64_Half,
595 e_phnum: Elf64_Half,
596 e_shentsize: Elf64_Half,
597 e_shnum: Elf64_Half,
598 e_shstrndx: Elf64_Half,
599};
600pub const Elf32_Shdr = extern struct {
601 sh_name: Elf32_Word,
602 sh_type: Elf32_Word,
603 sh_flags: Elf32_Word,
604 sh_addr: Elf32_Addr,
605 sh_offset: Elf32_Off,
606 sh_size: Elf32_Word,
607 sh_link: Elf32_Word,
608 sh_info: Elf32_Word,
609 sh_addralign: Elf32_Word,
610 sh_entsize: Elf32_Word,
611};
612pub const Elf64_Shdr = extern struct {
613 sh_name: Elf64_Word,
614 sh_type: Elf64_Word,
615 sh_flags: Elf64_Xword,
616 sh_addr: Elf64_Addr,
617 sh_offset: Elf64_Off,
618 sh_size: Elf64_Xword,
619 sh_link: Elf64_Word,
620 sh_info: Elf64_Word,
621 sh_addralign: Elf64_Xword,
622 sh_entsize: Elf64_Xword,
623};
624pub const Elf32_Chdr = extern struct {
625 ch_type: Elf32_Word,
626 ch_size: Elf32_Word,
627 ch_addralign: Elf32_Word,
628};
629pub const Elf64_Chdr = extern struct {
630 ch_type: Elf64_Word,
631 ch_reserved: Elf64_Word,
632 ch_size: Elf64_Xword,
633 ch_addralign: Elf64_Xword,
634};
635pub const Elf32_Sym = extern struct {
636 st_name: Elf32_Word,
637 st_value: Elf32_Addr,
638 st_size: Elf32_Word,
639 st_info: u8,
640 st_other: u8,
641 st_shndx: Elf32_Section,
642};
643pub const Elf64_Sym = extern struct {
644 st_name: Elf64_Word,
645 st_info: u8,
646 st_other: u8,
647 st_shndx: Elf64_Section,
648 st_value: Elf64_Addr,
649 st_size: Elf64_Xword,
650};
651pub const Elf32_Syminfo = extern struct {
652 si_boundto: Elf32_Half,
653 si_flags: Elf32_Half,
654};
655pub const Elf64_Syminfo = extern struct {
656 si_boundto: Elf64_Half,
657 si_flags: Elf64_Half,
658};
659pub const Elf32_Rel = extern struct {
660 r_offset: Elf32_Addr,
661 r_info: Elf32_Word,
662};
663pub const Elf64_Rel = extern struct {
664 r_offset: Elf64_Addr,
665 r_info: Elf64_Xword,
666};
667pub const Elf32_Rela = extern struct {
668 r_offset: Elf32_Addr,
669 r_info: Elf32_Word,
670 r_addend: Elf32_Sword,
671};
672pub const Elf64_Rela = extern struct {
673 r_offset: Elf64_Addr,
674 r_info: Elf64_Xword,
675 r_addend: Elf64_Sxword,
676};
677pub const Elf32_Phdr = extern struct {
678 p_type: Elf32_Word,
679 p_offset: Elf32_Off,
680 p_vaddr: Elf32_Addr,
681 p_paddr: Elf32_Addr,
682 p_filesz: Elf32_Word,
683 p_memsz: Elf32_Word,
684 p_flags: Elf32_Word,
685 p_align: Elf32_Word,
686};
687pub const Elf64_Phdr = extern struct {
688 p_type: Elf64_Word,
689 p_flags: Elf64_Word,
690 p_offset: Elf64_Off,
691 p_vaddr: Elf64_Addr,
692 p_paddr: Elf64_Addr,
693 p_filesz: Elf64_Xword,
694 p_memsz: Elf64_Xword,
695 p_align: Elf64_Xword,
696};
697pub const Elf32_Dyn = extern struct {
698 d_tag: Elf32_Sword,
699 d_un: extern union {
700 d_val: Elf32_Word,
701 d_ptr: Elf32_Addr,
702 },
703};
704pub const Elf64_Dyn = extern struct {
705 d_tag: Elf64_Sxword,
706 d_un: extern union {
707 d_val: Elf64_Xword,
708 d_ptr: Elf64_Addr,
709 },
710};
711pub const Elf32_Verdef = extern struct {
712 vd_version: Elf32_Half,
713 vd_flags: Elf32_Half,
714 vd_ndx: Elf32_Half,
715 vd_cnt: Elf32_Half,
716 vd_hash: Elf32_Word,
717 vd_aux: Elf32_Word,
718 vd_next: Elf32_Word,
719};
720pub const Elf64_Verdef = extern struct {
721 vd_version: Elf64_Half,
722 vd_flags: Elf64_Half,
723 vd_ndx: Elf64_Half,
724 vd_cnt: Elf64_Half,
725 vd_hash: Elf64_Word,
726 vd_aux: Elf64_Word,
727 vd_next: Elf64_Word,
728};
729pub const Elf32_Verdaux = extern struct {
730 vda_name: Elf32_Word,
731 vda_next: Elf32_Word,
732};
733pub const Elf64_Verdaux = extern struct {
734 vda_name: Elf64_Word,
735 vda_next: Elf64_Word,
736};
737pub const Elf32_Verneed = extern struct {
738 vn_version: Elf32_Half,
739 vn_cnt: Elf32_Half,
740 vn_file: Elf32_Word,
741 vn_aux: Elf32_Word,
742 vn_next: Elf32_Word,
743};
744pub const Elf64_Verneed = extern struct {
745 vn_version: Elf64_Half,
746 vn_cnt: Elf64_Half,
747 vn_file: Elf64_Word,
748 vn_aux: Elf64_Word,
749 vn_next: Elf64_Word,
750};
751pub const Elf32_Vernaux = extern struct {
752 vna_hash: Elf32_Word,
753 vna_flags: Elf32_Half,
754 vna_other: Elf32_Half,
755 vna_name: Elf32_Word,
756 vna_next: Elf32_Word,
757};
758pub const Elf64_Vernaux = extern struct {
759 vna_hash: Elf64_Word,
760 vna_flags: Elf64_Half,
761 vna_other: Elf64_Half,
762 vna_name: Elf64_Word,
763 vna_next: Elf64_Word,
764};
765pub const Elf32_auxv_t = extern struct {
766 a_type: u32,
767 a_un: extern union {
768 a_val: u32,
769 },
770};
771pub const Elf64_auxv_t = extern struct {
772 a_type: u64,
773 a_un: extern union {
774 a_val: u64,
775 },
776};
777pub const Elf32_Nhdr = extern struct {
778 n_namesz: Elf32_Word,
779 n_descsz: Elf32_Word,
780 n_type: Elf32_Word,
781};
782pub const Elf64_Nhdr = extern struct {
783 n_namesz: Elf64_Word,
784 n_descsz: Elf64_Word,
785 n_type: Elf64_Word,
786};
787pub const Elf32_Move = extern struct {
788 m_value: Elf32_Xword,
789 m_info: Elf32_Word,
790 m_poffset: Elf32_Word,
791 m_repeat: Elf32_Half,
792 m_stride: Elf32_Half,
793};
794pub const Elf64_Move = extern struct {
795 m_value: Elf64_Xword,
796 m_info: Elf64_Xword,
797 m_poffset: Elf64_Xword,
798 m_repeat: Elf64_Half,
799 m_stride: Elf64_Half,
800};
801pub const Elf32_gptab = extern union {
802 gt_header: extern struct {
803 gt_current_g_value: Elf32_Word,
804 gt_unused: Elf32_Word,
805 },
806 gt_entry: extern struct {
807 gt_g_value: Elf32_Word,
808 gt_bytes: Elf32_Word,
809 },
810};
811pub const Elf32_RegInfo = extern struct {
812 ri_gprmask: Elf32_Word,
813 ri_cprmask: [4]Elf32_Word,
814 ri_gp_value: Elf32_Sword,
815};
816pub const Elf_Options = extern struct {
817 kind: u8,
818 size: u8,
819 @"section": Elf32_Section,
820 info: Elf32_Word,
821};
822pub const Elf_Options_Hw = extern struct {
823 hwp_flags1: Elf32_Word,
824 hwp_flags2: Elf32_Word,
825};
826pub const Elf32_Lib = extern struct {
827 l_name: Elf32_Word,
828 l_time_stamp: Elf32_Word,
829 l_checksum: Elf32_Word,
830 l_version: Elf32_Word,
831 l_flags: Elf32_Word,
832};
833pub const Elf64_Lib = extern struct {
834 l_name: Elf64_Word,
835 l_time_stamp: Elf64_Word,
836 l_checksum: Elf64_Word,
837 l_version: Elf64_Word,
838 l_flags: Elf64_Word,
839};
840pub const Elf32_Conflict = Elf32_Addr;
841pub const Elf_MIPS_ABIFlags_v0 = extern struct {
842 version: Elf32_Half,
843 isa_level: u8,
844 isa_rev: u8,
845 gpr_size: u8,
846 cpr1_size: u8,
847 cpr2_size: u8,
848 fp_abi: u8,
849 isa_ext: Elf32_Word,
850 ases: Elf32_Word,
851 flags1: Elf32_Word,
852 flags2: Elf32_Word,
853};
854
855pub const Ehdr = switch(@sizeOf(usize)) {
856 4 => Elf32_Ehdr,
857 8 => Elf64_Ehdr,
858 else => @compileError("expected pointer size of 32 or 64"),
859};
860pub const Phdr = switch(@sizeOf(usize)) {
861 4 => Elf32_Phdr,
862 8 => Elf64_Phdr,
863 else => @compileError("expected pointer size of 32 or 64"),
864};
865pub const Sym = switch(@sizeOf(usize)) {
866 4 => Elf32_Sym,
867 8 => Elf64_Sym,
868 else => @compileError("expected pointer size of 32 or 64"),
869};
870pub const Verdef = switch(@sizeOf(usize)) {
871 4 => Elf32_Verdef,
872 8 => Elf64_Verdef,
873 else => @compileError("expected pointer size of 32 or 64"),
874};
875pub const Verdaux = switch(@sizeOf(usize)) {
876 4 => Elf32_Verdaux,
877 8 => Elf64_Verdaux,
878 else => @compileError("expected pointer size of 32 or 64"),
879};
std/fmt/index.zig+15-14
......@@ -8,25 +8,25 @@ const errol3 = @import("errol/index.zig").errol3;
88
99const max_int_digits = 65;
1010
11const State = enum { // TODO put inside format function and make sure the name and debug info is correct
12 Start,
13 OpenBrace,
14 CloseBrace,
15 Integer,
16 IntegerWidth,
17 Float,
18 FloatWidth,
19 Character,
20 Buf,
21 BufWidth,
22};
23
2411/// Renders fmt string with args, calling output with slices of bytes.
2512/// If `output` returns an error, the error is returned from `format` and
2613/// `output` is not called again.
2714pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void,
2815 comptime fmt: []const u8, args: ...) Errors!void
2916{
17 const State = enum {
18 Start,
19 OpenBrace,
20 CloseBrace,
21 Integer,
22 IntegerWidth,
23 Float,
24 FloatWidth,
25 Character,
26 Buf,
27 BufWidth,
28 };
29
3030 comptime var start_index = 0;
3131 comptime var state = State.Start;
3232 comptime var next_arg = 0;
......@@ -86,7 +86,8 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
8686 },
8787 's' => {
8888 state = State.Buf;
89 },'.' => {
89 },
90 '.' => {
9091 state = State.Float;
9192 },
9293 else => @compileError("Unknown format character: " ++ []u8{c}),
std/heap.zig+59-8
......@@ -79,19 +79,38 @@ pub const DirectAllocator = struct {
7979
8080 switch (builtin.os) {
8181 Os.linux, Os.macosx, Os.ios => {
82 assert(alignment <= os.page_size);
8382 const p = os.posix;
84 const addr = p.mmap(null, n, p.PROT_READ|p.PROT_WRITE,
85 p.MAP_PRIVATE|p.MAP_ANONYMOUS, -1, 0);
86 if (addr == p.MAP_FAILED) {
87 return error.OutOfMemory;
88 }
89 return @intToPtr(&u8, addr)[0..n];
83 const alloc_size = if(alignment <= os.page_size) n else n + alignment;
84 const addr = p.mmap(null, alloc_size, p.PROT_READ|p.PROT_WRITE,
85 p.MAP_PRIVATE|p.MAP_ANONYMOUS, -1, 0);
86 if(addr == p.MAP_FAILED) return error.OutOfMemory;
87
88 if(alloc_size == n) return @intToPtr(&u8, addr)[0..n];
89
90 var aligned_addr = addr & ~usize(alignment - 1);
91 aligned_addr += alignment;
92
93 //We can unmap the unused portions of our mmap, but we must only
94 // pass munmap bytes that exist outside our allocated pages or it
95 // will happily eat us too
96
97 //Since alignment > page_size, we are by definition on a page boundry
98 const unused_start = addr;
99 const unused_len = aligned_addr - 1 - unused_start;
100
101 var err = p.munmap(@intToPtr(&u8, unused_start), unused_len);
102 debug.assert(p.getErrno(err) == 0);
103
104 //It is impossible that there is an unoccupied page at the top of our
105 // mmap.
106
107 return @intToPtr(&u8, aligned_addr)[0..n];
90108 },
91109 Os.windows => {
92110 const amt = n + alignment + @sizeOf(usize);
93111 const heap_handle = self.heap_handle ?? blk: {
94 const hh = os.windows.HeapCreate(os.windows.HEAP_NO_SERIALIZE, amt, 0) ?? return error.OutOfMemory;
112 const hh = os.windows.HeapCreate(os.windows.HEAP_NO_SERIALIZE, amt, 0)
113 ?? return error.OutOfMemory;
95114 self.heap_handle = hh;
96115 break :blk hh;
97116 };
......@@ -322,6 +341,7 @@ test "DirectAllocator" {
322341
323342 const allocator = &direct_allocator.allocator;
324343 try testAllocator(allocator);
344 try testAllocatorLargeAlignment(allocator);
325345}
326346
327347test "ArenaAllocator" {
......@@ -332,6 +352,7 @@ test "ArenaAllocator" {
332352 defer arena_allocator.deinit();
333353
334354 try testAllocator(&arena_allocator.allocator);
355 try testAllocatorLargeAlignment(&arena_allocator.allocator);
335356}
336357
337358var test_fixed_buffer_allocator_memory: [30000 * @sizeOf(usize)]u8 = undefined;
......@@ -339,6 +360,7 @@ test "FixedBufferAllocator" {
339360 var fixed_buffer_allocator = FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..]);
340361
341362 try testAllocator(&fixed_buffer_allocator.allocator);
363 try testAllocatorLargeAlignment(&fixed_buffer_allocator.allocator);
342364}
343365
344366fn testAllocator(allocator: &mem.Allocator) !void {
......@@ -360,3 +382,32 @@ fn testAllocator(allocator: &mem.Allocator) !void {
360382
361383 allocator.free(slice);
362384}
385
386fn testAllocatorLargeAlignment(allocator: &mem.Allocator) mem.Allocator.Error!void {
387 //Maybe a platform's page_size is actually the same as or
388 // very near usize?
389 if(os.page_size << 2 > @maxValue(usize)) return;
390
391 const USizeShift = @IntType(false, std.math.log2(usize.bit_count));
392 const large_align = u29(os.page_size << 2);
393
394 var align_mask: usize = undefined;
395 _ = @shlWithOverflow(usize, ~usize(0), USizeShift(@ctz(large_align)), &align_mask);
396
397 var slice = try allocator.allocFn(allocator, 500, large_align);
398 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
399
400 slice = try allocator.reallocFn(allocator, slice, 100, large_align);
401 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
402
403 slice = try allocator.reallocFn(allocator, slice, 5000, large_align);
404 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
405
406 slice = try allocator.reallocFn(allocator, slice, 10, large_align);
407 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
408
409 slice = try allocator.reallocFn(allocator, slice, 20000, large_align);
410 debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
411
412 allocator.free(slice);
413}
std/math/complex/abs.zig created+18
......@@ -0,0 +1,18 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn abs(z: var) @typeOf(z.re) {
8 const T = @typeOf(z.re);
9 return math.hypot(T, z.re, z.im);
10}
11
12const epsilon = 0.0001;
13
14test "complex.cabs" {
15 const a = Complex(f32).new(5, 3);
16 const c = abs(a);
17 debug.assert(math.approxEq(f32, c, 5.83095, epsilon));
18}
std/math/complex/acos.zig created+21
......@@ -0,0 +1,21 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn acos(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 const q = cmath.asin(z);
10 return Complex(T).new(T(math.pi) / 2 - q.re, -q.im);
11}
12
13const epsilon = 0.0001;
14
15test "complex.cacos" {
16 const a = Complex(f32).new(5, 3);
17 const c = acos(a);
18
19 debug.assert(math.approxEq(f32, c.re, 0.546975, epsilon));
20 debug.assert(math.approxEq(f32, c.im, -2.452914, epsilon));
21}
std/math/complex/acosh.zig created+21
......@@ -0,0 +1,21 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn acosh(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 const q = cmath.acos(z);
10 return Complex(T).new(-q.im, q.re);
11}
12
13const epsilon = 0.0001;
14
15test "complex.cacosh" {
16 const a = Complex(f32).new(5, 3);
17 const c = acosh(a);
18
19 debug.assert(math.approxEq(f32, c.re, 2.452914, epsilon));
20 debug.assert(math.approxEq(f32, c.im, 0.546975, epsilon));
21}
std/math/complex/arg.zig created+18
......@@ -0,0 +1,18 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn arg(z: var) @typeOf(z.re) {
8 const T = @typeOf(z.re);
9 return math.atan2(T, z.im, z.re);
10}
11
12const epsilon = 0.0001;
13
14test "complex.carg" {
15 const a = Complex(f32).new(5, 3);
16 const c = arg(a);
17 debug.assert(math.approxEq(f32, c, 0.540420, epsilon));
18}
std/math/complex/asin.zig created+27
......@@ -0,0 +1,27 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn asin(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 const x = z.re;
10 const y = z.im;
11
12 const p = Complex(T).new(1.0 - (x - y) * (x + y), -2.0 * x * y);
13 const q = Complex(T).new(-y, x);
14 const r = cmath.log(q.add(cmath.sqrt(p)));
15
16 return Complex(T).new(r.im, -r.re);
17}
18
19const epsilon = 0.0001;
20
21test "complex.casin" {
22 const a = Complex(f32).new(5, 3);
23 const c = asin(a);
24
25 debug.assert(math.approxEq(f32, c.re, 1.023822, epsilon));
26 debug.assert(math.approxEq(f32, c.im, 2.452914, epsilon));
27}
std/math/complex/asinh.zig created+22
......@@ -0,0 +1,22 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn asinh(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 const q = Complex(T).new(-z.im, z.re);
10 const r = cmath.asin(q);
11 return Complex(T).new(r.im, -r.re);
12}
13
14const epsilon = 0.0001;
15
16test "complex.casinh" {
17 const a = Complex(f32).new(5, 3);
18 const c = asinh(a);
19
20 debug.assert(math.approxEq(f32, c.re, 2.459831, epsilon));
21 debug.assert(math.approxEq(f32, c.im, 0.533999, epsilon));
22}
std/math/complex/atan.zig created+130
......@@ -0,0 +1,130 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn atan(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 return switch (T) {
10 f32 => atan32(z),
11 f64 => atan64(z),
12 else => @compileError("atan not implemented for " ++ @typeName(z)),
13 };
14}
15
16fn redupif32(x: f32) f32 {
17 const DP1 = 3.140625;
18 const DP2 = 9.67502593994140625e-4;
19 const DP3 = 1.509957990978376432e-7;
20
21 var t = x / math.pi;
22 if (t >= 0.0) {
23 t += 0.5;
24 } else {
25 t -= 0.5;
26 }
27
28 const u = f32(i32(t));
29 return ((x - u * DP1) - u * DP2) - t * DP3;
30}
31
32fn atan32(z: &const Complex(f32)) Complex(f32) {
33 const maxnum = 1.0e38;
34
35 const x = z.re;
36 const y = z.im;
37
38 if ((x == 0.0) and (y > 1.0)) {
39 // overflow
40 return Complex(f32).new(maxnum, maxnum);
41 }
42
43 const x2 = x * x;
44 var a = 1.0 - x2 - (y * y);
45 if (a == 0.0) {
46 // overflow
47 return Complex(f32).new(maxnum, maxnum);
48 }
49
50 var t = 0.5 * math.atan2(f32, 2.0 * x, a);
51 var w = redupif32(t);
52
53 t = y - 1.0;
54 a = x2 + t * t;
55 if (a == 0.0) {
56 // overflow
57 return Complex(f32).new(maxnum, maxnum);
58 }
59
60 t = y + 1.0;
61 a = (x2 + (t * t)) / a;
62 return Complex(f32).new(w, 0.25 * math.ln(a));
63}
64
65fn redupif64(x: f64) f64 {
66 const DP1 = 3.14159265160560607910;
67 const DP2 = 1.98418714791870343106e-9;
68 const DP3 = 1.14423774522196636802e-17;
69
70 var t = x / math.pi;
71 if (t >= 0.0) {
72 t += 0.5;
73 } else {
74 t -= 0.5;
75 }
76
77 const u = f64(i64(t));
78 return ((x - u * DP1) - u * DP2) - t * DP3;
79}
80
81fn atan64(z: &const Complex(f64)) Complex(f64) {
82 const maxnum = 1.0e308;
83
84 const x = z.re;
85 const y = z.im;
86
87 if ((x == 0.0) and (y > 1.0)) {
88 // overflow
89 return Complex(f64).new(maxnum, maxnum);
90 }
91
92 const x2 = x * x;
93 var a = 1.0 - x2 - (y * y);
94 if (a == 0.0) {
95 // overflow
96 return Complex(f64).new(maxnum, maxnum);
97 }
98
99 var t = 0.5 * math.atan2(f64, 2.0 * x, a);
100 var w = redupif64(t);
101
102 t = y - 1.0;
103 a = x2 + t * t;
104 if (a == 0.0) {
105 // overflow
106 return Complex(f64).new(maxnum, maxnum);
107 }
108
109 t = y + 1.0;
110 a = (x2 + (t * t)) / a;
111 return Complex(f64).new(w, 0.25 * math.ln(a));
112}
113
114const epsilon = 0.0001;
115
116test "complex.catan32" {
117 const a = Complex(f32).new(5, 3);
118 const c = atan(a);
119
120 debug.assert(math.approxEq(f32, c.re, 1.423679, epsilon));
121 debug.assert(math.approxEq(f32, c.im, 0.086569, epsilon));
122}
123
124test "complex.catan64" {
125 const a = Complex(f64).new(5, 3);
126 const c = atan(a);
127
128 debug.assert(math.approxEq(f64, c.re, 1.423679, epsilon));
129 debug.assert(math.approxEq(f64, c.im, 0.086569, epsilon));
130}
std/math/complex/atanh.zig created+22
......@@ -0,0 +1,22 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn atanh(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 const q = Complex(T).new(-z.im, z.re);
10 const r = cmath.atan(q);
11 return Complex(T).new(r.im, -r.re);
12}
13
14const epsilon = 0.0001;
15
16test "complex.catanh" {
17 const a = Complex(f32).new(5, 3);
18 const c = atanh(a);
19
20 debug.assert(math.approxEq(f32, c.re, 0.146947, epsilon));
21 debug.assert(math.approxEq(f32, c.im, 1.480870, epsilon));
22}
std/math/complex/conj.zig created+17
......@@ -0,0 +1,17 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn conj(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 return Complex(T).new(z.re, -z.im);
10}
11
12test "complex.conj" {
13 const a = Complex(f32).new(5, 3);
14 const c = a.conjugate();
15
16 debug.assert(c.re == 5 and c.im == -3);
17}
std/math/complex/cos.zig created+21
......@@ -0,0 +1,21 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn cos(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 const p = Complex(T).new(-z.im, z.re);
10 return cmath.cosh(p);
11}
12
13const epsilon = 0.0001;
14
15test "complex.ccos" {
16 const a = Complex(f32).new(5, 3);
17 const c = cos(a);
18
19 debug.assert(math.approxEq(f32, c.re, 2.855815, epsilon));
20 debug.assert(math.approxEq(f32, c.im, 9.606383, epsilon));
21}
std/math/complex/cosh.zig created+165
......@@ -0,0 +1,165 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7const ldexp_cexp = @import("ldexp.zig").ldexp_cexp;
8
9pub fn cosh(z: var) Complex(@typeOf(z.re)) {
10 const T = @typeOf(z.re);
11 return switch (T) {
12 f32 => cosh32(z),
13 f64 => cosh64(z),
14 else => @compileError("cosh not implemented for " ++ @typeName(z)),
15 };
16}
17
18fn cosh32(z: &const Complex(f32)) Complex(f32) {
19 const x = z.re;
20 const y = z.im;
21
22 const hx = @bitCast(u32, x);
23 const ix = hx & 0x7fffffff;
24
25 const hy = @bitCast(u32, y);
26 const iy = hy & 0x7fffffff;
27
28 if (ix < 0x7f800000 and iy < 0x7f800000) {
29 if (iy == 0) {
30 return Complex(f32).new(math.cosh(x), y);
31 }
32 // small x: normal case
33 if (ix < 0x41100000) {
34 return Complex(f32).new(math.cosh(x) * math.cos(y), math.sinh(x) * math.sin(y));
35 }
36
37 // |x|>= 9, so cosh(x) ~= exp(|x|)
38 if (ix < 0x42b17218) {
39 // x < 88.7: exp(|x|) won't overflow
40 const h = math.exp(math.fabs(x)) * 0.5;
41 return Complex(f32).new(math.copysign(f32, h, x) * math.cos(y), h * math.sin(y));
42 }
43 // x < 192.7: scale to avoid overflow
44 else if (ix < 0x4340b1e7) {
45 const v = Complex(f32).new(math.fabs(x), y);
46 const r = ldexp_cexp(v, -1);
47 return Complex(f32).new(x, y * math.copysign(f32, 1, x));
48 }
49 // x >= 192.7: result always overflows
50 else {
51 const h = 0x1p127 * x;
52 return Complex(f32).new(h * h * math.cos(y), h * math.sin(y));
53 }
54 }
55
56 if (ix == 0 and iy >= 0x7f800000) {
57 return Complex(f32).new(y - y, math.copysign(f32, 0, x * (y - y)));
58 }
59
60 if (iy == 0 and ix >= 0x7f800000) {
61 if (hx & 0x7fffff == 0) {
62 return Complex(f32).new(x * x, math.copysign(f32, 0, x) * y);
63 }
64 return Complex(f32).new(x, math.copysign(f32, 0, (x + x) * y));
65 }
66
67 if (ix < 0x7f800000 and iy >= 0x7f800000) {
68 return Complex(f32).new(y - y, x * (y - y));
69 }
70
71 if (ix >= 0x7f800000 and (hx & 0x7fffff) == 0) {
72 if (iy >= 0x7f800000) {
73 return Complex(f32).new(x * x, x * (y - y));
74 }
75 return Complex(f32).new((x * x) * math.cos(y), x * math.sin(y));
76 }
77
78 return Complex(f32).new((x * x) * (y - y), (x + x) * (y - y));
79}
80
81fn cosh64(z: &const Complex(f64)) Complex(f64) {
82 const x = z.re;
83 const y = z.im;
84
85 const fx = @bitCast(u64, x);
86 const hx = u32(fx >> 32);
87 const lx = @truncate(u32, fx);
88 const ix = hx & 0x7fffffff;
89
90 const fy = @bitCast(u64, y);
91 const hy = u32(fy >> 32);
92 const ly = @truncate(u32, fy);
93 const iy = hy & 0x7fffffff;
94
95 // nearly non-exceptional case where x, y are finite
96 if (ix < 0x7ff00000 and iy < 0x7ff00000) {
97 if (iy | ly == 0) {
98 return Complex(f64).new(math.cosh(x), x * y);
99 }
100 // small x: normal case
101 if (ix < 0x40360000) {
102 return Complex(f64).new(math.cosh(x) * math.cos(y), math.sinh(x) * math.sin(y));
103 }
104
105 // |x|>= 22, so cosh(x) ~= exp(|x|)
106 if (ix < 0x40862e42) {
107 // x < 710: exp(|x|) won't overflow
108 const h = math.exp(math.fabs(x)) * 0.5;
109 return Complex(f64).new(h * math.cos(y), math.copysign(f64, h, x) * math.sin(y));
110 }
111 // x < 1455: scale to avoid overflow
112 else if (ix < 0x4096bbaa) {
113 const v = Complex(f64).new(math.fabs(x), y);
114 const r = ldexp_cexp(v, -1);
115 return Complex(f64).new(x, y * math.copysign(f64, 1, x));
116 }
117 // x >= 1455: result always overflows
118 else {
119 const h = 0x1p1023;
120 return Complex(f64).new(h * h * math.cos(y), h * math.sin(y));
121 }
122 }
123
124 if (ix | lx == 0 and iy >= 0x7ff00000) {
125 return Complex(f64).new(y - y, math.copysign(f64, 0, x * (y - y)));
126 }
127
128 if (iy | ly == 0 and ix >= 0x7ff00000) {
129 if ((hx & 0xfffff) | lx == 0) {
130 return Complex(f64).new(x * x, math.copysign(f64, 0, x) * y);
131 }
132 return Complex(f64).new(x * x, math.copysign(f64, 0, (x + x) * y));
133 }
134
135 if (ix < 0x7ff00000 and iy >= 0x7ff00000) {
136 return Complex(f64).new(y - y, x * (y - y));
137 }
138
139 if (ix >= 0x7ff00000 and (hx & 0xfffff) | lx == 0) {
140 if (iy >= 0x7ff00000) {
141 return Complex(f64).new(x * x, x * (y - y));
142 }
143 return Complex(f64).new(x * x * math.cos(y), x * math.sin(y));
144 }
145
146 return Complex(f64).new((x * x) * (y - y), (x + x) * (y - y));
147}
148
149const epsilon = 0.0001;
150
151test "complex.ccosh32" {
152 const a = Complex(f32).new(5, 3);
153 const c = cosh(a);
154
155 debug.assert(math.approxEq(f32, c.re, -73.467300, epsilon));
156 debug.assert(math.approxEq(f32, c.im, 10.471557, epsilon));
157}
158
159test "complex.ccosh64" {
160 const a = Complex(f64).new(5, 3);
161 const c = cosh(a);
162
163 debug.assert(math.approxEq(f64, c.re, -73.467300, epsilon));
164 debug.assert(math.approxEq(f64, c.im, 10.471557, epsilon));
165}
std/math/complex/exp.zig created+140
......@@ -0,0 +1,140 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7const ldexp_cexp = @import("ldexp.zig").ldexp_cexp;
8
9pub fn exp(z: var) Complex(@typeOf(z.re)) {
10 const T = @typeOf(z.re);
11
12 return switch (T) {
13 f32 => exp32(z),
14 f64 => exp64(z),
15 else => @compileError("exp not implemented for " ++ @typeName(z)),
16 };
17}
18
19fn exp32(z: &const Complex(f32)) Complex(f32) {
20 @setFloatMode(this, @import("builtin").FloatMode.Strict);
21
22 const exp_overflow = 0x42b17218; // max_exp * ln2 ~= 88.72283955
23 const cexp_overflow = 0x43400074; // (max_exp - min_denom_exp) * ln2
24
25 const x = z.re;
26 const y = z.im;
27
28 const hy = @bitCast(u32, y) & 0x7fffffff;
29 // cexp(x + i0) = exp(x) + i0
30 if (hy == 0) {
31 return Complex(f32).new(math.exp(x), y);
32 }
33
34 const hx = @bitCast(u32, x);
35 // cexp(0 + iy) = cos(y) + isin(y)
36 if ((hx & 0x7fffffff) == 0) {
37 return Complex(f32).new(math.cos(y), math.sin(y));
38 }
39
40 if (hy >= 0x7f800000) {
41 // cexp(finite|nan +- i inf|nan) = nan + i nan
42 if ((hx & 0x7fffffff) != 0x7f800000) {
43 return Complex(f32).new(y - y, y - y);
44 }
45 // cexp(-inf +- i inf|nan) = 0 + i0
46 else if (hx & 0x80000000 != 0) {
47 return Complex(f32).new(0, 0);
48 }
49 // cexp(+inf +- i inf|nan) = inf + i nan
50 else {
51 return Complex(f32).new(x, y - y);
52 }
53 }
54
55 // 88.7 <= x <= 192 so must scale
56 if (hx >= exp_overflow and hx <= cexp_overflow) {
57 return ldexp_cexp(z, 0);
58 }
59 // - x < exp_overflow => exp(x) won't overflow (common)
60 // - x > cexp_overflow, so exp(x) * s overflows for s > 0
61 // - x = +-inf
62 // - x = nan
63 else {
64 const exp_x = math.exp(x);
65 return Complex(f32).new(exp_x * math.cos(y), exp_x * math.sin(y));
66 }
67}
68
69fn exp64(z: &const Complex(f64)) Complex(f64) {
70 const exp_overflow = 0x40862e42; // high bits of max_exp * ln2 ~= 710
71 const cexp_overflow = 0x4096b8e4; // (max_exp - min_denorm_exp) * ln2
72
73 const x = z.re;
74 const y = z.im;
75
76 const fy = @bitCast(u64, y);
77 const hy = u32(fy >> 32) & 0x7fffffff;
78 const ly = @truncate(u32, fy);
79
80 // cexp(x + i0) = exp(x) + i0
81 if (hy | ly == 0) {
82 return Complex(f64).new(math.exp(x), y);
83 }
84
85 const fx = @bitCast(u64, x);
86 const hx = u32(fx >> 32);
87 const lx = @truncate(u32, fx);
88
89 // cexp(0 + iy) = cos(y) + isin(y)
90 if ((hx & 0x7fffffff) | lx == 0) {
91 return Complex(f64).new(math.cos(y), math.sin(y));
92 }
93
94 if (hy >= 0x7ff00000) {
95 // cexp(finite|nan +- i inf|nan) = nan + i nan
96 if (lx != 0 or (hx & 0x7fffffff) != 0x7ff00000) {
97 return Complex(f64).new(y - y, y - y);
98 }
99 // cexp(-inf +- i inf|nan) = 0 + i0
100 else if (hx & 0x80000000 != 0) {
101 return Complex(f64).new(0, 0);
102 }
103 // cexp(+inf +- i inf|nan) = inf + i nan
104 else {
105 return Complex(f64).new(x, y - y);
106 }
107 }
108
109 // 709.7 <= x <= 1454.3 so must scale
110 if (hx >= exp_overflow and hx <= cexp_overflow) {
111 const r = ldexp_cexp(z, 0);
112 return *r;
113 }
114 // - x < exp_overflow => exp(x) won't overflow (common)
115 // - x > cexp_overflow, so exp(x) * s overflows for s > 0
116 // - x = +-inf
117 // - x = nan
118 else {
119 const exp_x = math.exp(x);
120 return Complex(f64).new(exp_x * math.cos(y), exp_x * math.sin(y));
121 }
122}
123
124const epsilon = 0.0001;
125
126test "complex.cexp32" {
127 const a = Complex(f32).new(5, 3);
128 const c = exp(a);
129
130 debug.assert(math.approxEq(f32, c.re, -146.927917, epsilon));
131 debug.assert(math.approxEq(f32, c.im, 20.944065, epsilon));
132}
133
134test "complex.cexp64" {
135 const a = Complex(f32).new(5, 3);
136 const c = exp(a);
137
138 debug.assert(math.approxEq(f64, c.re, -146.927917, epsilon));
139 debug.assert(math.approxEq(f64, c.im, 20.944065, epsilon));
140}
std/math/complex/index.zig created+171
......@@ -0,0 +1,171 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4
5pub const abs = @import("abs.zig").abs;
6pub const acosh = @import("acosh.zig").acosh;
7pub const acos = @import("acos.zig").acos;
8pub const arg = @import("arg.zig").arg;
9pub const asinh = @import("asinh.zig").asinh;
10pub const asin = @import("asin.zig").asin;
11pub const atanh = @import("atanh.zig").atanh;
12pub const atan = @import("atan.zig").atan;
13pub const conj = @import("conj.zig").conj;
14pub const cosh = @import("cosh.zig").cosh;
15pub const cos = @import("cos.zig").cos;
16pub const exp = @import("exp.zig").exp;
17pub const log = @import("log.zig").log;
18pub const pow = @import("pow.zig").pow;
19pub const proj = @import("proj.zig").proj;
20pub const sinh = @import("sinh.zig").sinh;
21pub const sin = @import("sin.zig").sin;
22pub const sqrt = @import("sqrt.zig").sqrt;
23pub const tanh = @import("tanh.zig").tanh;
24pub const tan = @import("tan.zig").tan;
25
26pub fn Complex(comptime T: type) type {
27 return struct {
28 const Self = this;
29
30 re: T,
31 im: T,
32
33 pub fn new(re: T, im: T) Self {
34 return Self {
35 .re = re,
36 .im = im,
37 };
38 }
39
40 pub fn add(self: &const Self, other: &const Self) Self {
41 return Self {
42 .re = self.re + other.re,
43 .im = self.im + other.im,
44 };
45 }
46
47 pub fn sub(self: &const Self, other: &const Self) Self {
48 return Self {
49 .re = self.re - other.re,
50 .im = self.im - other.im,
51 };
52 }
53
54 pub fn mul(self: &const Self, other: &const Self) Self {
55 return Self {
56 .re = self.re * other.re - self.im * other.im,
57 .im = self.im * other.re + self.re * other.im,
58 };
59 }
60
61 pub fn div(self: &const Self, other: &const Self) Self {
62 const re_num = self.re * other.re + self.im * other.im;
63 const im_num = self.im * other.re - self.re * other.im;
64 const den = other.re * other.re + other.im * other.im;
65
66 return Self {
67 .re = re_num / den,
68 .im = im_num / den,
69 };
70 }
71
72 pub fn conjugate(self: &const Self) Self {
73 return Self {
74 .re = self.re,
75 .im = -self.im,
76 };
77 }
78
79 pub fn reciprocal(self: &const Self) Self {
80 const m = self.re * self.re + self.im * self.im;
81 return Self {
82 .re = self.re / m,
83 .im = -self.im / m,
84 };
85 }
86
87 pub fn magnitude(self: &const Self) T {
88 return math.sqrt(self.re * self.re + self.im * self.im);
89 }
90 };
91}
92
93const epsilon = 0.0001;
94
95test "complex.add" {
96 const a = Complex(f32).new(5, 3);
97 const b = Complex(f32).new(2, 7);
98 const c = a.add(b);
99
100 debug.assert(c.re == 7 and c.im == 10);
101}
102
103test "complex.sub" {
104 const a = Complex(f32).new(5, 3);
105 const b = Complex(f32).new(2, 7);
106 const c = a.sub(b);
107
108 debug.assert(c.re == 3 and c.im == -4);
109}
110
111test "complex.mul" {
112 const a = Complex(f32).new(5, 3);
113 const b = Complex(f32).new(2, 7);
114 const c = a.mul(b);
115
116 debug.assert(c.re == -11 and c.im == 41);
117}
118
119test "complex.div" {
120 const a = Complex(f32).new(5, 3);
121 const b = Complex(f32).new(2, 7);
122 const c = a.div(b);
123
124 debug.assert(math.approxEq(f32, c.re, f32(31)/53, epsilon) and
125 math.approxEq(f32, c.im, f32(-29)/53, epsilon));
126}
127
128test "complex.conjugate" {
129 const a = Complex(f32).new(5, 3);
130 const c = a.conjugate();
131
132 debug.assert(c.re == 5 and c.im == -3);
133}
134
135test "complex.reciprocal" {
136 const a = Complex(f32).new(5, 3);
137 const c = a.reciprocal();
138
139 debug.assert(math.approxEq(f32, c.re, f32(5)/34, epsilon) and
140 math.approxEq(f32, c.im, f32(-3)/34, epsilon));
141}
142
143test "complex.magnitude" {
144 const a = Complex(f32).new(5, 3);
145 const c = a.magnitude();
146
147 debug.assert(math.approxEq(f32, c, 5.83095, epsilon));
148}
149
150test "complex.cmath" {
151 _ = @import("abs.zig");
152 _ = @import("acosh.zig");
153 _ = @import("acos.zig");
154 _ = @import("arg.zig");
155 _ = @import("asinh.zig");
156 _ = @import("asin.zig");
157 _ = @import("atanh.zig");
158 _ = @import("atan.zig");
159 _ = @import("conj.zig");
160 _ = @import("cosh.zig");
161 _ = @import("cos.zig");
162 _ = @import("exp.zig");
163 _ = @import("log.zig");
164 _ = @import("pow.zig");
165 _ = @import("proj.zig");
166 _ = @import("sinh.zig");
167 _ = @import("sin.zig");
168 _ = @import("sqrt.zig");
169 _ = @import("tanh.zig");
170 _ = @import("tan.zig");
171}
std/math/complex/ldexp.zig created+75
......@@ -0,0 +1,75 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn ldexp_cexp(z: var, expt: i32) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9
10 return switch (T) {
11 f32 => ldexp_cexp32(z, expt),
12 f64 => ldexp_cexp64(z, expt),
13 else => unreachable,
14 };
15}
16
17fn frexp_exp32(x: f32, expt: &i32) f32 {
18 const k = 235; // reduction constant
19 const kln2 = 162.88958740; // k * ln2
20
21 const exp_x = math.exp(x - kln2);
22 const hx = @bitCast(u32, exp_x);
23 *expt = i32(hx >> 23) - (0x7f + 127) + k;
24 return @bitCast(f32, (hx & 0x7fffff) | ((0x7f + 127) << 23));
25}
26
27fn ldexp_cexp32(z: &const Complex(f32), expt: i32) Complex(f32) {
28 var ex_expt: i32 = undefined;
29 const exp_x = frexp_exp32(z.re, &ex_expt);
30 const exptf = expt + ex_expt;
31
32 const half_expt1 = @divTrunc(exptf, 2);
33 const scale1 = @bitCast(f32, (0x7f + half_expt1) << 23);
34
35 const half_expt2 = exptf - half_expt1;
36 const scale2 = @bitCast(f32, (0x7f + half_expt2) << 23);
37
38 return Complex(f32).new(
39 math.cos(z.im) * exp_x * scale1 * scale2,
40 math.sin(z.im) * exp_x * scale1 * scale2,
41 );
42}
43
44fn frexp_exp64(x: f64, expt: &i32) f64 {
45 const k = 1799; // reduction constant
46 const kln2 = 1246.97177782734161156; // k * ln2
47
48 const exp_x = math.exp(x - kln2);
49
50 const fx = @bitCast(u64, x);
51 const hx = u32(fx >> 32);
52 const lx = @truncate(u32, fx);
53
54 *expt = i32(hx >> 20) - (0x3ff + 1023) + k;
55
56 const high_word = (hx & 0xfffff) | ((0x3ff + 1023) << 20);
57 return @bitCast(f64, (u64(high_word) << 32) | lx);
58}
59
60fn ldexp_cexp64(z: &const Complex(f64), expt: i32) Complex(f64) {
61 var ex_expt: i32 = undefined;
62 const exp_x = frexp_exp64(z.re, &ex_expt);
63 const exptf = i64(expt + ex_expt);
64
65 const half_expt1 = @divTrunc(exptf, 2);
66 const scale1 = @bitCast(f64, (0x3ff + half_expt1) << 20);
67
68 const half_expt2 = exptf - half_expt1;
69 const scale2 = @bitCast(f64, (0x3ff + half_expt2) << 20);
70
71 return Complex(f64).new(
72 math.cos(z.im) * exp_x * scale1 * scale2,
73 math.sin(z.im) * exp_x * scale1 * scale2,
74 );
75}
std/math/complex/log.zig created+23
......@@ -0,0 +1,23 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn log(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 const r = cmath.abs(z);
10 const phi = cmath.arg(z);
11
12 return Complex(T).new(math.ln(r), phi);
13}
14
15const epsilon = 0.0001;
16
17test "complex.clog" {
18 const a = Complex(f32).new(5, 3);
19 const c = log(a);
20
21 debug.assert(math.approxEq(f32, c.re, 1.763180, epsilon));
22 debug.assert(math.approxEq(f32, c.im, 0.540419, epsilon));
23}
std/math/complex/pow.zig created+22
......@@ -0,0 +1,22 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn pow(comptime T: type, z: &const T, c: &const T) T {
8 const p = cmath.log(z);
9 const q = c.mul(p);
10 return cmath.exp(q);
11}
12
13const epsilon = 0.0001;
14
15test "complex.cpow" {
16 const a = Complex(f32).new(5, 3);
17 const b = Complex(f32).new(2.3, -1.3);
18 const c = pow(Complex(f32), a, b);
19
20 debug.assert(math.approxEq(f32, c.re, 58.049110, epsilon));
21 debug.assert(math.approxEq(f32, c.im, -101.003433, epsilon));
22}
std/math/complex/proj.zig created+24
......@@ -0,0 +1,24 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn proj(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9
10 if (math.isInf(z.re) or math.isInf(z.im)) {
11 return Complex(T).new(math.inf(T), math.copysign(T, 0, z.re));
12 }
13
14 return Complex(T).new(z.re, z.im);
15}
16
17const epsilon = 0.0001;
18
19test "complex.cproj" {
20 const a = Complex(f32).new(5, 3);
21 const c = proj(a);
22
23 debug.assert(c.re == 5 and c.im == 3);
24}
std/math/complex/sin.zig created+22
......@@ -0,0 +1,22 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn sin(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 const p = Complex(T).new(-z.im, z.re);
10 const q = cmath.sinh(p);
11 return Complex(T).new(q.im, -q.re);
12}
13
14const epsilon = 0.0001;
15
16test "complex.csin" {
17 const a = Complex(f32).new(5, 3);
18 const c = sin(a);
19
20 debug.assert(math.approxEq(f32, c.re, -9.654126, epsilon));
21 debug.assert(math.approxEq(f32, c.im, 2.841692, epsilon));
22}
std/math/complex/sinh.zig created+164
......@@ -0,0 +1,164 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7const ldexp_cexp = @import("ldexp.zig").ldexp_cexp;
8
9pub fn sinh(z: var) Complex(@typeOf(z.re)) {
10 const T = @typeOf(z.re);
11 return switch (T) {
12 f32 => sinh32(z),
13 f64 => sinh64(z),
14 else => @compileError("tan not implemented for " ++ @typeName(z)),
15 };
16}
17
18fn sinh32(z: &const Complex(f32)) Complex(f32) {
19 const x = z.re;
20 const y = z.im;
21
22 const hx = @bitCast(u32, x);
23 const ix = hx & 0x7fffffff;
24
25 const hy = @bitCast(u32, y);
26 const iy = hy & 0x7fffffff;
27
28 if (ix < 0x7f800000 and iy < 0x7f800000) {
29 if (iy == 0) {
30 return Complex(f32).new(math.sinh(x), y);
31 }
32 // small x: normal case
33 if (ix < 0x41100000) {
34 return Complex(f32).new(math.sinh(x) * math.cos(y), math.cosh(x) * math.sin(y));
35 }
36
37 // |x|>= 9, so cosh(x) ~= exp(|x|)
38 if (ix < 0x42b17218) {
39 // x < 88.7: exp(|x|) won't overflow
40 const h = math.exp(math.fabs(x)) * 0.5;
41 return Complex(f32).new(math.copysign(f32, h, x) * math.cos(y), h * math.sin(y));
42 }
43 // x < 192.7: scale to avoid overflow
44 else if (ix < 0x4340b1e7) {
45 const v = Complex(f32).new(math.fabs(x), y);
46 const r = ldexp_cexp(v, -1);
47 return Complex(f32).new(x * math.copysign(f32, 1, x), y);
48 }
49 // x >= 192.7: result always overflows
50 else {
51 const h = 0x1p127 * x;
52 return Complex(f32).new(h * math.cos(y), h * h * math.sin(y));
53 }
54 }
55
56 if (ix == 0 and iy >= 0x7f800000) {
57 return Complex(f32).new(math.copysign(f32, 0, x * (y - y)), y - y);
58 }
59
60 if (iy == 0 and ix >= 0x7f800000) {
61 if (hx & 0x7fffff == 0) {
62 return Complex(f32).new(x, y);
63 }
64 return Complex(f32).new(x, math.copysign(f32, 0, y));
65 }
66
67 if (ix < 0x7f800000 and iy >= 0x7f800000) {
68 return Complex(f32).new(y - y, x * (y - y));
69 }
70
71 if (ix >= 0x7f800000 and (hx & 0x7fffff) == 0) {
72 if (iy >= 0x7f800000) {
73 return Complex(f32).new(x * x, x * (y - y));
74 }
75 return Complex(f32).new(x * math.cos(y), math.inf_f32 * math.sin(y));
76 }
77
78 return Complex(f32).new((x * x) * (y - y), (x + x) * (y - y));
79}
80
81fn sinh64(z: &const Complex(f64)) Complex(f64) {
82 const x = z.re;
83 const y = z.im;
84
85 const fx = @bitCast(u64, x);
86 const hx = u32(fx >> 32);
87 const lx = @truncate(u32, fx);
88 const ix = hx & 0x7fffffff;
89
90 const fy = @bitCast(u64, y);
91 const hy = u32(fy >> 32);
92 const ly = @truncate(u32, fy);
93 const iy = hy & 0x7fffffff;
94
95 if (ix < 0x7ff00000 and iy < 0x7ff00000) {
96 if (iy | ly == 0) {
97 return Complex(f64).new(math.sinh(x), y);
98 }
99 // small x: normal case
100 if (ix < 0x40360000) {
101 return Complex(f64).new(math.sinh(x) * math.cos(y), math.cosh(x) * math.sin(y));
102 }
103
104 // |x|>= 22, so cosh(x) ~= exp(|x|)
105 if (ix < 0x40862e42) {
106 // x < 710: exp(|x|) won't overflow
107 const h = math.exp(math.fabs(x)) * 0.5;
108 return Complex(f64).new(math.copysign(f64, h, x) * math.cos(y), h * math.sin(y));
109 }
110 // x < 1455: scale to avoid overflow
111 else if (ix < 0x4096bbaa) {
112 const v = Complex(f64).new(math.fabs(x), y);
113 const r = ldexp_cexp(v, -1);
114 return Complex(f64).new(x * math.copysign(f64, 1, x), y);
115 }
116 // x >= 1455: result always overflows
117 else {
118 const h = 0x1p1023 * x;
119 return Complex(f64).new(h * math.cos(y), h * h * math.sin(y));
120 }
121 }
122
123 if (ix | lx == 0 and iy >= 0x7ff00000) {
124 return Complex(f64).new(math.copysign(f64, 0, x * (y - y)), y - y);
125 }
126
127 if (iy | ly == 0 and ix >= 0x7ff00000) {
128 if ((hx & 0xfffff) | lx == 0) {
129 return Complex(f64).new(x, y);
130 }
131 return Complex(f64).new(x, math.copysign(f64, 0, y));
132 }
133
134 if (ix < 0x7ff00000 and iy >= 0x7ff00000) {
135 return Complex(f64).new(y - y, x * (y - y));
136 }
137
138 if (ix >= 0x7ff00000 and (hx & 0xfffff) | lx == 0) {
139 if (iy >= 0x7ff00000) {
140 return Complex(f64).new(x * x, x * (y - y));
141 }
142 return Complex(f64).new(x * math.cos(y), math.inf_f64 * math.sin(y));
143 }
144
145 return Complex(f64).new((x * x) * (y - y), (x + x) * (y - y));
146}
147
148const epsilon = 0.0001;
149
150test "complex.csinh32" {
151 const a = Complex(f32).new(5, 3);
152 const c = sinh(a);
153
154 debug.assert(math.approxEq(f32, c.re, -73.460617, epsilon));
155 debug.assert(math.approxEq(f32, c.im, 10.472508, epsilon));
156}
157
158test "complex.csinh64" {
159 const a = Complex(f64).new(5, 3);
160 const c = sinh(a);
161
162 debug.assert(math.approxEq(f64, c.re, -73.460617, epsilon));
163 debug.assert(math.approxEq(f64, c.im, 10.472508, epsilon));
164}
std/math/complex/sqrt.zig created+133
......@@ -0,0 +1,133 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7// TODO when #733 is solved this can be @typeOf(z) instead of Complex(@typeOf(z.re))
8pub fn sqrt(z: var) Complex(@typeOf(z.re)) {
9 const T = @typeOf(z.re);
10
11 return switch (T) {
12 f32 => sqrt32(z),
13 f64 => sqrt64(z),
14 else => @compileError("sqrt not implemented for " ++ @typeName(z)),
15 };
16}
17
18fn sqrt32(z: &const Complex(f32)) Complex(f32) {
19 const x = z.re;
20 const y = z.im;
21
22 if (x == 0 and y == 0) {
23 return Complex(f32).new(0, y);
24 }
25 if (math.isInf(y)) {
26 return Complex(f32).new(math.inf(f32), y);
27 }
28 if (math.isNan(x)) {
29 // raise invalid if y is not nan
30 const t = (y - y) / (y - y);
31 return Complex(f32).new(x, t);
32 }
33 if (math.isInf(x)) {
34 // sqrt(inf + i nan) = inf + nan i
35 // sqrt(inf + iy) = inf + i0
36 // sqrt(-inf + i nan) = nan +- inf i
37 // sqrt(-inf + iy) = 0 + inf i
38 if (math.signbit(x)) {
39 return Complex(f32).new(math.fabs(x - y), math.copysign(f32, x, y));
40 } else {
41 return Complex(f32).new(x, math.copysign(f32, y - y, y));
42 }
43 }
44
45 // y = nan special case is handled fine below
46
47 // double-precision avoids overflow with correct rounding.
48 const dx = f64(x);
49 const dy = f64(y);
50
51 if (dx >= 0) {
52 const t = math.sqrt((dx + math.hypot(f64, dx, dy)) * 0.5);
53 return Complex(f32).new(f32(t), f32(dy / (2.0 * t)));
54 } else {
55 const t = math.sqrt((-dx + math.hypot(f64, dx, dy)) * 0.5);
56 return Complex(f32).new(f32(math.fabs(y) / (2.0 * t)), f32(math.copysign(f64, t, y)));
57 }
58}
59
60fn sqrt64(z: &const Complex(f64)) Complex(f64) {
61 // may encounter overflow for im,re >= DBL_MAX / (1 + sqrt(2))
62 const threshold = 0x1.a827999fcef32p+1022;
63
64 var x = z.re;
65 var y = z.im;
66
67 if (x == 0 and y == 0) {
68 return Complex(f64).new(0, y);
69 }
70 if (math.isInf(y)) {
71 return Complex(f64).new(math.inf(f64), y);
72 }
73 if (math.isNan(x)) {
74 // raise invalid if y is not nan
75 const t = (y - y) / (y - y);
76 return Complex(f64).new(x, t);
77 }
78 if (math.isInf(x)) {
79 // sqrt(inf + i nan) = inf + nan i
80 // sqrt(inf + iy) = inf + i0
81 // sqrt(-inf + i nan) = nan +- inf i
82 // sqrt(-inf + iy) = 0 + inf i
83 if (math.signbit(x)) {
84 return Complex(f64).new(math.fabs(x - y), math.copysign(f64, x, y));
85 } else {
86 return Complex(f64).new(x, math.copysign(f64, y - y, y));
87 }
88 }
89
90 // y = nan special case is handled fine below
91
92 // scale to avoid overflow
93 var scale = false;
94 if (math.fabs(x) >= threshold or math.fabs(y) >= threshold) {
95 x *= 0.25;
96 y *= 0.25;
97 scale = true;
98 }
99
100 var result: Complex(f64) = undefined;
101 if (x >= 0) {
102 const t = math.sqrt((x + math.hypot(f64, x, y)) * 0.5);
103 result = Complex(f64).new(t, y / (2.0 * t));
104 } else {
105 const t = math.sqrt((-x + math.hypot(f64, x, y)) * 0.5);
106 result = Complex(f64).new(math.fabs(y) / (2.0 * t), math.copysign(f64, t, y));
107 }
108
109 if (scale) {
110 result.re *= 2;
111 result.im *= 2;
112 }
113
114 return result;
115}
116
117const epsilon = 0.0001;
118
119test "complex.csqrt32" {
120 const a = Complex(f32).new(5, 3);
121 const c = sqrt(a);
122
123 debug.assert(math.approxEq(f32, c.re, 2.327117, epsilon));
124 debug.assert(math.approxEq(f32, c.im, 0.644574, epsilon));
125}
126
127test "complex.csqrt64" {
128 const a = Complex(f64).new(5, 3);
129 const c = sqrt(a);
130
131 debug.assert(math.approxEq(f64, c.re, 2.3271175190399496, epsilon));
132 debug.assert(math.approxEq(f64, c.im, 0.6445742373246469, epsilon));
133}
std/math/complex/tan.zig created+22
......@@ -0,0 +1,22 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn tan(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 const q = Complex(T).new(-z.im, z.re);
10 const r = cmath.tanh(q);
11 return Complex(T).new(r.im, -r.re);
12}
13
14const epsilon = 0.0001;
15
16test "complex.ctan" {
17 const a = Complex(f32).new(5, 3);
18 const c = tan(a);
19
20 debug.assert(math.approxEq(f32, c.re, -0.002708233, epsilon));
21 debug.assert(math.approxEq(f32, c.im, 1.004165, epsilon));
22}
std/math/complex/tanh.zig created+111
......@@ -0,0 +1,111 @@
1const std = @import("../../index.zig");
2const debug = std.debug;
3const math = std.math;
4const cmath = math.complex;
5const Complex = cmath.Complex;
6
7pub fn tanh(z: var) Complex(@typeOf(z.re)) {
8 const T = @typeOf(z.re);
9 return switch (T) {
10 f32 => tanh32(z),
11 f64 => tanh64(z),
12 else => @compileError("tan not implemented for " ++ @typeName(z)),
13 };
14}
15
16fn tanh32(z: &const Complex(f32)) Complex(f32) {
17 const x = z.re;
18 const y = z.im;
19
20 const hx = @bitCast(u32, x);
21 const ix = hx & 0x7fffffff;
22
23 if (ix >= 0x7f800000) {
24 if (ix & 0x7fffff != 0) {
25 const r = if (y == 0) y else x * y;
26 return Complex(f32).new(x, r);
27 }
28 const xx = @bitCast(f32, hx - 0x40000000);
29 const r = if (math.isInf(y)) y else math.sin(y) * math.cos(y);
30 return Complex(f32).new(xx, math.copysign(f32, 0, r));
31 }
32
33 if (!math.isFinite(y)) {
34 const r = if (ix != 0) y - y else x;
35 return Complex(f32).new(r, y - y);
36 }
37
38 // x >= 11
39 if (ix >= 0x41300000) {
40 const exp_mx = math.exp(-math.fabs(x));
41 return Complex(f32).new(math.copysign(f32, 1, x), 4 * math.sin(y) * math.cos(y) * exp_mx * exp_mx);
42 }
43
44 // Kahan's algorithm
45 const t = math.tan(y);
46 const beta = 1.0 + t * t;
47 const s = math.sinh(x);
48 const rho = math.sqrt(1 + s * s);
49 const den = 1 + beta * s * s;
50
51 return Complex(f32).new((beta * rho * s) / den, t / den);
52}
53
54fn tanh64(z: &const Complex(f64)) Complex(f64) {
55 const x = z.re;
56 const y = z.im;
57
58 const fx = @bitCast(u64, x);
59 const hx = u32(fx >> 32);
60 const lx = @truncate(u32, fx);
61 const ix = hx & 0x7fffffff;
62
63 if (ix >= 0x7ff00000) {
64 if ((ix & 0x7fffff) | lx != 0) {
65 const r = if (y == 0) y else x * y;
66 return Complex(f64).new(x, r);
67 }
68
69 const xx = @bitCast(f64, (u64(hx - 0x40000000) << 32) | lx);
70 const r = if (math.isInf(y)) y else math.sin(y) * math.cos(y);
71 return Complex(f64).new(xx, math.copysign(f64, 0, r));
72 }
73
74 if (!math.isFinite(y)) {
75 const r = if (ix != 0) y - y else x;
76 return Complex(f64).new(r, y - y);
77 }
78
79 // x >= 22
80 if (ix >= 0x40360000) {
81 const exp_mx = math.exp(-math.fabs(x));
82 return Complex(f64).new(math.copysign(f64, 1, x), 4 * math.sin(y) * math.cos(y) * exp_mx * exp_mx);
83 }
84
85 // Kahan's algorithm
86 const t = math.tan(y);
87 const beta = 1.0 + t * t;
88 const s = math.sinh(x);
89 const rho = math.sqrt(1 + s * s);
90 const den = 1 + beta * s * s;
91
92 return Complex(f64).new((beta * rho * s) / den, t / den);
93}
94
95const epsilon = 0.0001;
96
97test "complex.ctanh32" {
98 const a = Complex(f32).new(5, 3);
99 const c = tanh(a);
100
101 debug.assert(math.approxEq(f32, c.re, 0.999913, epsilon));
102 debug.assert(math.approxEq(f32, c.im, -0.000025, epsilon));
103}
104
105test "complex.ctanh64" {
106 const a = Complex(f64).new(5, 3);
107 const c = tanh(a);
108
109 debug.assert(math.approxEq(f64, c.re, 0.999913, epsilon));
110 debug.assert(math.approxEq(f64, c.im, -0.000025, epsilon));
111}
std/math/exp.zig+5
......@@ -6,6 +6,7 @@
66const std = @import("../index.zig");
77const math = std.math;
88const assert = std.debug.assert;
9const builtin = @import("builtin");
910
1011pub fn exp(x: var) @typeOf(x) {
1112 const T = @typeOf(x);
......@@ -17,6 +18,8 @@ pub fn exp(x: var) @typeOf(x) {
1718}
1819
1920fn exp32(x_: f32) f32 {
21 @setFloatMode(this, builtin.FloatMode.Strict);
22
2023 const half = []f32 { 0.5, -0.5 };
2124 const ln2hi = 6.9314575195e-1;
2225 const ln2lo = 1.4286067653e-6;
......@@ -94,6 +97,8 @@ fn exp32(x_: f32) f32 {
9497}
9598
9699fn exp64(x_: f64) f64 {
100 @setFloatMode(this, builtin.FloatMode.Strict);
101
97102 const half = []const f64 { 0.5, -0.5 };
98103 const ln2hi: f64 = 6.93147180369123816490e-01;
99104 const ln2lo: f64 = 1.90821492927058770002e-10;
std/math/index.zig+5
......@@ -129,6 +129,9 @@ pub const cos = @import("cos.zig").cos;
129129pub const sin = @import("sin.zig").sin;
130130pub const tan = @import("tan.zig").tan;
131131
132pub const complex = @import("complex/index.zig");
133pub const Complex = complex.Complex;
134
132135test "math" {
133136 _ = @import("nan.zig");
134137 _ = @import("isnan.zig");
......@@ -172,6 +175,8 @@ test "math" {
172175 _ = @import("sin.zig");
173176 _ = @import("cos.zig");
174177 _ = @import("tan.zig");
178
179 _ = @import("complex/index.zig");
175180}
176181
177182
std/math/ln.zig+2
......@@ -89,6 +89,8 @@ pub fn ln_32(x_: f32) f32 {
8989}
9090
9191pub fn ln_64(x_: f64) f64 {
92 @setFloatMode(this, @import("builtin").FloatMode.Strict);
93
9294 const ln2_hi: f64 = 6.93147180369123816490e-01;
9395 const ln2_lo: f64 = 1.90821492927058770002e-10;
9496 const Lg1: f64 = 6.666666666666735130e-01;
std/math/sqrt.zig+33-262
......@@ -14,26 +14,8 @@ const TypeId = builtin.TypeId;
1414pub fn sqrt(x: var) (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @typeOf(x).bit_count / 2) else @typeOf(x)) {
1515 const T = @typeOf(x);
1616 switch (@typeId(T)) {
17 TypeId.FloatLiteral => {
18 return T(sqrt64(x));
19 },
20 TypeId.Float => {
21 switch (T) {
22 f32 => {
23 switch (builtin.arch) {
24 builtin.Arch.x86_64 => return @import("x86_64/sqrt.zig").sqrt32(x),
25 else => return sqrt32(x),
26 }
27 },
28 f64 => {
29 switch (builtin.arch) {
30 builtin.Arch.x86_64 => return @import("x86_64/sqrt.zig").sqrt64(x),
31 else => return sqrt64(x),
32 }
33 },
34 else => @compileError("sqrt not implemented for " ++ @typeName(T)),
35 }
36 },
17 TypeId.FloatLiteral => return T(@sqrt(f64, x)), // TODO upgrade to f128
18 TypeId.Float => return @sqrt(T, x),
3719 TypeId.IntLiteral => comptime {
3820 if (x > @maxValue(u128)) {
3921 @compileError("sqrt not implemented for comptime_int greater than 128 bits");
......@@ -43,269 +25,58 @@ pub fn sqrt(x: var) (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @typ
4325 }
4426 return T(sqrt_int(u128, x));
4527 },
46 TypeId.Int => {
47 return sqrt_int(T, x);
48 },
28 TypeId.Int => return sqrt_int(T, x),
4929 else => @compileError("sqrt not implemented for " ++ @typeName(T)),
5030 }
5131}
5232
53fn sqrt32(x: f32) f32 {
54 const tiny: f32 = 1.0e-30;
55 const sign: i32 = @bitCast(i32, u32(0x80000000));
56 var ix: i32 = @bitCast(i32, x);
57
58 if ((ix & 0x7F800000) == 0x7F800000) {
59 return x * x + x; // sqrt(nan) = nan, sqrt(+inf) = +inf, sqrt(-inf) = snan
60 }
61
62 // zero
63 if (ix <= 0) {
64 if (ix & ~sign == 0) {
65 return x; // sqrt (+-0) = +-0
66 }
67 if (ix < 0) {
68 return math.snan(f32);
69 }
70 }
71
72 // normalize
73 var m = ix >> 23;
74 if (m == 0) {
75 // subnormal
76 var i: i32 = 0;
77 while (ix & 0x00800000 == 0) : (i += 1) {
78 ix <<= 1;
79 }
80 m -= i - 1;
81 }
82
83 m -= 127; // unbias exponent
84 ix = (ix & 0x007FFFFF) | 0x00800000;
85
86 if (m & 1 != 0) { // odd m, double x to even
87 ix += ix;
88 }
89
90 m >>= 1; // m = [m / 2]
91
92 // sqrt(x) bit by bit
93 ix += ix;
94 var q: i32 = 0; // q = sqrt(x)
95 var s: i32 = 0;
96 var r: i32 = 0x01000000; // r = moving bit right -> left
97
98 while (r != 0) {
99 const t = s + r;
100 if (t <= ix) {
101 s = t + r;
102 ix -= t;
103 q += r;
104 }
105 ix += ix;
106 r >>= 1;
107 }
108
109 // floating add to find rounding direction
110 if (ix != 0) {
111 var z = 1.0 - tiny; // inexact
112 if (z >= 1.0) {
113 z = 1.0 + tiny;
114 if (z > 1.0) {
115 q += 2;
116 } else {
117 if (q & 1 != 0) {
118 q += 1;
119 }
120 }
121 }
122 }
123
124 ix = (q >> 1) + 0x3f000000;
125 ix += m << 23;
126 return @bitCast(f32, ix);
127}
128
129// NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound
130// behaviour. Most intermediate i32 values are changed to u32 where appropriate but there are
131// potentially some edge cases remaining that are not handled in the same way.
132fn sqrt64(x: f64) f64 {
133 const tiny: f64 = 1.0e-300;
134 const sign: u32 = 0x80000000;
135 const u = @bitCast(u64, x);
136
137 var ix0 = u32(u >> 32);
138 var ix1 = u32(u & 0xFFFFFFFF);
139
140 // sqrt(nan) = nan, sqrt(+inf) = +inf, sqrt(-inf) = nan
141 if (ix0 & 0x7FF00000 == 0x7FF00000) {
142 return x * x + x;
143 }
144
145 // sqrt(+-0) = +-0
146 if (x == 0.0) {
147 return x;
148 }
149 // sqrt(-ve) = snan
150 if (ix0 & sign != 0) {
151 return math.snan(f64);
152 }
153
154 // normalize x
155 var m = i32(ix0 >> 20);
156 if (m == 0) {
157 // subnormal
158 while (ix0 == 0) {
159 m -= 21;
160 ix0 |= ix1 >> 11;
161 ix1 <<= 21;
162 }
163
164 // subnormal
165 var i: u32 = 0;
166 while (ix0 & 0x00100000 == 0) : (i += 1) {
167 ix0 <<= 1;
168 }
169 m -= i32(i) - 1;
170 ix0 |= ix1 >> u5(32 - i);
171 ix1 <<= u5(i);
172 }
173
174 // unbias exponent
175 m -= 1023;
176 ix0 = (ix0 & 0x000FFFFF) | 0x00100000;
177 if (m & 1 != 0) {
178 ix0 += ix0 + (ix1 >> 31);
179 ix1 = ix1 +% ix1;
180 }
181 m >>= 1;
182
183 // sqrt(x) bit by bit
184 ix0 += ix0 + (ix1 >> 31);
185 ix1 = ix1 +% ix1;
186
187 var q: u32 = 0;
188 var q1: u32 = 0;
189 var s0: u32 = 0;
190 var s1: u32 = 0;
191 var r: u32 = 0x00200000;
192 var t: u32 = undefined;
193 var t1: u32 = undefined;
194
195 while (r != 0) {
196 t = s0 +% r;
197 if (t <= ix0) {
198 s0 = t + r;
199 ix0 -= t;
200 q += r;
201 }
202 ix0 = ix0 +% ix0 +% (ix1 >> 31);
203 ix1 = ix1 +% ix1;
204 r >>= 1;
205 }
206
207 r = sign;
208 while (r != 0) {
209 t = s1 +% r;
210 t = s0;
211 if (t < ix0 or (t == ix0 and t1 <= ix1)) {
212 s1 = t1 +% r;
213 if (t1 & sign == sign and s1 & sign == 0) {
214 s0 += 1;
215 }
216 ix0 -= t;
217 if (ix1 < t1) {
218 ix0 -= 1;
219 }
220 ix1 = ix1 -% t1;
221 q1 += r;
222 }
223 ix0 = ix0 +% ix0 +% (ix1 >> 31);
224 ix1 = ix1 +% ix1;
225 r >>= 1;
226 }
227
228 // rounding direction
229 if (ix0 | ix1 != 0) {
230 var z = 1.0 - tiny; // raise inexact
231 if (z >= 1.0) {
232 z = 1.0 + tiny;
233 if (q1 == 0xFFFFFFFF) {
234 q1 = 0;
235 q += 1;
236 } else if (z > 1.0) {
237 if (q1 == 0xFFFFFFFE) {
238 q += 1;
239 }
240 q1 += 2;
241 } else {
242 q1 += q1 & 1;
243 }
244 }
245 }
246
247 ix0 = (q >> 1) + 0x3FE00000;
248 ix1 = q1 >> 1;
249 if (q & 1 != 0) {
250 ix1 |= 0x80000000;
251 }
252
253 // NOTE: musl here appears to rely on signed twos-complement wraparound. +% has the same
254 // behaviour at least.
255 var iix0 = i32(ix0);
256 iix0 = iix0 +% (m << 20);
257
258 const uz = (u64(iix0) << 32) | ix1;
259 return @bitCast(f64, uz);
260}
261
26233test "math.sqrt" {
263 assert(sqrt(f32(0.0)) == sqrt32(0.0));
264 assert(sqrt(f64(0.0)) == sqrt64(0.0));
34 assert(sqrt(f32(0.0)) == @sqrt(f32, 0.0));
35 assert(sqrt(f64(0.0)) == @sqrt(f64, 0.0));
26536}
26637
26738test "math.sqrt32" {
26839 const epsilon = 0.000001;
26940
270 assert(sqrt32(0.0) == 0.0);
271 assert(math.approxEq(f32, sqrt32(2.0), 1.414214, epsilon));
272 assert(math.approxEq(f32, sqrt32(3.6), 1.897367, epsilon));
273 assert(sqrt32(4.0) == 2.0);
274 assert(math.approxEq(f32, sqrt32(7.539840), 2.745877, epsilon));
275 assert(math.approxEq(f32, sqrt32(19.230934), 4.385309, epsilon));
276 assert(sqrt32(64.0) == 8.0);
277 assert(math.approxEq(f32, sqrt32(64.1), 8.006248, epsilon));
278 assert(math.approxEq(f32, sqrt32(8942.230469), 94.563370, epsilon));
41 assert(@sqrt(f32, 0.0) == 0.0);
42 assert(math.approxEq(f32, @sqrt(f32, 2.0), 1.414214, epsilon));
43 assert(math.approxEq(f32, @sqrt(f32, 3.6), 1.897367, epsilon));
44 assert(@sqrt(f32, 4.0) == 2.0);
45 assert(math.approxEq(f32, @sqrt(f32, 7.539840), 2.745877, epsilon));
46 assert(math.approxEq(f32, @sqrt(f32, 19.230934), 4.385309, epsilon));
47 assert(@sqrt(f32, 64.0) == 8.0);
48 assert(math.approxEq(f32, @sqrt(f32, 64.1), 8.006248, epsilon));
49 assert(math.approxEq(f32, @sqrt(f32, 8942.230469), 94.563370, epsilon));
27950}
28051
28152test "math.sqrt64" {
28253 const epsilon = 0.000001;
28354
284 assert(sqrt64(0.0) == 0.0);
285 assert(math.approxEq(f64, sqrt64(2.0), 1.414214, epsilon));
286 assert(math.approxEq(f64, sqrt64(3.6), 1.897367, epsilon));
287 assert(sqrt64(4.0) == 2.0);
288 assert(math.approxEq(f64, sqrt64(7.539840), 2.745877, epsilon));
289 assert(math.approxEq(f64, sqrt64(19.230934), 4.385309, epsilon));
290 assert(sqrt64(64.0) == 8.0);
291 assert(math.approxEq(f64, sqrt64(64.1), 8.006248, epsilon));
292 assert(math.approxEq(f64, sqrt64(8942.230469), 94.563367, epsilon));
55 assert(@sqrt(f64, 0.0) == 0.0);
56 assert(math.approxEq(f64, @sqrt(f64, 2.0), 1.414214, epsilon));
57 assert(math.approxEq(f64, @sqrt(f64, 3.6), 1.897367, epsilon));
58 assert(@sqrt(f64, 4.0) == 2.0);
59 assert(math.approxEq(f64, @sqrt(f64, 7.539840), 2.745877, epsilon));
60 assert(math.approxEq(f64, @sqrt(f64, 19.230934), 4.385309, epsilon));
61 assert(@sqrt(f64, 64.0) == 8.0);
62 assert(math.approxEq(f64, @sqrt(f64, 64.1), 8.006248, epsilon));
63 assert(math.approxEq(f64, @sqrt(f64, 8942.230469), 94.563367, epsilon));
29364}
29465
29566test "math.sqrt32.special" {
296 assert(math.isPositiveInf(sqrt32(math.inf(f32))));
297 assert(sqrt32(0.0) == 0.0);
298 assert(sqrt32(-0.0) == -0.0);
299 assert(math.isNan(sqrt32(-1.0)));
300 assert(math.isNan(sqrt32(math.nan(f32))));
67 assert(math.isPositiveInf(@sqrt(f32, math.inf(f32))));
68 assert(@sqrt(f32, 0.0) == 0.0);
69 assert(@sqrt(f32, -0.0) == -0.0);
70 assert(math.isNan(@sqrt(f32, -1.0)));
71 assert(math.isNan(@sqrt(f32, math.nan(f32))));
30172}
30273
30374test "math.sqrt64.special" {
304 assert(math.isPositiveInf(sqrt64(math.inf(f64))));
305 assert(sqrt64(0.0) == 0.0);
306 assert(sqrt64(-0.0) == -0.0);
307 assert(math.isNan(sqrt64(-1.0)));
308 assert(math.isNan(sqrt64(math.nan(f64))));
75 assert(math.isPositiveInf(@sqrt(f64, math.inf(f64))));
76 assert(@sqrt(f64, 0.0) == 0.0);
77 assert(@sqrt(f64, -0.0) == -0.0);
78 assert(math.isNan(@sqrt(f64, -1.0)));
79 assert(math.isNan(@sqrt(f64, math.nan(f64))));
30980}
31081
31182fn sqrt_int(comptime T: type, value: T) @IntType(false, T.bit_count / 2) {
std/math/x86_64/sqrt.zig deleted-15
......@@ -1,15 +0,0 @@
1pub fn sqrt32(x: f32) f32 {
2 return asm (
3 \\sqrtss %%xmm0, %%xmm0
4 : [ret] "={xmm0}" (-> f32)
5 : [x] "{xmm0}" (x)
6 );
7}
8
9pub fn sqrt64(x: f64) f64 {
10 return asm (
11 \\sqrtsd %%xmm0, %%xmm0
12 : [ret] "={xmm0}" (-> f64)
13 : [x] "{xmm0}" (x)
14 );
15}
std/mem.zig+86-2
......@@ -11,6 +11,8 @@ pub const Allocator = struct {
1111 /// Allocate byte_count bytes and return them in a slice, with the
1212 /// slice's pointer aligned at least to alignment bytes.
1313 /// The returned newly allocated memory is undefined.
14 /// `alignment` is guaranteed to be >= 1
15 /// `alignment` is guaranteed to be a power of 2
1416 allocFn: fn (self: &Allocator, byte_count: usize, alignment: u29) Error![]u8,
1517
1618 /// If `new_byte_count > old_mem.len`:
......@@ -18,10 +20,12 @@ pub const Allocator = struct {
1820 /// * alignment >= alignment of old_mem.ptr
1921 ///
2022 /// If `new_byte_count <= old_mem.len`:
21 /// * this function must return successfully.
23 /// * this function must return successfully.
2224 /// * alignment <= alignment of old_mem.ptr
2325 ///
2426 /// The returned newly allocated memory is undefined.
27 /// `alignment` is guaranteed to be >= 1
28 /// `alignment` is guaranteed to be a power of 2
2529 reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) Error![]u8,
2630
2731 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
......@@ -170,6 +174,20 @@ pub fn dupe(allocator: &Allocator, comptime T: type, m: []const T) ![]T {
170174 return new_buf;
171175}
172176
177/// Remove values from the beginning of a slice.
178pub fn trimLeft(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
179 var begin: usize = 0;
180 while (begin < slice.len and indexOfScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {}
181 return slice[begin..];
182}
183
184/// Remove values from the end of a slice.
185pub fn trimRight(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
186 var end: usize = slice.len;
187 while (end > 0 and indexOfScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {}
188 return slice[0..end];
189}
190
173191/// Remove values from the beginning and end of a slice.
174192pub fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
175193 var begin: usize = 0;
......@@ -180,6 +198,8 @@ pub fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) []co
180198}
181199
182200test "mem.trim" {
201 assert(eql(u8, trimLeft(u8, " foo\n ", " \n"), "foo\n "));
202 assert(eql(u8, trimRight(u8, " foo\n ", " \n"), " foo"));
183203 assert(eql(u8, trim(u8, " foo\n ", " \n"), "foo"));
184204 assert(eql(u8, trim(u8, "foo", " \n"), "foo"));
185205}
......@@ -189,6 +209,17 @@ pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
189209 return indexOfScalarPos(T, slice, 0, value);
190210}
191211
212/// Linear search for the last index of a scalar value inside a slice.
213pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
214 var i: usize = slice.len;
215 while (i != 0) {
216 i -= 1;
217 if (slice[i] == value)
218 return i;
219 }
220 return null;
221}
222
192223pub fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {
193224 var i: usize = start_index;
194225 while (i < slice.len) : (i += 1) {
......@@ -202,6 +233,18 @@ pub fn indexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize
202233 return indexOfAnyPos(T, slice, 0, values);
203234}
204235
236pub fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize {
237 var i: usize = slice.len;
238 while (i != 0) {
239 i -= 1;
240 for (values) |value| {
241 if (slice[i] == value)
242 return i;
243 }
244 }
245 return null;
246}
247
205248pub fn indexOfAnyPos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize {
206249 var i: usize = start_index;
207250 while (i < slice.len) : (i += 1) {
......@@ -217,6 +260,22 @@ pub fn indexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize
217260 return indexOfPos(T, haystack, 0, needle);
218261}
219262
263/// Find the index in a slice of a sub-slice, searching from the end backwards.
264/// To start looking at a different index, slice the haystack first.
265/// TODO is there even a better algorithm for this?
266pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize {
267 if (needle.len > haystack.len)
268 return null;
269
270 var i: usize = haystack.len - needle.len;
271 while (true) : (i -= 1) {
272 if (mem.eql(T, haystack[i..i+needle.len], needle))
273 return i;
274 if (i == 0)
275 return null;
276 }
277}
278
220279// TODO boyer-moore algorithm
221280pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize {
222281 if (needle.len > haystack.len)
......@@ -233,9 +292,19 @@ pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, nee
233292
234293test "mem.indexOf" {
235294 assert(??indexOf(u8, "one two three four", "four") == 14);
295 assert(??lastIndexOf(u8, "one two three two four", "two") == 14);
236296 assert(indexOf(u8, "one two three four", "gour") == null);
297 assert(lastIndexOf(u8, "one two three four", "gour") == null);
237298 assert(??indexOf(u8, "foo", "foo") == 0);
299 assert(??lastIndexOf(u8, "foo", "foo") == 0);
238300 assert(indexOf(u8, "foo", "fool") == null);
301 assert(lastIndexOf(u8, "foo", "lfoo") == null);
302 assert(lastIndexOf(u8, "foo", "fool") == null);
303
304 assert(??indexOf(u8, "foo foo", "foo") == 0);
305 assert(??lastIndexOf(u8, "foo foo", "foo") == 4);
306 assert(??lastIndexOfAny(u8, "boo, cat", "abo") == 6);
307 assert(??lastIndexOfScalar(u8, "boo", 'o') == 2);
239308}
240309
241310/// Reads an integer from memory with size equal to bytes.len.
......@@ -355,9 +424,24 @@ pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool
355424 return if (needle.len > haystack.len) false else eql(T, haystack[0 .. needle.len], needle);
356425}
357426
427test "mem.startsWith" {
428 assert(startsWith(u8, "Bob", "Bo"));
429 assert(!startsWith(u8, "Needle in haystack", "haystack"));
430}
431
432pub fn endsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
433 return if (needle.len > haystack.len) false else eql(T, haystack[haystack.len - needle.len ..], needle);
434}
435
436
437test "mem.endsWith" {
438 assert(endsWith(u8, "Needle in haystack", "haystack"));
439 assert(!endsWith(u8, "Bob", "Bo"));
440}
441
358442pub const SplitIterator = struct {
359443 buffer: []const u8,
360 split_bytes: []const u8,
444 split_bytes: []const u8,
361445 index: usize,
362446
363447 pub fn next(self: &SplitIterator) ?[]const u8 {
std/os/darwin.zig+21
......@@ -41,6 +41,11 @@ pub const SA_64REGSET = 0x0200; /// signal handler with SA_SIGINFO args with 64
4141pub const O_LARGEFILE = 0x0000;
4242pub const O_PATH = 0x0000;
4343
44pub const F_OK = 0;
45pub const X_OK = 1;
46pub const W_OK = 2;
47pub const R_OK = 4;
48
4449pub const O_RDONLY = 0x0000; /// open for reading only
4550pub const O_WRONLY = 0x0001; /// open for writing only
4651pub const O_RDWR = 0x0002; /// open for reading and writing
......@@ -209,6 +214,10 @@ pub fn fork() usize {
209214 return errnoWrap(c.fork());
210215}
211216
217pub fn access(path: &const u8, mode: u32) usize {
218 return errnoWrap(c.access(path, mode));
219}
220
212221pub fn pipe(fds: &[2]i32) usize {
213222 comptime assert(i32.bit_count == c_int.bit_count);
214223 return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));
......@@ -251,6 +260,10 @@ pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) u
251260 return errnoWrap(c.readlink(path, buf_ptr, buf_len));
252261}
253262
263pub fn gettimeofday(tv: ?&timeval, tz: ?&timezone) usize {
264 return errnoWrap(c.gettimeofday(tv, tz));
265}
266
254267pub fn nanosleep(req: &const timespec, rem: ?&timespec) usize {
255268 return errnoWrap(c.nanosleep(req, rem));
256269}
......@@ -321,3 +334,11 @@ pub fn sigaddset(set: &sigset_t, signo: u5) void {
321334fn errnoWrap(value: isize) usize {
322335 return @bitCast(usize, if (value == -1) -isize(*c._errno()) else value);
323336}
337
338
339pub const timezone = c.timezone;
340pub const timeval = c.timeval;
341pub const mach_timebase_info_data = c.mach_timebase_info_data;
342
343pub const mach_absolute_time = c.mach_absolute_time;
344pub const mach_timebase_info = c.mach_timebase_info;
\ No newline at end of file
std/os/epoch.zig created+26
......@@ -0,0 +1,26 @@
1/// Epoch reference times in terms of their difference from
2/// posix epoch in seconds.
3pub const posix = 0; //Jan 01, 1970 AD
4pub const dos = 315532800; //Jan 01, 1980 AD
5pub const ios = 978307200; //Jan 01, 2001 AD
6pub const openvms = -3506716800; //Nov 17, 1858 AD
7pub const zos = -2208988800; //Jan 01, 1900 AD
8pub const windows = -11644473600; //Jan 01, 1601 AD
9pub const amiga = 252460800; //Jan 01, 1978 AD
10pub const pickos = -63244800; //Dec 31, 1967 AD
11pub const gps = 315964800; //Jan 06, 1980 AD
12pub const clr = -62135769600; //Jan 01, 0001 AD
13
14pub const unix = posix;
15pub const android = posix;
16pub const os2 = dos;
17pub const bios = dos;
18pub const vfat = dos;
19pub const ntfs = windows;
20pub const ntp = zos;
21pub const jbase = pickos;
22pub const aros = amiga;
23pub const morphos = amiga;
24pub const brew = gps;
25pub const atsc = gps;
26pub const go = clr;
\ No newline at end of file
std/os/file.zig+44-1
......@@ -85,6 +85,47 @@ pub const File = struct {
8585 };
8686 }
8787
88 pub fn access(allocator: &mem.Allocator, path: []const u8, file_mode: os.FileMode) !bool {
89 const path_with_null = try std.cstr.addNullByte(allocator, path);
90 defer allocator.free(path_with_null);
91
92 if (is_posix) {
93 // mode is ignored and is always F_OK for now
94 const result = posix.access(path_with_null.ptr, posix.F_OK);
95 const err = posix.getErrno(result);
96 if (err > 0) {
97 return switch (err) {
98 posix.EACCES => error.PermissionDenied,
99 posix.EROFS => error.PermissionDenied,
100 posix.ELOOP => error.PermissionDenied,
101 posix.ETXTBSY => error.PermissionDenied,
102 posix.ENOTDIR => error.NotFound,
103 posix.ENOENT => error.NotFound,
104
105 posix.ENAMETOOLONG => error.NameTooLong,
106 posix.EINVAL => error.BadMode,
107 posix.EFAULT => error.BadPathName,
108 posix.EIO => error.Io,
109 posix.ENOMEM => error.SystemResources,
110 else => os.unexpectedErrorPosix(err),
111 };
112 }
113 return true;
114 } else if (is_windows) {
115 if (os.windows.PathFileExists(path_with_null.ptr) == os.windows.TRUE) {
116 return true;
117 }
118
119 const err = windows.GetLastError();
120 return switch (err) {
121 windows.ERROR.FILE_NOT_FOUND => error.NotFound,
122 windows.ERROR.ACCESS_DENIED => error.PermissionDenied,
123 else => os.unexpectedErrorWindows(err),
124 };
125 } else {
126 @compileError("TODO implement access for this OS");
127 }
128 }
88129
89130 /// Upon success, the stream is in an uninitialized state. To continue using it,
90131 /// you must use the open() function.
......@@ -245,7 +286,9 @@ pub const File = struct {
245286 };
246287 }
247288
248 return stat.mode;
289 // TODO: we should be able to cast u16 to ModeError!u32, making this
290 // explicit cast not necessary
291 return os.FileMode(stat.mode);
249292 } else if (is_windows) {
250293 return {};
251294 } else {
std/os/index.zig+132-46
......@@ -9,11 +9,10 @@ test "std.os" {
99 _ = @import("darwin.zig");
1010 _ = @import("darwin_errno.zig");
1111 _ = @import("get_user_id.zig");
12 _ = @import("linux/errno.zig");
1312 _ = @import("linux/index.zig");
14 _ = @import("linux/x86_64.zig");
1513 _ = @import("path.zig");
1614 _ = @import("test.zig");
15 _ = @import("time.zig");
1716 _ = @import("windows/index.zig");
1817}
1918
......@@ -32,6 +31,7 @@ pub const net = @import("net.zig");
3231pub const ChildProcess = @import("child_process.zig").ChildProcess;
3332pub const path = @import("path.zig");
3433pub const File = @import("file.zig").File;
34pub const time = @import("time.zig");
3535
3636pub const FileMode = switch (builtin.os) {
3737 Os.windows => void,
......@@ -478,6 +478,7 @@ fn posixExecveErrnoToErr(err: usize) PosixExecveError {
478478 };
479479}
480480
481pub var linux_aux_raw = []usize{0} ** 38;
481482pub var posix_environ_raw: []&u8 = undefined;
482483
483484/// Caller must free result when done.
......@@ -1379,50 +1380,6 @@ pub fn readLink(allocator: &Allocator, pathname: []const u8) ![]u8 {
13791380 }
13801381}
13811382
1382pub fn sleep(seconds: usize, nanoseconds: usize) void {
1383 switch(builtin.os) {
1384 Os.linux, Os.macosx, Os.ios => {
1385 posixSleep(u63(seconds), u63(nanoseconds));
1386 },
1387 Os.windows => {
1388 const milliseconds = seconds * 1000 + nanoseconds / 1000000;
1389 windows.Sleep(windows.DWORD(milliseconds));
1390 },
1391 else => @compileError("Unsupported OS"),
1392 }
1393}
1394
1395const u63 = @IntType(false, 63);
1396pub fn posixSleep(seconds: u63, nanoseconds: u63) void {
1397 var req = posix.timespec {
1398 .tv_sec = seconds,
1399 .tv_nsec = nanoseconds,
1400 };
1401 var rem: posix.timespec = undefined;
1402 while (true) {
1403 const ret_val = posix.nanosleep(&req, &rem);
1404 const err = posix.getErrno(ret_val);
1405 if (err == 0) return;
1406 switch (err) {
1407 posix.EFAULT => unreachable,
1408 posix.EINVAL => {
1409 // Sometimes Darwin returns EINVAL for no reason.
1410 // We treat it as a spurious wakeup.
1411 return;
1412 },
1413 posix.EINTR => {
1414 req = rem;
1415 continue;
1416 },
1417 else => return,
1418 }
1419 }
1420}
1421
1422test "os.sleep" {
1423 sleep(0, 1);
1424}
1425
14261383pub fn posix_setuid(uid: u32) !void {
14271384 const err = posix.getErrno(posix.setuid(uid));
14281385 if (err == 0) return;
......@@ -2384,3 +2341,132 @@ pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {
23842341 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
23852342 }
23862343}
2344
2345pub const Thread = struct {
2346 pid: i32,
2347 allocator: ?&mem.Allocator,
2348 stack: []u8,
2349
2350 pub fn wait(self: &const Thread) void {
2351 while (true) {
2352 const pid_value = @atomicLoad(i32, &self.pid, builtin.AtomicOrder.SeqCst);
2353 if (pid_value == 0) break;
2354 const rc = linux.futex_wait(@ptrToInt(&self.pid), linux.FUTEX_WAIT, pid_value, null);
2355 switch (linux.getErrno(rc)) {
2356 0 => continue,
2357 posix.EINTR => continue,
2358 posix.EAGAIN => continue,
2359 else => unreachable,
2360 }
2361 }
2362 if (self.allocator) |a| {
2363 a.free(self.stack);
2364 }
2365 }
2366};
2367
2368pub const SpawnThreadError = error {
2369 /// A system-imposed limit on the number of threads was encountered.
2370 /// There are a number of limits that may trigger this error:
2371 /// * the RLIMIT_NPROC soft resource limit (set via setrlimit(2)),
2372 /// which limits the number of processes and threads for a real
2373 /// user ID, was reached;
2374 /// * the kernel's system-wide limit on the number of processes and
2375 /// threads, /proc/sys/kernel/threads-max, was reached (see
2376 /// proc(5));
2377 /// * the maximum number of PIDs, /proc/sys/kernel/pid_max, was
2378 /// reached (see proc(5)); or
2379 /// * the PID limit (pids.max) imposed by the cgroup "process num‐
2380 /// ber" (PIDs) controller was reached.
2381 ThreadQuotaExceeded,
2382
2383 /// The kernel cannot allocate sufficient memory to allocate a task structure
2384 /// for the child, or to copy those parts of the caller's context that need to
2385 /// be copied.
2386 SystemResources,
2387
2388 Unexpected,
2389};
2390
2391pub const SpawnThreadAllocatorError = SpawnThreadError || error{OutOfMemory};
2392
2393/// caller must call wait on the returned thread
2394/// fn startFn(@typeOf(context)) T
2395/// where T is u8, noreturn, void, or !void
2396pub fn spawnThreadAllocator(allocator: &mem.Allocator, context: var, comptime startFn: var) SpawnThreadAllocatorError!&Thread {
2397 // TODO compile-time call graph analysis to determine stack upper bound
2398 // https://github.com/zig-lang/zig/issues/157
2399 const default_stack_size = 8 * 1024 * 1024;
2400 const stack_bytes = try allocator.alloc(u8, default_stack_size);
2401 const thread = try spawnThread(stack_bytes, context, startFn);
2402 thread.allocator = allocator;
2403 return thread;
2404}
2405
2406/// stack must be big enough to store one Thread and one @typeOf(context), each with default alignment, at the end
2407/// fn startFn(@typeOf(context)) T
2408/// where T is u8, noreturn, void, or !void
2409/// caller must call wait on the returned thread
2410pub fn spawnThread(stack: []u8, context: var, comptime startFn: var) SpawnThreadError!&Thread {
2411 const Context = @typeOf(context);
2412 comptime assert(@ArgType(@typeOf(startFn), 0) == Context);
2413
2414 var stack_end: usize = @ptrToInt(stack.ptr) + stack.len;
2415 var arg: usize = undefined;
2416 if (@sizeOf(Context) != 0) {
2417 stack_end -= @sizeOf(Context);
2418 stack_end -= stack_end % @alignOf(Context);
2419 assert(stack_end >= @ptrToInt(stack.ptr));
2420 const context_ptr = @alignCast(@alignOf(Context), @intToPtr(&Context, stack_end));
2421 *context_ptr = context;
2422 arg = stack_end;
2423 }
2424
2425 stack_end -= @sizeOf(Thread);
2426 stack_end -= stack_end % @alignOf(Thread);
2427 assert(stack_end >= @ptrToInt(stack.ptr));
2428 const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(&Thread, stack_end));
2429 thread_ptr.stack = stack;
2430 thread_ptr.allocator = null;
2431
2432 const threadMain = struct {
2433 extern fn threadMain(ctx_addr: usize) u8 {
2434 if (@sizeOf(Context) == 0) {
2435 return startFn({});
2436 } else {
2437 return startFn(*@intToPtr(&const Context, ctx_addr));
2438 }
2439 }
2440 }.threadMain;
2441
2442 const flags = posix.CLONE_VM | posix.CLONE_FS | posix.CLONE_FILES | posix.CLONE_SIGHAND
2443 | posix.CLONE_THREAD | posix.CLONE_SYSVSEM // | posix.CLONE_SETTLS
2444 | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID | posix.CLONE_DETACHED;
2445 const newtls: usize = 0;
2446 const rc = posix.clone(threadMain, stack_end, flags, arg, &thread_ptr.pid, newtls, &thread_ptr.pid);
2447 const err = posix.getErrno(rc);
2448 switch (err) {
2449 0 => return thread_ptr,
2450 posix.EAGAIN => return SpawnThreadError.ThreadQuotaExceeded,
2451 posix.EINVAL => unreachable,
2452 posix.ENOMEM => return SpawnThreadError.SystemResources,
2453 posix.ENOSPC => unreachable,
2454 posix.EPERM => unreachable,
2455 posix.EUSERS => unreachable,
2456 else => return unexpectedErrorPosix(err),
2457 }
2458}
2459
2460pub fn posixWait(pid: i32) i32 {
2461 var status: i32 = undefined;
2462 while (true) {
2463 const err = posix.getErrno(posix.waitpid(pid, &status, 0));
2464 switch (err) {
2465 0 => return status,
2466 posix.EINTR => continue,
2467 posix.ECHILD => unreachable, // The process specified does not exist. It would be a race condition to handle this error.
2468 posix.EINVAL => unreachable, // The options argument was invalid
2469 else => unreachable,
2470 }
2471 }
2472}
std/os/linux/index.zig+80-3
......@@ -1,6 +1,7 @@
11const std = @import("../../index.zig");
22const assert = std.debug.assert;
33const builtin = @import("builtin");
4const vdso = @import("vdso.zig");
45pub use switch (builtin.arch) {
56 builtin.Arch.x86_64 => @import("x86_64.zig"),
67 builtin.Arch.i386 => @import("i386.zig"),
......@@ -14,6 +15,22 @@ pub const STDIN_FILENO = 0;
1415pub const STDOUT_FILENO = 1;
1516pub const STDERR_FILENO = 2;
1617
18pub const FUTEX_WAIT = 0;
19pub const FUTEX_WAKE = 1;
20pub const FUTEX_FD = 2;
21pub const FUTEX_REQUEUE = 3;
22pub const FUTEX_CMP_REQUEUE = 4;
23pub const FUTEX_WAKE_OP = 5;
24pub const FUTEX_LOCK_PI = 6;
25pub const FUTEX_UNLOCK_PI = 7;
26pub const FUTEX_TRYLOCK_PI = 8;
27pub const FUTEX_WAIT_BITSET = 9;
28
29pub const FUTEX_PRIVATE_FLAG = 128;
30
31pub const FUTEX_CLOCK_REALTIME = 256;
32
33
1734pub const PROT_NONE = 0;
1835pub const PROT_READ = 1;
1936pub const PROT_WRITE = 2;
......@@ -38,6 +55,11 @@ pub const MAP_STACK = 0x20000;
3855pub const MAP_HUGETLB = 0x40000;
3956pub const MAP_FILE = 0;
4057
58pub const F_OK = 0;
59pub const X_OK = 1;
60pub const W_OK = 2;
61pub const R_OK = 4;
62
4163pub const WNOHANG = 1;
4264pub const WUNTRACED = 2;
4365pub const WSTOPPED = 2;
......@@ -647,6 +669,10 @@ pub fn fork() usize {
647669 return syscall0(SYS_fork);
648670}
649671
672pub fn futex_wait(uaddr: usize, futex_op: u32, val: i32, timeout: ?&timespec) usize {
673 return syscall4(SYS_futex, uaddr, futex_op, @bitCast(u32, val), @ptrToInt(timeout));
674}
675
650676pub fn getcwd(buf: &u8, size: usize) usize {
651677 return syscall2(SYS_getcwd, @ptrToInt(buf), size);
652678}
......@@ -705,6 +731,10 @@ pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) usize {
705731 return syscall4(SYS_pread, usize(fd), @ptrToInt(buf), count, offset);
706732}
707733
734pub fn access(path: &const u8, mode: u32) usize {
735 return syscall2(SYS_access, @ptrToInt(path), mode);
736}
737
708738pub fn pipe(fd: &[2]i32) usize {
709739 return pipe2(fd, 0);
710740}
......@@ -737,6 +767,16 @@ pub fn openat(dirfd: i32, path: &const u8, flags: usize, mode: usize) usize {
737767 return syscall4(SYS_openat, usize(dirfd), @ptrToInt(path), flags, mode);
738768}
739769
770/// See also `clone` (from the arch-specific include)
771pub fn clone5(flags: usize, child_stack_ptr: usize, parent_tid: &i32, child_tid: &i32, newtls: usize) usize {
772 return syscall5(SYS_clone, flags, child_stack_ptr, @ptrToInt(parent_tid), @ptrToInt(child_tid), newtls);
773}
774
775/// See also `clone` (from the arch-specific include)
776pub fn clone2(flags: usize, child_stack_ptr: usize) usize {
777 return syscall2(SYS_clone, flags, child_stack_ptr);
778}
779
740780pub fn close(fd: i32) usize {
741781 return syscall1(SYS_close, usize(fd));
742782}
......@@ -766,6 +806,45 @@ pub fn waitpid(pid: i32, status: &i32, options: i32) usize {
766806 return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0);
767807}
768808
809pub fn clock_gettime(clk_id: i32, tp: &timespec) usize {
810 if (VDSO_CGT_SYM.len != 0) {
811 const f = @atomicLoad(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, builtin.AtomicOrder.Unordered);
812 if (@ptrToInt(f) != 0) {
813 const rc = f(clk_id, tp);
814 switch (rc) {
815 0, @bitCast(usize, isize(-EINVAL)) => return rc,
816 else => {},
817 }
818 }
819 }
820 return syscall2(SYS_clock_gettime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
821}
822var vdso_clock_gettime = init_vdso_clock_gettime;
823extern fn init_vdso_clock_gettime(clk: i32, ts: &timespec) usize {
824 const addr = vdso.lookup(VDSO_CGT_VER, VDSO_CGT_SYM);
825 var f = @intToPtr(@typeOf(init_vdso_clock_gettime), addr);
826 _ = @cmpxchgStrong(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, init_vdso_clock_gettime, f,
827 builtin.AtomicOrder.Monotonic, builtin.AtomicOrder.Monotonic);
828 if (@ptrToInt(f) == 0) return @bitCast(usize, isize(-ENOSYS));
829 return f(clk, ts);
830}
831
832pub fn clock_getres(clk_id: i32, tp: &timespec) usize {
833 return syscall2(SYS_clock_getres, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
834}
835
836pub fn clock_settime(clk_id: i32, tp: &const timespec) usize {
837 return syscall2(SYS_clock_settime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
838}
839
840pub fn gettimeofday(tv: &timeval, tz: &timezone) usize {
841 return syscall2(SYS_gettimeofday, @ptrToInt(tv), @ptrToInt(tz));
842}
843
844pub fn settimeofday(tv: &const timeval, tz: &const timezone) usize {
845 return syscall2(SYS_settimeofday, @ptrToInt(tv), @ptrToInt(tz));
846}
847
769848pub fn nanosleep(req: &const timespec, rem: ?&timespec) usize {
770849 return syscall2(SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem));
771850}
......@@ -1250,9 +1329,7 @@ pub fn capset(hdrp: &cap_user_header_t, datap: &const cap_user_data_t) usize {
12501329 return syscall2(SYS_capset, @ptrToInt(hdrp), @ptrToInt(datap));
12511330}
12521331
1253test "import linux test" {
1254 // TODO lazy analysis should prevent this test from being compiled on windows, but
1255 // it is still compiled on windows
1332test "import" {
12561333 if (builtin.os == builtin.Os.linux) {
12571334 _ = @import("test.zig");
12581335 }
std/os/linux/test.zig+1
......@@ -1,4 +1,5 @@
11const std = @import("../../index.zig");
2const builtin = @import("builtin");
23const linux = std.os.linux;
34const assert = std.debug.assert;
45
std/os/linux/vdso.zig created+89
......@@ -0,0 +1,89 @@
1const std = @import("../../index.zig");
2const elf = std.elf;
3const linux = std.os.linux;
4const cstr = std.cstr;
5const mem = std.mem;
6
7pub fn lookup(vername: []const u8, name: []const u8) usize {
8 const vdso_addr = std.os.linux_aux_raw[std.elf.AT_SYSINFO_EHDR];
9 if (vdso_addr == 0) return 0;
10
11 const eh = @intToPtr(&elf.Ehdr, vdso_addr);
12 var ph_addr: usize = vdso_addr + eh.e_phoff;
13 const ph = @intToPtr(&elf.Phdr, ph_addr);
14
15 var maybe_dynv: ?&usize = null;
16 var base: usize = @maxValue(usize);
17 {
18 var i: usize = 0;
19 while (i < eh.e_phnum) : ({i += 1; ph_addr += eh.e_phentsize;}) {
20 const this_ph = @intToPtr(&elf.Phdr, ph_addr);
21 switch (this_ph.p_type) {
22 elf.PT_LOAD => base = vdso_addr + this_ph.p_offset - this_ph.p_vaddr,
23 elf.PT_DYNAMIC => maybe_dynv = @intToPtr(&usize, vdso_addr + this_ph.p_offset),
24 else => {},
25 }
26 }
27 }
28 const dynv = maybe_dynv ?? return 0;
29 if (base == @maxValue(usize)) return 0;
30
31 var maybe_strings: ?&u8 = null;
32 var maybe_syms: ?&elf.Sym = null;
33 var maybe_hashtab: ?&linux.Elf_Symndx = null;
34 var maybe_versym: ?&u16 = null;
35 var maybe_verdef: ?&elf.Verdef = null;
36
37 {
38 var i: usize = 0;
39 while (dynv[i] != 0) : (i += 2) {
40 const p = base + dynv[i + 1];
41 switch (dynv[i]) {
42 elf.DT_STRTAB => maybe_strings = @intToPtr(&u8, p),
43 elf.DT_SYMTAB => maybe_syms = @intToPtr(&elf.Sym, p),
44 elf.DT_HASH => maybe_hashtab = @intToPtr(&linux.Elf_Symndx, p),
45 elf.DT_VERSYM => maybe_versym = @intToPtr(&u16, p),
46 elf.DT_VERDEF => maybe_verdef = @intToPtr(&elf.Verdef, p),
47 else => {},
48 }
49 }
50 }
51
52 const strings = maybe_strings ?? return 0;
53 const syms = maybe_syms ?? return 0;
54 const hashtab = maybe_hashtab ?? return 0;
55 if (maybe_verdef == null) maybe_versym = null;
56
57
58 const OK_TYPES = (1<<elf.STT_NOTYPE | 1<<elf.STT_OBJECT | 1<<elf.STT_FUNC | 1<<elf.STT_COMMON);
59 const OK_BINDS = (1<<elf.STB_GLOBAL | 1<<elf.STB_WEAK | 1<<elf.STB_GNU_UNIQUE);
60
61 var i: usize = 0;
62 while (i < hashtab[1]) : (i += 1) {
63 if (0==(u32(1)<<u5(syms[i].st_info&0xf) & OK_TYPES)) continue;
64 if (0==(u32(1)<<u5(syms[i].st_info>>4) & OK_BINDS)) continue;
65 if (0==syms[i].st_shndx) continue;
66 if (!mem.eql(u8, name, cstr.toSliceConst(&strings[syms[i].st_name]))) continue;
67 if (maybe_versym) |versym| {
68 if (!checkver(??maybe_verdef, versym[i], vername, strings))
69 continue;
70 }
71 return base + syms[i].st_value;
72 }
73
74 return 0;
75}
76
77fn checkver(def_arg: &elf.Verdef, vsym_arg: i32, vername: []const u8, strings: &u8) bool {
78 var def = def_arg;
79 const vsym = @bitCast(u32, vsym_arg) & 0x7fff;
80 while (true) {
81 if (0==(def.vd_flags & elf.VER_FLG_BASE) and (def.vd_ndx & 0x7fff) == vsym)
82 break;
83 if (def.vd_next == 0)
84 return false;
85 def = @intToPtr(&elf.Verdef, @ptrToInt(def) + def.vd_next);
86 }
87 const aux = @intToPtr(&elf.Verdaux, @ptrToInt(def ) + def.vd_aux);
88 return mem.eql(u8, vername, cstr.toSliceConst(&strings[aux.vda_name]));
89}
std/os/linux/x86_64.zig+21
......@@ -371,6 +371,13 @@ pub const F_GETOWN_EX = 16;
371371
372372pub const F_GETOWNER_UIDS = 17;
373373
374
375pub const VDSO_USEFUL = true;
376pub const VDSO_CGT_SYM = "__vdso_clock_gettime";
377pub const VDSO_CGT_VER = "LINUX_2.6";
378pub const VDSO_GETCPU_SYM = "__vdso_getcpu";
379pub const VDSO_GETCPU_VER = "LINUX_2.6";
380
374381pub fn syscall0(number: usize) usize {
375382 return asm volatile ("syscall"
376383 : [ret] "={rax}" (-> usize)
......@@ -443,6 +450,9 @@ pub fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usiz
443450 : "rcx", "r11");
444451}
445452
453/// This matches the libc clone function.
454pub extern fn clone(func: extern fn(arg: usize) u8, stack: usize, flags: usize, arg: usize, ptid: &i32, tls: usize, ctid: &i32) usize;
455
446456pub nakedcc fn restore_rt() void {
447457 return asm volatile ("syscall"
448458 :
......@@ -489,6 +499,16 @@ pub const timespec = extern struct {
489499 tv_nsec: isize,
490500};
491501
502pub const timeval = extern struct {
503 tv_sec: isize,
504 tv_usec: isize,
505};
506
507pub const timezone = extern struct {
508 tz_minuteswest: i32,
509 tz_dsttime: i32,
510};
511
492512pub const dirent = extern struct {
493513 d_ino: usize,
494514 d_off: usize,
......@@ -496,3 +516,4 @@ pub const dirent = extern struct {
496516 d_name: u8, // field address is the address of first byte of name
497517};
498518
519pub const Elf_Symndx = u32;
std/os/test.zig+56
......@@ -6,6 +6,8 @@ const io = std.io;
66const a = std.debug.global_allocator;
77
88const builtin = @import("builtin");
9const AtomicRmwOp = builtin.AtomicRmwOp;
10const AtomicOrder = builtin.AtomicOrder;
911
1012test "makePath, put some files in it, deleteTree" {
1113 if (builtin.os == builtin.Os.windows) {
......@@ -23,3 +25,57 @@ test "makePath, put some files in it, deleteTree" {
2325 assert(err == error.PathNotFound);
2426 }
2527}
28
29test "access file" {
30 if (builtin.os == builtin.Os.windows) {
31 return;
32 }
33
34 try os.makePath(a, "os_test_tmp");
35 if (os.File.access(a, "os_test_tmp/file.txt", os.default_file_mode)) |ok| {
36 unreachable;
37 } else |err| {
38 assert(err == error.NotFound);
39 }
40
41 try io.writeFile(a, "os_test_tmp/file.txt", "");
42 assert((try os.File.access(a, "os_test_tmp/file.txt", os.default_file_mode)) == true);
43 try os.deleteTree(a, "os_test_tmp");
44}
45
46test "spawn threads" {
47 if (builtin.os != builtin.Os.linux) {
48 // TODO implement threads on macos and windows
49 return;
50 }
51
52 var direct_allocator = std.heap.DirectAllocator.init();
53 defer direct_allocator.deinit();
54
55 var shared_ctx: i32 = 1;
56
57 const thread1 = try std.os.spawnThreadAllocator(&direct_allocator.allocator, {}, start1);
58 const thread4 = try std.os.spawnThreadAllocator(&direct_allocator.allocator, &shared_ctx, start2);
59
60 var stack1: [1024]u8 = undefined;
61 var stack2: [1024]u8 = undefined;
62
63 const thread2 = try std.os.spawnThread(stack1[0..], &shared_ctx, start2);
64 const thread3 = try std.os.spawnThread(stack2[0..], &shared_ctx, start2);
65
66 thread1.wait();
67 thread2.wait();
68 thread3.wait();
69 thread4.wait();
70
71 assert(shared_ctx == 4);
72}
73
74fn start1(ctx: void) u8 {
75 return 0;
76}
77
78fn start2(ctx: &i32) u8 {
79 _ = @atomicRmw(i32, ctx, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
80 return 0;
81}
std/os/time.zig created+288
......@@ -0,0 +1,288 @@
1const std = @import("../index.zig");
2const builtin = @import("builtin");
3const Os = builtin.Os;
4const debug = std.debug;
5
6const windows = std.os.windows;
7const linux = std.os.linux;
8const darwin = std.os.darwin;
9const posix = std.os.posix;
10
11pub const epoch = @import("epoch.zig");
12
13/// Sleep for the specified duration
14pub fn sleep(seconds: usize, nanoseconds: usize) void {
15 switch (builtin.os) {
16 Os.linux, Os.macosx, Os.ios => {
17 posixSleep(u63(seconds), u63(nanoseconds));
18 },
19 Os.windows => {
20 const ns_per_ms = ns_per_s / ms_per_s;
21 const milliseconds = seconds * ms_per_s + nanoseconds / ns_per_ms;
22 windows.Sleep(windows.DWORD(milliseconds));
23 },
24 else => @compileError("Unsupported OS"),
25 }
26}
27
28const u63 = @IntType(false, 63);
29pub fn posixSleep(seconds: u63, nanoseconds: u63) void {
30 var req = posix.timespec {
31 .tv_sec = seconds,
32 .tv_nsec = nanoseconds,
33 };
34 var rem: posix.timespec = undefined;
35 while (true) {
36 const ret_val = posix.nanosleep(&req, &rem);
37 const err = posix.getErrno(ret_val);
38 if (err == 0) return;
39 switch (err) {
40 posix.EFAULT => unreachable,
41 posix.EINVAL => {
42 // Sometimes Darwin returns EINVAL for no reason.
43 // We treat it as a spurious wakeup.
44 return;
45 },
46 posix.EINTR => {
47 req = rem;
48 continue;
49 },
50 else => return,
51 }
52 }
53}
54
55/// Get the posix timestamp, UTC, in seconds
56pub fn timestamp() u64 {
57 return @divFloor(milliTimestamp(), ms_per_s);
58}
59
60/// Get the posix timestamp, UTC, in milliseconds
61pub const milliTimestamp = switch (builtin.os) {
62 Os.windows => milliTimestampWindows,
63 Os.linux => milliTimestampPosix,
64 Os.macosx, Os.ios => milliTimestampDarwin,
65 else => @compileError("Unsupported OS"),
66};
67
68fn milliTimestampWindows() u64 {
69 //FileTime has a granularity of 100 nanoseconds
70 // and uses the NTFS/Windows epoch
71 var ft: i64 = undefined;
72 windows.GetSystemTimeAsFileTime(&ft);
73 const hns_per_ms = (ns_per_s / 100) / ms_per_s;
74 const epoch_adj = epoch.windows * ms_per_s;
75 return u64(@divFloor(ft, hns_per_ms) + epoch_adj);
76}
77
78fn milliTimestampDarwin() u64 {
79 //Sources suggest MacOS 10.12 has support for
80 // posix clock_gettime.
81 var tv: darwin.timeval = undefined;
82 var err = darwin.gettimeofday(&tv, null);
83 debug.assert(err == 0);
84 const sec_ms = u64(tv.tv_sec) * ms_per_s;
85 const usec_ms = @divFloor(u64(tv.tv_usec), us_per_s / ms_per_s);
86 return u64(sec_ms) + u64(usec_ms);
87}
88
89fn milliTimestampPosix() u64 {
90 //From what I can tell there's no reason clock_gettime
91 // should ever fail for us with CLOCK_REALTIME,
92 // seccomp aside.
93 var ts: posix.timespec = undefined;
94 const err = posix.clock_gettime(posix.CLOCK_REALTIME, &ts);
95 debug.assert(err == 0);
96 const sec_ms = u64(ts.tv_sec) * ms_per_s;
97 const nsec_ms = @divFloor(u64(ts.tv_nsec), ns_per_s / ms_per_s);
98 return sec_ms + nsec_ms;
99}
100
101/// Divisions of a second
102pub const ns_per_s = 1000000000;
103pub const us_per_s = 1000000;
104pub const ms_per_s = 1000;
105pub const cs_per_s = 100;
106
107/// Common time divisions
108pub const s_per_min = 60;
109pub const s_per_hour = s_per_min * 60;
110pub const s_per_day = s_per_hour * 24;
111pub const s_per_week = s_per_day * 7;
112
113
114/// A monotonic high-performance timer.
115/// Timer.start() must be called to initialize the struct, which captures
116/// the counter frequency on windows and darwin, records the resolution,
117/// and gives the user an oportunity to check for the existnece of
118/// monotonic clocks without forcing them to check for error on each read.
119/// .resolution is in nanoseconds on all platforms but .start_time's meaning
120/// depends on the OS. On Windows and Darwin it is a hardware counter
121/// value that requires calculation to convert to a meaninful unit.
122pub const Timer = struct {
123
124 //if we used resolution's value when performing the
125 // performance counter calc on windows/darwin, it would
126 // be less precise
127 frequency: switch (builtin.os) {
128 Os.windows => u64,
129 Os.macosx, Os.ios => darwin.mach_timebase_info_data,
130 else => void,
131 },
132 resolution: u64,
133 start_time: u64,
134
135
136 //At some point we may change our minds on RAW, but for now we're
137 // sticking with posix standard MONOTONIC. For more information, see:
138 // https://github.com/zig-lang/zig/pull/933
139 //
140 //const monotonic_clock_id = switch(builtin.os) {
141 // Os.linux => linux.CLOCK_MONOTONIC_RAW,
142 // else => posix.CLOCK_MONOTONIC,
143 //};
144 const monotonic_clock_id = posix.CLOCK_MONOTONIC;
145
146
147 /// Initialize the timer structure.
148 //This gives us an oportunity to grab the counter frequency in windows.
149 //On Windows: QueryPerformanceCounter will succeed on anything >= XP/2000.
150 //On Posix: CLOCK_MONOTONIC will only fail if the monotonic counter is not
151 // supported, or if the timespec pointer is out of bounds, which should be
152 // impossible here barring cosmic rays or other such occurances of
153 // incredibly bad luck.
154 //On Darwin: This cannot fail, as far as I am able to tell.
155 const TimerError = error{TimerUnsupported, Unexpected};
156 pub fn start() TimerError!Timer {
157 var self: Timer = undefined;
158
159 switch (builtin.os) {
160 Os.windows => {
161 var freq: i64 = undefined;
162 var err = windows.QueryPerformanceFrequency(&freq);
163 if (err == windows.FALSE) return error.TimerUnsupported;
164 self.frequency = u64(freq);
165 self.resolution = @divFloor(ns_per_s, self.frequency);
166
167 var start_time: i64 = undefined;
168 err = windows.QueryPerformanceCounter(&start_time);
169 debug.assert(err != windows.FALSE);
170 self.start_time = u64(start_time);
171 },
172 Os.linux => {
173 //On Linux, seccomp can do arbitrary things to our ability to call
174 // syscalls, including return any errno value it wants and
175 // inconsistently throwing errors. Since we can't account for
176 // abuses of seccomp in a reasonable way, we'll assume that if
177 // seccomp is going to block us it will at least do so consistently
178 var ts: posix.timespec = undefined;
179 var result = posix.clock_getres(monotonic_clock_id, &ts);
180 var errno = posix.getErrno(result);
181 switch (errno) {
182 0 => {},
183 posix.EINVAL => return error.TimerUnsupported,
184 else => return std.os.unexpectedErrorPosix(errno),
185 }
186 self.resolution = u64(ts.tv_sec) * u64(ns_per_s) + u64(ts.tv_nsec);
187
188 result = posix.clock_gettime(monotonic_clock_id, &ts);
189 errno = posix.getErrno(result);
190 if (errno != 0) return std.os.unexpectedErrorPosix(errno);
191 self.start_time = u64(ts.tv_sec) * u64(ns_per_s) + u64(ts.tv_nsec);
192 },
193 Os.macosx, Os.ios => {
194 darwin.mach_timebase_info(&self.frequency);
195 self.resolution = @divFloor(self.frequency.numer, self.frequency.denom);
196 self.start_time = darwin.mach_absolute_time();
197 },
198 else => @compileError("Unsupported OS"),
199 }
200 return self;
201 }
202
203 /// Reads the timer value since start or the last reset in nanoseconds
204 pub fn read(self: &Timer) u64 {
205 var clock = clockNative() - self.start_time;
206 return switch (builtin.os) {
207 Os.windows => @divFloor(clock * ns_per_s, self.frequency),
208 Os.linux => clock,
209 Os.macosx, Os.ios => @divFloor(clock * self.frequency.numer, self.frequency.denom),
210 else => @compileError("Unsupported OS"),
211 };
212 }
213
214 /// Resets the timer value to 0/now.
215 pub fn reset(self: &Timer) void
216 {
217 self.start_time = clockNative();
218 }
219
220 /// Returns the current value of the timer in nanoseconds, then resets it
221 pub fn lap(self: &Timer) u64 {
222 var now = clockNative();
223 var lap_time = self.read();
224 self.start_time = now;
225 return lap_time;
226 }
227
228
229 const clockNative = switch (builtin.os) {
230 Os.windows => clockWindows,
231 Os.linux => clockLinux,
232 Os.macosx, Os.ios => clockDarwin,
233 else => @compileError("Unsupported OS"),
234 };
235
236 fn clockWindows() u64 {
237 var result: i64 = undefined;
238 var err = windows.QueryPerformanceCounter(&result);
239 debug.assert(err != windows.FALSE);
240 return u64(result);
241 }
242
243 fn clockDarwin() u64 {
244 return darwin.mach_absolute_time();
245 }
246
247 fn clockLinux() u64 {
248 var ts: posix.timespec = undefined;
249 var result = posix.clock_gettime(monotonic_clock_id, &ts);
250 debug.assert(posix.getErrno(result) == 0);
251 return u64(ts.tv_sec) * u64(ns_per_s) + u64(ts.tv_nsec);
252 }
253};
254
255
256
257
258
259test "os.time.sleep" {
260 sleep(0, 1);
261}
262
263test "os.time.timestamp" {
264 const ns_per_ms = (ns_per_s / ms_per_s);
265 const margin = 50;
266
267 const time_0 = milliTimestamp();
268 sleep(0, ns_per_ms);
269 const time_1 = milliTimestamp();
270 const interval = time_1 - time_0;
271 debug.assert(interval > 0 and interval < margin);
272}
273
274test "os.time.Timer" {
275 const ns_per_ms = (ns_per_s / ms_per_s);
276 const margin = ns_per_ms * 50;
277
278 var timer = try Timer.start();
279 sleep(0, 10 * ns_per_ms);
280 const time_0 = timer.read();
281 debug.assert(time_0 > 0 and time_0 < margin);
282
283 const time_1 = timer.lap();
284 debug.assert(time_1 > time_0);
285
286 timer.reset();
287 debug.assert(timer.read() < time_1);
288}
std/os/windows/index.zig+13
......@@ -61,6 +61,8 @@ pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(hFile: HANDLE, lpsz
6161
6262pub extern "kernel32" stdcallcc fn GetProcessHeap() ?HANDLE;
6363
64pub extern "kernel32" stdcallcc fn GetSystemTimeAsFileTime(?&FILETIME) void;
65
6466pub extern "kernel32" stdcallcc fn HeapCreate(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T) ?HANDLE;
6567pub extern "kernel32" stdcallcc fn HeapDestroy(hHeap: HANDLE) BOOL;
6668pub extern "kernel32" stdcallcc fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: &c_void, dwBytes: SIZE_T) ?&c_void;
......@@ -77,6 +79,12 @@ pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem
7779
7880pub extern "kernel32" stdcallcc fn MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR,
7981 dwFlags: DWORD) BOOL;
82
83pub extern "kernel32" stdcallcc fn QueryPerformanceCounter(lpPerformanceCount: &LARGE_INTEGER) BOOL;
84
85pub extern "kernel32" stdcallcc fn QueryPerformanceFrequency(lpFrequency: &LARGE_INTEGER) BOOL;
86
87pub extern "kernel32" stdcallcc fn PathFileExists(pszPath: ?LPCTSTR) BOOL;
8088
8189pub extern "kernel32" stdcallcc fn ReadFile(in_hFile: HANDLE, out_lpBuffer: &c_void,
8290 in_nNumberOfBytesToRead: DWORD, out_lpNumberOfBytesRead: &DWORD,
......@@ -137,6 +145,7 @@ pub const UNICODE = false;
137145pub const WCHAR = u16;
138146pub const WORD = u16;
139147pub const LARGE_INTEGER = i64;
148pub const FILETIME = i64;
140149
141150pub const TRUE = 1;
142151pub const FALSE = 0;
......@@ -308,3 +317,7 @@ pub const FILE_END = 2;
308317pub const HEAP_CREATE_ENABLE_EXECUTE = 0x00040000;
309318pub const HEAP_GENERATE_EXCEPTIONS = 0x00000004;
310319pub const HEAP_NO_SERIALIZE = 0x00000001;
320
321test "import" {
322 _ = @import("util.zig");
323}
std/rand/index.zig+19-5
......@@ -19,6 +19,7 @@ const builtin = @import("builtin");
1919const assert = std.debug.assert;
2020const mem = std.mem;
2121const math = std.math;
22const ziggurat = @import("ziggurat.zig");
2223
2324// When you need fast unbiased random numbers
2425pub const DefaultPrng = Xoroshiro128;
......@@ -109,15 +110,28 @@ pub const Random = struct {
109110 }
110111 }
111112
112 /// Return a floating point value normally distributed in the range [0, 1].
113 /// Return a floating point value normally distributed with mean = 0, stddev = 1.
114 ///
115 /// To use different parameters, use: floatNorm(...) * desiredStddev + desiredMean.
113116 pub fn floatNorm(r: &Random, comptime T: type) T {
114 // TODO(tiehuis): See https://www.doornik.com/research/ziggurat.pdf
115 @compileError("floatNorm is unimplemented");
117 const value = ziggurat.next_f64(r, ziggurat.NormDist);
118 switch (T) {
119 f32 => return f32(value),
120 f64 => return value,
121 else => @compileError("unknown floating point type"),
122 }
116123 }
117124
118 /// Return a exponentially distributed float between (0, @maxValue(f64))
125 /// Return an exponentially distributed float with a rate parameter of 1.
126 ///
127 /// To use a different rate parameter, use: floatExp(...) / desiredRate.
119128 pub fn floatExp(r: &Random, comptime T: type) T {
120 @compileError("floatExp is unimplemented");
129 const value = ziggurat.next_f64(r, ziggurat.ExpDist);
130 switch (T) {
131 f32 => return f32(value),
132 f64 => return value,
133 else => @compileError("unknown floating point type"),
134 }
121135 }
122136
123137 /// Shuffle a slice into a random order.
std/rand/ziggurat.zig created+146
......@@ -0,0 +1,146 @@
1// Implements ZIGNOR [1].
2//
3// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to Generate Normal Random Samples*]
4// (https://www.doornik.com/research/ziggurat.pdf). Nuffield College, Oxford.
5//
6// rust/rand used as a reference;
7//
8// NOTE: This seems interesting but reference code is a bit hard to grok:
9// https://sbarral.github.io/etf.
10
11const std = @import("../index.zig");
12const math = std.math;
13const Random = std.rand.Random;
14
15pub fn next_f64(random: &Random, comptime tables: &const ZigTable) f64 {
16 while (true) {
17 // We manually construct a float from parts as we can avoid an extra random lookup here by
18 // using the unused exponent for the lookup table entry.
19 const bits = random.scalar(u64);
20 const i = usize(bits & 0xff);
21
22 const u = blk: {
23 if (tables.is_symmetric) {
24 // Generate a value in the range [2, 4) and scale into [-1, 1)
25 const repr = ((0x3ff + 1) << 52) | (bits >> 12);
26 break :blk @bitCast(f64, repr) - 3.0;
27 } else {
28 // Generate a value in the range [1, 2) and scale into (0, 1)
29 const repr = (0x3ff << 52) | (bits >> 12);
30 break :blk @bitCast(f64, repr) - (1.0 - math.f64_epsilon / 2.0);
31 }
32 };
33
34 const x = u * tables.x[i];
35 const test_x = if (tables.is_symmetric) math.fabs(x) else x;
36
37 // equivalent to |u| < tables.x[i+1] / tables.x[i] (or u < tables.x[i+1] / tables.x[i])
38 if (test_x < tables.x[i + 1]) {
39 return x;
40 }
41
42 if (i == 0) {
43 return tables.zero_case(random, u);
44 }
45
46 // equivalent to f1 + DRanU() * (f0 - f1) < 1
47 if (tables.f[i + 1] + (tables.f[i] - tables.f[i + 1]) * random.float(f64) < tables.pdf(x)) {
48 return x;
49 }
50 }
51}
52
53pub const ZigTable = struct {
54 r: f64,
55 x: [257]f64,
56 f: [257]f64,
57
58 // probability density function used as a fallback
59 pdf: fn(f64) f64,
60 // whether the distribution is symmetric
61 is_symmetric: bool,
62 // fallback calculation in the case we are in the 0 block
63 zero_case: fn(&Random, f64) f64,
64};
65
66// zigNorInit
67fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, comptime f: fn(f64) f64,
68 comptime f_inv: fn(f64) f64, comptime zero_case: fn(&Random, f64) f64) ZigTable {
69 var tables: ZigTable = undefined;
70
71 tables.is_symmetric = is_symmetric;
72 tables.r = r;
73 tables.pdf = f;
74 tables.zero_case = zero_case;
75
76 tables.x[0] = v / f(r);
77 tables.x[1] = r;
78
79 for (tables.x[2..256]) |*entry, i| {
80 const last = tables.x[2 + i - 1];
81 *entry = f_inv(v / last + f(last));
82 }
83 tables.x[256] = 0;
84
85 for (tables.f[0..]) |*entry, i| {
86 *entry = f(tables.x[i]);
87 }
88
89 return tables;
90}
91
92// N(0, 1)
93pub const NormDist = blk: {
94 @setEvalBranchQuota(30000);
95 break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case);
96};
97
98const norm_r = 3.6541528853610088;
99const norm_v = 0.00492867323399;
100
101fn norm_f(x: f64) f64 { return math.exp(-x * x / 2.0); }
102fn norm_f_inv(y: f64) f64 { return math.sqrt(-2.0 * math.ln(y)); }
103fn norm_zero_case(random: &Random, u: f64) f64 {
104 var x: f64 = 1;
105 var y: f64 = 0;
106
107 while (-2.0 * y < x * x) {
108 x = math.ln(random.float(f64)) / norm_r;
109 y = math.ln(random.float(f64));
110 }
111
112 if (u < 0) {
113 return x - norm_r;
114 } else {
115 return norm_r - x;
116 }
117}
118
119test "ziggurant normal dist sanity" {
120 var prng = std.rand.DefaultPrng.init(0);
121 var i: usize = 0;
122 while (i < 1000) : (i += 1) {
123 _ = prng.random.floatNorm(f64);
124 }
125}
126
127// Exp(1)
128pub const ExpDist = blk: {
129 @setEvalBranchQuota(30000);
130 break :blk ZigTableGen(false, exp_r, exp_v, exp_f, exp_f_inv, exp_zero_case);
131};
132
133const exp_r = 7.69711747013104972;
134const exp_v = 0.0039496598225815571993;
135
136fn exp_f(x: f64) f64 { return math.exp(-x); }
137fn exp_f_inv(y: f64) f64 { return -math.ln(y); }
138fn exp_zero_case(random: &Random, _: f64) f64 { return exp_r - math.ln(random.float(f64)); }
139
140test "ziggurant exp dist sanity" {
141 var prng = std.rand.DefaultPrng.init(0);
142 var i: usize = 0;
143 while (i < 1000) : (i += 1) {
144 _ = prng.random.floatExp(f64);
145 }
146}
std/special/bootstrap.zig+19-8
......@@ -48,22 +48,33 @@ extern fn WinMainCRTStartup() noreturn {
4848fn posixCallMainAndExit() noreturn {
4949 const argc = *argc_ptr;
5050 const argv = @ptrCast(&&u8, &argc_ptr[1]);
51 const envp = @ptrCast(&?&u8, &argv[argc + 1]);
51 const envp_nullable = @ptrCast(&?&u8, &argv[argc + 1]);
52 var envp_count: usize = 0;
53 while (envp_nullable[envp_count]) |_| : (envp_count += 1) {}
54 const envp = @ptrCast(&&u8, envp_nullable)[0..envp_count];
55 if (builtin.os == builtin.Os.linux) {
56 const auxv = &@ptrCast(&usize, envp.ptr)[envp_count + 1];
57 var i: usize = 0;
58 while (auxv[i] != 0) : (i += 2) {
59 if (auxv[i] < std.os.linux_aux_raw.len) std.os.linux_aux_raw[auxv[i]] = auxv[i+1];
60 }
61 std.debug.assert(std.os.linux_aux_raw[std.elf.AT_PAGESZ] == std.os.page_size);
62 }
63
5264 std.os.posix.exit(callMainWithArgs(argc, argv, envp));
5365}
5466
55fn callMainWithArgs(argc: usize, argv: &&u8, envp: &?&u8) u8 {
67fn callMainWithArgs(argc: usize, argv: &&u8, envp: []&u8) u8 {
5668 std.os.ArgIteratorPosix.raw = argv[0..argc];
57
58 var env_count: usize = 0;
59 while (envp[env_count] != null) : (env_count += 1) {}
60 std.os.posix_environ_raw = @ptrCast(&&u8, envp)[0..env_count];
61
69 std.os.posix_environ_raw = envp;
6270 return callMain();
6371}
6472
6573extern fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) i32 {
66 return callMainWithArgs(usize(c_argc), c_argv, c_envp);
74 var env_count: usize = 0;
75 while (c_envp[env_count] != null) : (env_count += 1) {}
76 const envp = @ptrCast(&&u8, c_envp)[0..env_count];
77 return callMainWithArgs(usize(c_argc), c_argv, envp);
6778}
6879
6980fn callMain() u8 {
std/special/builtin.zig+247-1
......@@ -54,14 +54,51 @@ export fn memmove(dest: ?&u8, src: ?&const u8, n: usize) ?&u8 {
5454}
5555
5656comptime {
57 if (builtin.mode != builtin.Mode.ReleaseFast and builtin.os != builtin.Os.windows) {
57 if (builtin.mode != builtin.Mode.ReleaseFast and
58 builtin.mode != builtin.Mode.ReleaseSmall and
59 builtin.os != builtin.Os.windows) {
5860 @export("__stack_chk_fail", __stack_chk_fail, builtin.GlobalLinkage.Strong);
5961 }
62 if (builtin.os == builtin.Os.linux and builtin.arch == builtin.Arch.x86_64) {
63 @export("clone", clone, builtin.GlobalLinkage.Strong);
64 }
6065}
6166extern fn __stack_chk_fail() noreturn {
6267 @panic("stack smashing detected");
6368}
6469
70// TODO we should be able to put this directly in std/linux/x86_64.zig but
71// it causes a segfault in release mode. this is a workaround of calling it
72// across .o file boundaries. fix comptime @ptrCast of nakedcc functions.
73nakedcc fn clone() void {
74 asm volatile (
75 \\ xor %%eax,%%eax
76 \\ mov $56,%%al
77 \\ mov %%rdi,%%r11
78 \\ mov %%rdx,%%rdi
79 \\ mov %%r8,%%rdx
80 \\ mov %%r9,%%r8
81 \\ mov 8(%%rsp),%%r10
82 \\ mov %%r11,%%r9
83 \\ and $-16,%%rsi
84 \\ sub $8,%%rsi
85 \\ mov %%rcx,(%%rsi)
86 \\ syscall
87 \\ test %%eax,%%eax
88 \\ jnz 1f
89 \\ xor %%ebp,%%ebp
90 \\ pop %%rdi
91 \\ call *%%r9
92 \\ mov %%eax,%%edi
93 \\ xor %%eax,%%eax
94 \\ mov $60,%%al
95 \\ syscall
96 \\ hlt
97 \\1: ret
98 \\
99 );
100}
101
65102const math = @import("../math/index.zig");
66103
67104export fn fmodf(x: f32, y: f32) f32 { return generic_fmod(f32, x, y); }
......@@ -159,3 +196,212 @@ fn isNan(comptime T: type, bits: T) bool {
159196 unreachable;
160197 }
161198}
199
200// NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound
201// behaviour. Most intermediate i32 values are changed to u32 where appropriate but there are
202// potentially some edge cases remaining that are not handled in the same way.
203export fn sqrt(x: f64) f64 {
204 const tiny: f64 = 1.0e-300;
205 const sign: u32 = 0x80000000;
206 const u = @bitCast(u64, x);
207
208 var ix0 = u32(u >> 32);
209 var ix1 = u32(u & 0xFFFFFFFF);
210
211 // sqrt(nan) = nan, sqrt(+inf) = +inf, sqrt(-inf) = nan
212 if (ix0 & 0x7FF00000 == 0x7FF00000) {
213 return x * x + x;
214 }
215
216 // sqrt(+-0) = +-0
217 if (x == 0.0) {
218 return x;
219 }
220 // sqrt(-ve) = snan
221 if (ix0 & sign != 0) {
222 return math.snan(f64);
223 }
224
225 // normalize x
226 var m = i32(ix0 >> 20);
227 if (m == 0) {
228 // subnormal
229 while (ix0 == 0) {
230 m -= 21;
231 ix0 |= ix1 >> 11;
232 ix1 <<= 21;
233 }
234
235 // subnormal
236 var i: u32 = 0;
237 while (ix0 & 0x00100000 == 0) : (i += 1) {
238 ix0 <<= 1;
239 }
240 m -= i32(i) - 1;
241 ix0 |= ix1 >> u5(32 - i);
242 ix1 <<= u5(i);
243 }
244
245 // unbias exponent
246 m -= 1023;
247 ix0 = (ix0 & 0x000FFFFF) | 0x00100000;
248 if (m & 1 != 0) {
249 ix0 += ix0 + (ix1 >> 31);
250 ix1 = ix1 +% ix1;
251 }
252 m >>= 1;
253
254 // sqrt(x) bit by bit
255 ix0 += ix0 + (ix1 >> 31);
256 ix1 = ix1 +% ix1;
257
258 var q: u32 = 0;
259 var q1: u32 = 0;
260 var s0: u32 = 0;
261 var s1: u32 = 0;
262 var r: u32 = 0x00200000;
263 var t: u32 = undefined;
264 var t1: u32 = undefined;
265
266 while (r != 0) {
267 t = s0 +% r;
268 if (t <= ix0) {
269 s0 = t + r;
270 ix0 -= t;
271 q += r;
272 }
273 ix0 = ix0 +% ix0 +% (ix1 >> 31);
274 ix1 = ix1 +% ix1;
275 r >>= 1;
276 }
277
278 r = sign;
279 while (r != 0) {
280 t = s1 +% r;
281 t = s0;
282 if (t < ix0 or (t == ix0 and t1 <= ix1)) {
283 s1 = t1 +% r;
284 if (t1 & sign == sign and s1 & sign == 0) {
285 s0 += 1;
286 }
287 ix0 -= t;
288 if (ix1 < t1) {
289 ix0 -= 1;
290 }
291 ix1 = ix1 -% t1;
292 q1 += r;
293 }
294 ix0 = ix0 +% ix0 +% (ix1 >> 31);
295 ix1 = ix1 +% ix1;
296 r >>= 1;
297 }
298
299 // rounding direction
300 if (ix0 | ix1 != 0) {
301 var z = 1.0 - tiny; // raise inexact
302 if (z >= 1.0) {
303 z = 1.0 + tiny;
304 if (q1 == 0xFFFFFFFF) {
305 q1 = 0;
306 q += 1;
307 } else if (z > 1.0) {
308 if (q1 == 0xFFFFFFFE) {
309 q += 1;
310 }
311 q1 += 2;
312 } else {
313 q1 += q1 & 1;
314 }
315 }
316 }
317
318 ix0 = (q >> 1) + 0x3FE00000;
319 ix1 = q1 >> 1;
320 if (q & 1 != 0) {
321 ix1 |= 0x80000000;
322 }
323
324 // NOTE: musl here appears to rely on signed twos-complement wraparound. +% has the same
325 // behaviour at least.
326 var iix0 = i32(ix0);
327 iix0 = iix0 +% (m << 20);
328
329 const uz = (u64(iix0) << 32) | ix1;
330 return @bitCast(f64, uz);
331}
332
333export fn sqrtf(x: f32) f32 {
334 const tiny: f32 = 1.0e-30;
335 const sign: i32 = @bitCast(i32, u32(0x80000000));
336 var ix: i32 = @bitCast(i32, x);
337
338 if ((ix & 0x7F800000) == 0x7F800000) {
339 return x * x + x; // sqrt(nan) = nan, sqrt(+inf) = +inf, sqrt(-inf) = snan
340 }
341
342 // zero
343 if (ix <= 0) {
344 if (ix & ~sign == 0) {
345 return x; // sqrt (+-0) = +-0
346 }
347 if (ix < 0) {
348 return math.snan(f32);
349 }
350 }
351
352 // normalize
353 var m = ix >> 23;
354 if (m == 0) {
355 // subnormal
356 var i: i32 = 0;
357 while (ix & 0x00800000 == 0) : (i += 1) {
358 ix <<= 1;
359 }
360 m -= i - 1;
361 }
362
363 m -= 127; // unbias exponent
364 ix = (ix & 0x007FFFFF) | 0x00800000;
365
366 if (m & 1 != 0) { // odd m, double x to even
367 ix += ix;
368 }
369
370 m >>= 1; // m = [m / 2]
371
372 // sqrt(x) bit by bit
373 ix += ix;
374 var q: i32 = 0; // q = sqrt(x)
375 var s: i32 = 0;
376 var r: i32 = 0x01000000; // r = moving bit right -> left
377
378 while (r != 0) {
379 const t = s + r;
380 if (t <= ix) {
381 s = t + r;
382 ix -= t;
383 q += r;
384 }
385 ix += ix;
386 r >>= 1;
387 }
388
389 // floating add to find rounding direction
390 if (ix != 0) {
391 var z = 1.0 - tiny; // inexact
392 if (z >= 1.0) {
393 z = 1.0 + tiny;
394 if (z > 1.0) {
395 q += 2;
396 } else {
397 if (q & 1 != 0) {
398 q += 1;
399 }
400 }
401 }
402 }
403
404 ix = (q >> 1) + 0x3f000000;
405 ix += m << 23;
406 return @bitCast(f32, ix);
407}
std/zig/ast.zig+1315-1364
......@@ -6,7 +6,6 @@ const mem = std.mem;
66
77pub const Node = struct {
88 id: Id,
9 comment: ?&NodeLineComment,
109
1110 pub const Id = enum {
1211 // Top level
......@@ -74,1734 +73,1686 @@ pub const Node = struct {
7473 FieldInitializer,
7574 };
7675
77 const IdTypePair = struct {
78 id: Id,
79 Type: type,
80 };
81
82 // TODO: When @field exists, we could generate this by iterating over all members of `Id`,
83 // and making an array of `IdTypePair { .id = @field(Id, @memberName(Id, i)), .Type = @field(ast, "Node" ++ @memberName(Id, i)) }`
84 const idTypeTable = []IdTypePair {
85 IdTypePair { .id = Id.Root, .Type = NodeRoot },
86 IdTypePair { .id = Id.Use, .Type = NodeUse },
87 IdTypePair { .id = Id.TestDecl, .Type = NodeTestDecl },
88
89 IdTypePair { .id = Id.VarDecl, .Type = NodeVarDecl },
90 IdTypePair { .id = Id.Defer, .Type = NodeDefer },
91
92 IdTypePair { .id = Id.InfixOp, .Type = NodeInfixOp },
93 IdTypePair { .id = Id.PrefixOp, .Type = NodePrefixOp },
94 IdTypePair { .id = Id.SuffixOp, .Type = NodeSuffixOp },
95
96 IdTypePair { .id = Id.Switch, .Type = NodeSwitch },
97 IdTypePair { .id = Id.While, .Type = NodeWhile },
98 IdTypePair { .id = Id.For, .Type = NodeFor },
99 IdTypePair { .id = Id.If, .Type = NodeIf },
100 IdTypePair { .id = Id.ControlFlowExpression, .Type = NodeControlFlowExpression },
101 IdTypePair { .id = Id.Suspend, .Type = NodeSuspend },
102
103 IdTypePair { .id = Id.VarType, .Type = NodeVarType },
104 IdTypePair { .id = Id.ErrorType, .Type = NodeErrorType },
105 IdTypePair { .id = Id.FnProto, .Type = NodeFnProto },
106
107 IdTypePair { .id = Id.IntegerLiteral, .Type = NodeIntegerLiteral },
108 IdTypePair { .id = Id.FloatLiteral, .Type = NodeFloatLiteral },
109 IdTypePair { .id = Id.StringLiteral, .Type = NodeStringLiteral },
110 IdTypePair { .id = Id.MultilineStringLiteral, .Type = NodeMultilineStringLiteral },
111 IdTypePair { .id = Id.CharLiteral, .Type = NodeCharLiteral },
112 IdTypePair { .id = Id.BoolLiteral, .Type = NodeBoolLiteral },
113 IdTypePair { .id = Id.NullLiteral, .Type = NodeNullLiteral },
114 IdTypePair { .id = Id.UndefinedLiteral, .Type = NodeUndefinedLiteral },
115 IdTypePair { .id = Id.ThisLiteral, .Type = NodeThisLiteral },
116 IdTypePair { .id = Id.Unreachable, .Type = NodeUnreachable },
117 IdTypePair { .id = Id.Identifier, .Type = NodeIdentifier },
118 IdTypePair { .id = Id.GroupedExpression, .Type = NodeGroupedExpression },
119 IdTypePair { .id = Id.BuiltinCall, .Type = NodeBuiltinCall },
120 IdTypePair { .id = Id.ErrorSetDecl, .Type = NodeErrorSetDecl },
121 IdTypePair { .id = Id.ContainerDecl, .Type = NodeContainerDecl },
122 IdTypePair { .id = Id.Asm, .Type = NodeAsm },
123 IdTypePair { .id = Id.Comptime, .Type = NodeComptime },
124 IdTypePair { .id = Id.Block, .Type = NodeBlock },
125
126 IdTypePair { .id = Id.LineComment, .Type = NodeLineComment },
127 IdTypePair { .id = Id.SwitchCase, .Type = NodeSwitchCase },
128 IdTypePair { .id = Id.SwitchElse, .Type = NodeSwitchElse },
129 IdTypePair { .id = Id.Else, .Type = NodeElse },
130 IdTypePair { .id = Id.Payload, .Type = NodePayload },
131 IdTypePair { .id = Id.PointerPayload, .Type = NodePointerPayload },
132 IdTypePair { .id = Id.PointerIndexPayload, .Type = NodePointerIndexPayload },
133 IdTypePair { .id = Id.StructField, .Type = NodeStructField },
134 IdTypePair { .id = Id.UnionTag, .Type = NodeUnionTag },
135 IdTypePair { .id = Id.EnumTag, .Type = NodeEnumTag },
136 IdTypePair { .id = Id.AsmInput, .Type = NodeAsmInput },
137 IdTypePair { .id = Id.AsmOutput, .Type = NodeAsmOutput },
138 IdTypePair { .id = Id.AsyncAttribute, .Type = NodeAsyncAttribute },
139 IdTypePair { .id = Id.ParamDecl, .Type = NodeParamDecl },
140 IdTypePair { .id = Id.FieldInitializer, .Type = NodeFieldInitializer },
141 };
142
143 pub fn IdToType(comptime id: Id) type {
144 inline for (idTypeTable) |id_type_pair| {
145 if (id == id_type_pair.id)
146 return id_type_pair.Type;
147 }
148
149 unreachable;
150 }
151
152 pub fn typeToId(comptime T: type) Id {
153 inline for (idTypeTable) |id_type_pair| {
154 if (T == id_type_pair.Type)
155 return id_type_pair.id;
156 }
157
158 unreachable;
159 }
160
16176 pub fn iterate(base: &Node, index: usize) ?&Node {
162 inline for (idTypeTable) |id_type_pair| {
163 if (base.id == id_type_pair.id)
164 return @fieldParentPtr(id_type_pair.Type, "base", base).iterate(index);
77 comptime var i = 0;
78 inline while (i < @memberCount(Id)) : (i += 1) {
79 if (base.id == @field(Id, @memberName(Id, i))) {
80 const T = @field(Node, @memberName(Id, i));
81 return @fieldParentPtr(T, "base", base).iterate(index);
82 }
16583 }
166
16784 unreachable;
16885 }
16986
17087 pub fn firstToken(base: &Node) Token {
171 inline for (idTypeTable) |id_type_pair| {
172 if (base.id == id_type_pair.id)
173 return @fieldParentPtr(id_type_pair.Type, "base", base).firstToken();
88 comptime var i = 0;
89 inline while (i < @memberCount(Id)) : (i += 1) {
90 if (base.id == @field(Id, @memberName(Id, i))) {
91 const T = @field(Node, @memberName(Id, i));
92 return @fieldParentPtr(T, "base", base).firstToken();
93 }
17494 }
175
17695 unreachable;
17796 }
17897
17998 pub fn lastToken(base: &Node) Token {
180 inline for (idTypeTable) |id_type_pair| {
181 if (base.id == id_type_pair.id)
182 return @fieldParentPtr(id_type_pair.Type, "base", base).lastToken();
99 comptime var i = 0;
100 inline while (i < @memberCount(Id)) : (i += 1) {
101 if (base.id == @field(Id, @memberName(Id, i))) {
102 const T = @field(Node, @memberName(Id, i));
103 return @fieldParentPtr(T, "base", base).lastToken();
104 }
183105 }
184
185106 unreachable;
186107 }
187};
188108
189pub const NodeRoot = struct {
190 base: Node,
191 decls: ArrayList(&Node),
192 eof_token: Token,
193
194 pub fn iterate(self: &NodeRoot, index: usize) ?&Node {
195 if (index < self.decls.len) {
196 return self.decls.items[self.decls.len - index - 1];
109 pub fn typeToId(comptime T: type) Id {
110 comptime var i = 0;
111 inline while (i < @memberCount(Id)) : (i += 1) {
112 if (T == @field(Node, @memberName(Id, i))) {
113 return @field(Id, @memberName(Id, i));
114 }
197115 }
198 return null;
199 }
200
201 pub fn firstToken(self: &NodeRoot) Token {
202 return if (self.decls.len == 0) self.eof_token else self.decls.at(0).firstToken();
116 unreachable;
203117 }
204118
205 pub fn lastToken(self: &NodeRoot) Token {
206 return if (self.decls.len == 0) self.eof_token else self.decls.at(self.decls.len - 1).lastToken();
207 }
208};
119 pub const Root = struct {
120 base: Node,
121 decls: ArrayList(&Node),
122 eof_token: Token,
209123
210pub const NodeVarDecl = struct {
211 base: Node,
212 visib_token: ?Token,
213 name_token: Token,
214 eq_token: Token,
215 mut_token: Token,
216 comptime_token: ?Token,
217 extern_export_token: ?Token,
218 lib_name: ?&Node,
219 type_node: ?&Node,
220 align_node: ?&Node,
221 init_node: ?&Node,
222 semicolon_token: Token,
223
224 pub fn iterate(self: &NodeVarDecl, index: usize) ?&Node {
225 var i = index;
226
227 if (self.type_node) |type_node| {
228 if (i < 1) return type_node;
229 i -= 1;
124 pub fn iterate(self: &Root, index: usize) ?&Node {
125 if (index < self.decls.len) {
126 return self.decls.items[self.decls.len - index - 1];
127 }
128 return null;
230129 }
231130
232 if (self.align_node) |align_node| {
233 if (i < 1) return align_node;
234 i -= 1;
131 pub fn firstToken(self: &Root) Token {
132 return if (self.decls.len == 0) self.eof_token else self.decls.at(0).firstToken();
235133 }
236134
237 if (self.init_node) |init_node| {
238 if (i < 1) return init_node;
239 i -= 1;
135 pub fn lastToken(self: &Root) Token {
136 return if (self.decls.len == 0) self.eof_token else self.decls.at(self.decls.len - 1).lastToken();
240137 }
138 };
241139
242 return null;
243 }
244
245 pub fn firstToken(self: &NodeVarDecl) Token {
246 if (self.visib_token) |visib_token| return visib_token;
247 if (self.comptime_token) |comptime_token| return comptime_token;
248 if (self.extern_export_token) |extern_export_token| return extern_export_token;
249 assert(self.lib_name == null);
250 return self.mut_token;
251 }
252
253 pub fn lastToken(self: &NodeVarDecl) Token {
254 return self.semicolon_token;
255 }
256};
257
258pub const NodeUse = struct {
259 base: Node,
260 visib_token: ?Token,
261 expr: &Node,
262 semicolon_token: Token,
263
264 pub fn iterate(self: &NodeUse, index: usize) ?&Node {
265 var i = index;
140 pub const VarDecl = struct {
141 base: Node,
142 comments: ?&LineComment,
143 visib_token: ?Token,
144 name_token: Token,
145 eq_token: Token,
146 mut_token: Token,
147 comptime_token: ?Token,
148 extern_export_token: ?Token,
149 lib_name: ?&Node,
150 type_node: ?&Node,
151 align_node: ?&Node,
152 init_node: ?&Node,
153 semicolon_token: Token,
154
155 pub fn iterate(self: &VarDecl, index: usize) ?&Node {
156 var i = index;
157
158 if (self.type_node) |type_node| {
159 if (i < 1) return type_node;
160 i -= 1;
161 }
266162
267 if (i < 1) return self.expr;
268 i -= 1;
163 if (self.align_node) |align_node| {
164 if (i < 1) return align_node;
165 i -= 1;
166 }
269167
270 return null;
271 }
168 if (self.init_node) |init_node| {
169 if (i < 1) return init_node;
170 i -= 1;
171 }
272172
273 pub fn firstToken(self: &NodeUse) Token {
274 if (self.visib_token) |visib_token| return visib_token;
275 return self.expr.firstToken();
276 }
173 return null;
174 }
277175
278 pub fn lastToken(self: &NodeUse) Token {
279 return self.semicolon_token;
280 }
281};
176 pub fn firstToken(self: &VarDecl) Token {
177 if (self.visib_token) |visib_token| return visib_token;
178 if (self.comptime_token) |comptime_token| return comptime_token;
179 if (self.extern_export_token) |extern_export_token| return extern_export_token;
180 assert(self.lib_name == null);
181 return self.mut_token;
182 }
282183
283pub const NodeErrorSetDecl = struct {
284 base: Node,
285 error_token: Token,
286 decls: ArrayList(&NodeIdentifier),
287 rbrace_token: Token,
184 pub fn lastToken(self: &VarDecl) Token {
185 return self.semicolon_token;
186 }
187 };
288188
289 pub fn iterate(self: &NodeErrorSetDecl, index: usize) ?&Node {
290 var i = index;
189 pub const Use = struct {
190 base: Node,
191 visib_token: ?Token,
192 expr: &Node,
193 semicolon_token: Token,
291194
292 if (i < self.decls.len) return &self.decls.at(i).base;
293 i -= self.decls.len;
195 pub fn iterate(self: &Use, index: usize) ?&Node {
196 var i = index;
294197
295 return null;
296 }
198 if (i < 1) return self.expr;
199 i -= 1;
297200
298 pub fn firstToken(self: &NodeErrorSetDecl) Token {
299 return self.error_token;
300 }
201 return null;
202 }
301203
302 pub fn lastToken(self: &NodeErrorSetDecl) Token {
303 return self.rbrace_token;
304 }
305};
204 pub fn firstToken(self: &Use) Token {
205 if (self.visib_token) |visib_token| return visib_token;
206 return self.expr.firstToken();
207 }
306208
307pub const NodeContainerDecl = struct {
308 base: Node,
309 ltoken: Token,
310 layout: Layout,
311 kind: Kind,
312 init_arg_expr: InitArg,
313 fields_and_decls: ArrayList(&Node),
314 rbrace_token: Token,
315
316 const Layout = enum {
317 Auto,
318 Extern,
319 Packed,
209 pub fn lastToken(self: &Use) Token {
210 return self.semicolon_token;
211 }
320212 };
321213
322 const Kind = enum {
323 Struct,
324 Enum,
325 Union,
326 };
214 pub const ErrorSetDecl = struct {
215 base: Node,
216 error_token: Token,
217 decls: ArrayList(&Node),
218 rbrace_token: Token,
327219
328 const InitArg = union(enum) {
329 None,
330 Enum,
331 Type: &Node,
332 };
220 pub fn iterate(self: &ErrorSetDecl, index: usize) ?&Node {
221 var i = index;
333222
334 pub fn iterate(self: &NodeContainerDecl, index: usize) ?&Node {
335 var i = index;
223 if (i < self.decls.len) return self.decls.at(i);
224 i -= self.decls.len;
336225
337 switch (self.init_arg_expr) {
338 InitArg.Type => |t| {
339 if (i < 1) return t;
340 i -= 1;
341 },
342 InitArg.None,
343 InitArg.Enum => { }
226 return null;
344227 }
345228
346 if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i);
347 i -= self.fields_and_decls.len;
229 pub fn firstToken(self: &ErrorSetDecl) Token {
230 return self.error_token;
231 }
348232
349 return null;
350 }
233 pub fn lastToken(self: &ErrorSetDecl) Token {
234 return self.rbrace_token;
235 }
236 };
351237
352 pub fn firstToken(self: &NodeContainerDecl) Token {
353 return self.ltoken;
354 }
238 pub const ContainerDecl = struct {
239 base: Node,
240 ltoken: Token,
241 layout: Layout,
242 kind: Kind,
243 init_arg_expr: InitArg,
244 fields_and_decls: ArrayList(&Node),
245 rbrace_token: Token,
246
247 const Layout = enum {
248 Auto,
249 Extern,
250 Packed,
251 };
355252
356 pub fn lastToken(self: &NodeContainerDecl) Token {
357 return self.rbrace_token;
358 }
359};
253 const Kind = enum {
254 Struct,
255 Enum,
256 Union,
257 };
258
259 const InitArg = union(enum) {
260 None,
261 Enum,
262 Type: &Node,
263 };
360264
361pub const NodeStructField = struct {
362 base: Node,
363 visib_token: ?Token,
364 name_token: Token,
365 type_expr: &Node,
265 pub fn iterate(self: &ContainerDecl, index: usize) ?&Node {
266 var i = index;
366267
367 pub fn iterate(self: &NodeStructField, index: usize) ?&Node {
368 var i = index;
268 switch (self.init_arg_expr) {
269 InitArg.Type => |t| {
270 if (i < 1) return t;
271 i -= 1;
272 },
273 InitArg.None,
274 InitArg.Enum => { }
275 }
369276
370 if (i < 1) return self.type_expr;
371 i -= 1;
277 if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i);
278 i -= self.fields_and_decls.len;
372279
373 return null;
374 }
280 return null;
281 }
375282
376 pub fn firstToken(self: &NodeStructField) Token {
377 if (self.visib_token) |visib_token| return visib_token;
378 return self.name_token;
379 }
283 pub fn firstToken(self: &ContainerDecl) Token {
284 return self.ltoken;
285 }
380286
381 pub fn lastToken(self: &NodeStructField) Token {
382 return self.type_expr.lastToken();
383 }
384};
287 pub fn lastToken(self: &ContainerDecl) Token {
288 return self.rbrace_token;
289 }
290 };
385291
386pub const NodeUnionTag = struct {
387 base: Node,
388 name_token: Token,
389 type_expr: ?&Node,
292 pub const StructField = struct {
293 base: Node,
294 visib_token: ?Token,
295 name_token: Token,
296 type_expr: &Node,
390297
391 pub fn iterate(self: &NodeUnionTag, index: usize) ?&Node {
392 var i = index;
298 pub fn iterate(self: &StructField, index: usize) ?&Node {
299 var i = index;
393300
394 if (self.type_expr) |type_expr| {
395 if (i < 1) return type_expr;
301 if (i < 1) return self.type_expr;
396302 i -= 1;
397 }
398303
399 return null;
400 }
304 return null;
305 }
401306
402 pub fn firstToken(self: &NodeUnionTag) Token {
403 return self.name_token;
404 }
307 pub fn firstToken(self: &StructField) Token {
308 if (self.visib_token) |visib_token| return visib_token;
309 return self.name_token;
310 }
405311
406 pub fn lastToken(self: &NodeUnionTag) Token {
407 if (self.type_expr) |type_expr| {
408 return type_expr.lastToken();
312 pub fn lastToken(self: &StructField) Token {
313 return self.type_expr.lastToken();
409314 }
315 };
410316
411 return self.name_token;
412 }
413};
317 pub const UnionTag = struct {
318 base: Node,
319 name_token: Token,
320 type_expr: ?&Node,
414321
415pub const NodeEnumTag = struct {
416 base: Node,
417 name_token: Token,
418 value: ?&Node,
322 pub fn iterate(self: &UnionTag, index: usize) ?&Node {
323 var i = index;
419324
420 pub fn iterate(self: &NodeEnumTag, index: usize) ?&Node {
421 var i = index;
325 if (self.type_expr) |type_expr| {
326 if (i < 1) return type_expr;
327 i -= 1;
328 }
422329
423 if (self.value) |value| {
424 if (i < 1) return value;
425 i -= 1;
330 return null;
426331 }
427332
428 return null;
429 }
333 pub fn firstToken(self: &UnionTag) Token {
334 return self.name_token;
335 }
430336
431 pub fn firstToken(self: &NodeEnumTag) Token {
432 return self.name_token;
433 }
337 pub fn lastToken(self: &UnionTag) Token {
338 if (self.type_expr) |type_expr| {
339 return type_expr.lastToken();
340 }
434341
435 pub fn lastToken(self: &NodeEnumTag) Token {
436 if (self.value) |value| {
437 return value.lastToken();
342 return self.name_token;
438343 }
344 };
439345
440 return self.name_token;
441 }
442};
443
444pub const NodeIdentifier = struct {
445 base: Node,
446 token: Token,
346 pub const EnumTag = struct {
347 base: Node,
348 name_token: Token,
349 value: ?&Node,
447350
448 pub fn iterate(self: &NodeIdentifier, index: usize) ?&Node {
449 return null;
450 }
351 pub fn iterate(self: &EnumTag, index: usize) ?&Node {
352 var i = index;
451353
452 pub fn firstToken(self: &NodeIdentifier) Token {
453 return self.token;
454 }
354 if (self.value) |value| {
355 if (i < 1) return value;
356 i -= 1;
357 }
455358
456 pub fn lastToken(self: &NodeIdentifier) Token {
457 return self.token;
458 }
459};
359 return null;
360 }
460361
461pub const NodeAsyncAttribute = struct {
462 base: Node,
463 async_token: Token,
464 allocator_type: ?&Node,
465 rangle_bracket: ?Token,
362 pub fn firstToken(self: &EnumTag) Token {
363 return self.name_token;
364 }
466365
467 pub fn iterate(self: &NodeAsyncAttribute, index: usize) ?&Node {
468 var i = index;
366 pub fn lastToken(self: &EnumTag) Token {
367 if (self.value) |value| {
368 return value.lastToken();
369 }
469370
470 if (self.allocator_type) |allocator_type| {
471 if (i < 1) return allocator_type;
472 i -= 1;
371 return self.name_token;
473372 }
373 };
474374
475 return null;
476 }
477
478 pub fn firstToken(self: &NodeAsyncAttribute) Token {
479 return self.async_token;
480 }
375 pub const Identifier = struct {
376 base: Node,
377 token: Token,
481378
482 pub fn lastToken(self: &NodeAsyncAttribute) Token {
483 if (self.rangle_bracket) |rangle_bracket| {
484 return rangle_bracket;
379 pub fn iterate(self: &Identifier, index: usize) ?&Node {
380 return null;
485381 }
486382
487 return self.async_token;
488 }
489};
383 pub fn firstToken(self: &Identifier) Token {
384 return self.token;
385 }
490386
491pub const NodeFnProto = struct {
492 base: Node,
493 visib_token: ?Token,
494 fn_token: Token,
495 name_token: ?Token,
496 params: ArrayList(&Node),
497 return_type: ReturnType,
498 var_args_token: ?Token,
499 extern_export_inline_token: ?Token,
500 cc_token: ?Token,
501 async_attr: ?&NodeAsyncAttribute,
502 body_node: ?&Node,
503 lib_name: ?&Node, // populated if this is an extern declaration
504 align_expr: ?&Node, // populated if align(A) is present
505
506 pub const ReturnType = union(enum) {
507 Explicit: &Node,
508 InferErrorSet: &Node,
387 pub fn lastToken(self: &Identifier) Token {
388 return self.token;
389 }
509390 };
510391
511 pub fn iterate(self: &NodeFnProto, index: usize) ?&Node {
512 var i = index;
392 pub const AsyncAttribute = struct {
393 base: Node,
394 async_token: Token,
395 allocator_type: ?&Node,
396 rangle_bracket: ?Token,
513397
514 if (self.body_node) |body_node| {
515 if (i < 1) return body_node;
516 i -= 1;
517 }
398 pub fn iterate(self: &AsyncAttribute, index: usize) ?&Node {
399 var i = index;
518400
519 switch (self.return_type) {
520 // TODO allow this and next prong to share bodies since the types are the same
521 ReturnType.Explicit => |node| {
522 if (i < 1) return node;
401 if (self.allocator_type) |allocator_type| {
402 if (i < 1) return allocator_type;
523403 i -= 1;
524 },
525 ReturnType.InferErrorSet => |node| {
526 if (i < 1) return node;
527 i -= 1;
528 },
404 }
405
406 return null;
529407 }
530408
531 if (self.align_expr) |align_expr| {
532 if (i < 1) return align_expr;
533 i -= 1;
409 pub fn firstToken(self: &AsyncAttribute) Token {
410 return self.async_token;
534411 }
535412
536 if (i < self.params.len) return self.params.items[self.params.len - i - 1];
537 i -= self.params.len;
413 pub fn lastToken(self: &AsyncAttribute) Token {
414 if (self.rangle_bracket) |rangle_bracket| {
415 return rangle_bracket;
416 }
538417
539 if (self.lib_name) |lib_name| {
540 if (i < 1) return lib_name;
541 i -= 1;
418 return self.async_token;
542419 }
420 };
543421
544 return null;
545 }
422 pub const FnProto = struct {
423 base: Node,
424 comments: ?&LineComment,
425 visib_token: ?Token,
426 fn_token: Token,
427 name_token: ?Token,
428 params: ArrayList(&Node),
429 return_type: ReturnType,
430 var_args_token: ?Token,
431 extern_export_inline_token: ?Token,
432 cc_token: ?Token,
433 async_attr: ?&AsyncAttribute,
434 body_node: ?&Node,
435 lib_name: ?&Node, // populated if this is an extern declaration
436 align_expr: ?&Node, // populated if align(A) is present
437
438 pub const ReturnType = union(enum) {
439 Explicit: &Node,
440 InferErrorSet: &Node,
441 };
546442
547 pub fn firstToken(self: &NodeFnProto) Token {
548 if (self.visib_token) |visib_token| return visib_token;
549 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
550 assert(self.lib_name == null);
551 if (self.cc_token) |cc_token| return cc_token;
552 return self.fn_token;
553 }
443 pub fn iterate(self: &FnProto, index: usize) ?&Node {
444 var i = index;
554445
555 pub fn lastToken(self: &NodeFnProto) Token {
556 if (self.body_node) |body_node| return body_node.lastToken();
557 switch (self.return_type) {
558 // TODO allow this and next prong to share bodies since the types are the same
559 ReturnType.Explicit => |node| return node.lastToken(),
560 ReturnType.InferErrorSet => |node| return node.lastToken(),
561 }
562 }
563};
446 if (self.body_node) |body_node| {
447 if (i < 1) return body_node;
448 i -= 1;
449 }
564450
565pub const NodeParamDecl = struct {
566 base: Node,
567 comptime_token: ?Token,
568 noalias_token: ?Token,
569 name_token: ?Token,
570 type_node: &Node,
571 var_args_token: ?Token,
451 switch (self.return_type) {
452 // TODO allow this and next prong to share bodies since the types are the same
453 ReturnType.Explicit => |node| {
454 if (i < 1) return node;
455 i -= 1;
456 },
457 ReturnType.InferErrorSet => |node| {
458 if (i < 1) return node;
459 i -= 1;
460 },
461 }
572462
573 pub fn iterate(self: &NodeParamDecl, index: usize) ?&Node {
574 var i = index;
463 if (self.align_expr) |align_expr| {
464 if (i < 1) return align_expr;
465 i -= 1;
466 }
575467
576 if (i < 1) return self.type_node;
577 i -= 1;
468 if (i < self.params.len) return self.params.items[self.params.len - i - 1];
469 i -= self.params.len;
578470
579 return null;
580 }
471 if (self.lib_name) |lib_name| {
472 if (i < 1) return lib_name;
473 i -= 1;
474 }
581475
582 pub fn firstToken(self: &NodeParamDecl) Token {
583 if (self.comptime_token) |comptime_token| return comptime_token;
584 if (self.noalias_token) |noalias_token| return noalias_token;
585 if (self.name_token) |name_token| return name_token;
586 return self.type_node.firstToken();
587 }
476 return null;
477 }
588478
589 pub fn lastToken(self: &NodeParamDecl) Token {
590 if (self.var_args_token) |var_args_token| return var_args_token;
591 return self.type_node.lastToken();
592 }
593};
479 pub fn firstToken(self: &FnProto) Token {
480 if (self.visib_token) |visib_token| return visib_token;
481 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
482 assert(self.lib_name == null);
483 if (self.cc_token) |cc_token| return cc_token;
484 return self.fn_token;
485 }
594486
595pub const NodeBlock = struct {
596 base: Node,
597 label: ?Token,
598 lbrace: Token,
599 statements: ArrayList(&Node),
600 rbrace: Token,
487 pub fn lastToken(self: &FnProto) Token {
488 if (self.body_node) |body_node| return body_node.lastToken();
489 switch (self.return_type) {
490 // TODO allow this and next prong to share bodies since the types are the same
491 ReturnType.Explicit => |node| return node.lastToken(),
492 ReturnType.InferErrorSet => |node| return node.lastToken(),
493 }
494 }
495 };
601496
602 pub fn iterate(self: &NodeBlock, index: usize) ?&Node {
603 var i = index;
497 pub const ParamDecl = struct {
498 base: Node,
499 comptime_token: ?Token,
500 noalias_token: ?Token,
501 name_token: ?Token,
502 type_node: &Node,
503 var_args_token: ?Token,
604504
605 if (i < self.statements.len) return self.statements.items[i];
606 i -= self.statements.len;
505 pub fn iterate(self: &ParamDecl, index: usize) ?&Node {
506 var i = index;
607507
608 return null;
609 }
508 if (i < 1) return self.type_node;
509 i -= 1;
610510
611 pub fn firstToken(self: &NodeBlock) Token {
612 if (self.label) |label| {
613 return label;
511 return null;
614512 }
615513
616 return self.lbrace;
617 }
514 pub fn firstToken(self: &ParamDecl) Token {
515 if (self.comptime_token) |comptime_token| return comptime_token;
516 if (self.noalias_token) |noalias_token| return noalias_token;
517 if (self.name_token) |name_token| return name_token;
518 return self.type_node.firstToken();
519 }
618520
619 pub fn lastToken(self: &NodeBlock) Token {
620 return self.rbrace;
621 }
622};
521 pub fn lastToken(self: &ParamDecl) Token {
522 if (self.var_args_token) |var_args_token| return var_args_token;
523 return self.type_node.lastToken();
524 }
525 };
623526
624pub const NodeDefer = struct {
625 base: Node,
626 defer_token: Token,
627 kind: Kind,
628 expr: &Node,
527 pub const Block = struct {
528 base: Node,
529 label: ?Token,
530 lbrace: Token,
531 statements: ArrayList(&Node),
532 rbrace: Token,
629533
630 const Kind = enum {
631 Error,
632 Unconditional,
633 };
534 pub fn iterate(self: &Block, index: usize) ?&Node {
535 var i = index;
634536
635 pub fn iterate(self: &NodeDefer, index: usize) ?&Node {
636 var i = index;
537 if (i < self.statements.len) return self.statements.items[i];
538 i -= self.statements.len;
637539
638 if (i < 1) return self.expr;
639 i -= 1;
540 return null;
541 }
640542
641 return null;
642 }
543 pub fn firstToken(self: &Block) Token {
544 if (self.label) |label| {
545 return label;
546 }
643547
644 pub fn firstToken(self: &NodeDefer) Token {
645 return self.defer_token;
646 }
548 return self.lbrace;
549 }
647550
648 pub fn lastToken(self: &NodeDefer) Token {
649 return self.expr.lastToken();
650 }
651};
551 pub fn lastToken(self: &Block) Token {
552 return self.rbrace;
553 }
554 };
652555
653pub const NodeComptime = struct {
654 base: Node,
655 comptime_token: Token,
656 expr: &Node,
556 pub const Defer = struct {
557 base: Node,
558 defer_token: Token,
559 kind: Kind,
560 expr: &Node,
657561
658 pub fn iterate(self: &NodeComptime, index: usize) ?&Node {
659 var i = index;
562 const Kind = enum {
563 Error,
564 Unconditional,
565 };
660566
661 if (i < 1) return self.expr;
662 i -= 1;
567 pub fn iterate(self: &Defer, index: usize) ?&Node {
568 var i = index;
663569
664 return null;
665 }
570 if (i < 1) return self.expr;
571 i -= 1;
666572
667 pub fn firstToken(self: &NodeComptime) Token {
668 return self.comptime_token;
669 }
573 return null;
574 }
670575
671 pub fn lastToken(self: &NodeComptime) Token {
672 return self.expr.lastToken();
673 }
674};
576 pub fn firstToken(self: &Defer) Token {
577 return self.defer_token;
578 }
675579
676pub const NodePayload = struct {
677 base: Node,
678 lpipe: Token,
679 error_symbol: &NodeIdentifier,
680 rpipe: Token,
580 pub fn lastToken(self: &Defer) Token {
581 return self.expr.lastToken();
582 }
583 };
681584
682 pub fn iterate(self: &NodePayload, index: usize) ?&Node {
683 var i = index;
585 pub const Comptime = struct {
586 base: Node,
587 comptime_token: Token,
588 expr: &Node,
684589
685 if (i < 1) return &self.error_symbol.base;
686 i -= 1;
590 pub fn iterate(self: &Comptime, index: usize) ?&Node {
591 var i = index;
687592
688 return null;
689 }
593 if (i < 1) return self.expr;
594 i -= 1;
690595
691 pub fn firstToken(self: &NodePayload) Token {
692 return self.lpipe;
693 }
596 return null;
597 }
694598
695 pub fn lastToken(self: &NodePayload) Token {
696 return self.rpipe;
697 }
698};
599 pub fn firstToken(self: &Comptime) Token {
600 return self.comptime_token;
601 }
699602
700pub const NodePointerPayload = struct {
701 base: Node,
702 lpipe: Token,
703 is_ptr: bool,
704 value_symbol: &NodeIdentifier,
705 rpipe: Token,
603 pub fn lastToken(self: &Comptime) Token {
604 return self.expr.lastToken();
605 }
606 };
706607
707 pub fn iterate(self: &NodePointerPayload, index: usize) ?&Node {
708 var i = index;
608 pub const Payload = struct {
609 base: Node,
610 lpipe: Token,
611 error_symbol: &Node,
612 rpipe: Token,
709613
710 if (i < 1) return &self.value_symbol.base;
711 i -= 1;
614 pub fn iterate(self: &Payload, index: usize) ?&Node {
615 var i = index;
712616
713 return null;
714 }
617 if (i < 1) return self.error_symbol;
618 i -= 1;
715619
716 pub fn firstToken(self: &NodePointerPayload) Token {
717 return self.lpipe;
718 }
620 return null;
621 }
719622
720 pub fn lastToken(self: &NodePointerPayload) Token {
721 return self.rpipe;
722 }
723};
623 pub fn firstToken(self: &Payload) Token {
624 return self.lpipe;
625 }
724626
725pub const NodePointerIndexPayload = struct {
726 base: Node,
727 lpipe: Token,
728 is_ptr: bool,
729 value_symbol: &NodeIdentifier,
730 index_symbol: ?&NodeIdentifier,
731 rpipe: Token,
627 pub fn lastToken(self: &Payload) Token {
628 return self.rpipe;
629 }
630 };
732631
733 pub fn iterate(self: &NodePointerIndexPayload, index: usize) ?&Node {
734 var i = index;
632 pub const PointerPayload = struct {
633 base: Node,
634 lpipe: Token,
635 ptr_token: ?Token,
636 value_symbol: &Node,
637 rpipe: Token,
735638
736 if (i < 1) return &self.value_symbol.base;
737 i -= 1;
639 pub fn iterate(self: &PointerPayload, index: usize) ?&Node {
640 var i = index;
738641
739 if (self.index_symbol) |index_symbol| {
740 if (i < 1) return &index_symbol.base;
642 if (i < 1) return self.value_symbol;
741643 i -= 1;
742 }
743644
744 return null;
745 }
645 return null;
646 }
746647
747 pub fn firstToken(self: &NodePointerIndexPayload) Token {
748 return self.lpipe;
749 }
648 pub fn firstToken(self: &PointerPayload) Token {
649 return self.lpipe;
650 }
750651
751 pub fn lastToken(self: &NodePointerIndexPayload) Token {
752 return self.rpipe;
753 }
754};
652 pub fn lastToken(self: &PointerPayload) Token {
653 return self.rpipe;
654 }
655 };
755656
756pub const NodeElse = struct {
757 base: Node,
758 else_token: Token,
759 payload: ?&NodePayload,
760 body: &Node,
657 pub const PointerIndexPayload = struct {
658 base: Node,
659 lpipe: Token,
660 ptr_token: ?Token,
661 value_symbol: &Node,
662 index_symbol: ?&Node,
663 rpipe: Token,
761664
762 pub fn iterate(self: &NodeElse, index: usize) ?&Node {
763 var i = index;
665 pub fn iterate(self: &PointerIndexPayload, index: usize) ?&Node {
666 var i = index;
764667
765 if (self.payload) |payload| {
766 if (i < 1) return &payload.base;
668 if (i < 1) return self.value_symbol;
767669 i -= 1;
768 }
769670
770 if (i < 1) return self.body;
771 i -= 1;
772
773 return null;
774 }
671 if (self.index_symbol) |index_symbol| {
672 if (i < 1) return index_symbol;
673 i -= 1;
674 }
775675
776 pub fn firstToken(self: &NodeElse) Token {
777 return self.else_token;
778 }
676 return null;
677 }
779678
780 pub fn lastToken(self: &NodeElse) Token {
781 return self.body.lastToken();
782 }
783};
679 pub fn firstToken(self: &PointerIndexPayload) Token {
680 return self.lpipe;
681 }
784682
785pub const NodeSwitch = struct {
786 base: Node,
787 switch_token: Token,
788 expr: &Node,
789 cases: ArrayList(&NodeSwitchCase),
790 rbrace: Token,
683 pub fn lastToken(self: &PointerIndexPayload) Token {
684 return self.rpipe;
685 }
686 };
791687
792 pub fn iterate(self: &NodeSwitch, index: usize) ?&Node {
793 var i = index;
688 pub const Else = struct {
689 base: Node,
690 else_token: Token,
691 payload: ?&Node,
692 body: &Node,
794693
795 if (i < 1) return self.expr;
796 i -= 1;
694 pub fn iterate(self: &Else, index: usize) ?&Node {
695 var i = index;
797696
798 if (i < self.cases.len) return &self.cases.at(i).base;
799 i -= self.cases.len;
697 if (self.payload) |payload| {
698 if (i < 1) return payload;
699 i -= 1;
700 }
800701
801 return null;
802 }
702 if (i < 1) return self.body;
703 i -= 1;
803704
804 pub fn firstToken(self: &NodeSwitch) Token {
805 return self.switch_token;
806 }
705 return null;
706 }
807707
808 pub fn lastToken(self: &NodeSwitch) Token {
809 return self.rbrace;
810 }
811};
708 pub fn firstToken(self: &Else) Token {
709 return self.else_token;
710 }
812711
813pub const NodeSwitchCase = struct {
814 base: Node,
815 items: ArrayList(&Node),
816 payload: ?&NodePointerPayload,
817 expr: &Node,
712 pub fn lastToken(self: &Else) Token {
713 return self.body.lastToken();
714 }
715 };
818716
819 pub fn iterate(self: &NodeSwitchCase, index: usize) ?&Node {
820 var i = index;
717 pub const Switch = struct {
718 base: Node,
719 switch_token: Token,
720 expr: &Node,
721 cases: ArrayList(&SwitchCase),
722 rbrace: Token,
821723
822 if (i < self.items.len) return self.items.at(i);
823 i -= self.items.len;
724 pub fn iterate(self: &Switch, index: usize) ?&Node {
725 var i = index;
824726
825 if (self.payload) |payload| {
826 if (i < 1) return &payload.base;
727 if (i < 1) return self.expr;
827728 i -= 1;
828 }
829729
830 if (i < 1) return self.expr;
831 i -= 1;
730 if (i < self.cases.len) return &self.cases.at(i).base;
731 i -= self.cases.len;
832732
833 return null;
834 }
733 return null;
734 }
835735
836 pub fn firstToken(self: &NodeSwitchCase) Token {
837 return self.items.at(0).firstToken();
838 }
736 pub fn firstToken(self: &Switch) Token {
737 return self.switch_token;
738 }
839739
840 pub fn lastToken(self: &NodeSwitchCase) Token {
841 return self.expr.lastToken();
842 }
843};
740 pub fn lastToken(self: &Switch) Token {
741 return self.rbrace;
742 }
743 };
844744
845pub const NodeSwitchElse = struct {
846 base: Node,
847 token: Token,
745 pub const SwitchCase = struct {
746 base: Node,
747 items: ArrayList(&Node),
748 payload: ?&Node,
749 expr: &Node,
848750
849 pub fn iterate(self: &NodeSwitchElse, index: usize) ?&Node {
850 return null;
851 }
751 pub fn iterate(self: &SwitchCase, index: usize) ?&Node {
752 var i = index;
852753
853 pub fn firstToken(self: &NodeSwitchElse) Token {
854 return self.token;
855 }
754 if (i < self.items.len) return self.items.at(i);
755 i -= self.items.len;
856756
857 pub fn lastToken(self: &NodeSwitchElse) Token {
858 return self.token;
859 }
860};
757 if (self.payload) |payload| {
758 if (i < 1) return payload;
759 i -= 1;
760 }
861761
862pub const NodeWhile = struct {
863 base: Node,
864 label: ?Token,
865 inline_token: ?Token,
866 while_token: Token,
867 condition: &Node,
868 payload: ?&NodePointerPayload,
869 continue_expr: ?&Node,
870 body: &Node,
871 @"else": ?&NodeElse,
872
873 pub fn iterate(self: &NodeWhile, index: usize) ?&Node {
874 var i = index;
875
876 if (i < 1) return self.condition;
877 i -= 1;
878
879 if (self.payload) |payload| {
880 if (i < 1) return &payload.base;
762 if (i < 1) return self.expr;
881763 i -= 1;
882 }
883764
884 if (self.continue_expr) |continue_expr| {
885 if (i < 1) return continue_expr;
886 i -= 1;
765 return null;
887766 }
888767
889 if (i < 1) return self.body;
890 i -= 1;
768 pub fn firstToken(self: &SwitchCase) Token {
769 return self.items.at(0).firstToken();
770 }
891771
892 if (self.@"else") |@"else"| {
893 if (i < 1) return &@"else".base;
894 i -= 1;
772 pub fn lastToken(self: &SwitchCase) Token {
773 return self.expr.lastToken();
895774 }
775 };
896776
897 return null;
898 }
777 pub const SwitchElse = struct {
778 base: Node,
779 token: Token,
899780
900 pub fn firstToken(self: &NodeWhile) Token {
901 if (self.label) |label| {
902 return label;
781 pub fn iterate(self: &SwitchElse, index: usize) ?&Node {
782 return null;
903783 }
904784
905 if (self.inline_token) |inline_token| {
906 return inline_token;
785 pub fn firstToken(self: &SwitchElse) Token {
786 return self.token;
907787 }
908788
909 return self.while_token;
910 }
911
912 pub fn lastToken(self: &NodeWhile) Token {
913 if (self.@"else") |@"else"| {
914 return @"else".body.lastToken();
789 pub fn lastToken(self: &SwitchElse) Token {
790 return self.token;
915791 }
792 };
916793
917 return self.body.lastToken();
918 }
919};
920
921pub const NodeFor = struct {
922 base: Node,
923 label: ?Token,
924 inline_token: ?Token,
925 for_token: Token,
926 array_expr: &Node,
927 payload: ?&NodePointerIndexPayload,
928 body: &Node,
929 @"else": ?&NodeElse,
794 pub const While = struct {
795 base: Node,
796 label: ?Token,
797 inline_token: ?Token,
798 while_token: Token,
799 condition: &Node,
800 payload: ?&Node,
801 continue_expr: ?&Node,
802 body: &Node,
803 @"else": ?&Else,
804
805 pub fn iterate(self: &While, index: usize) ?&Node {
806 var i = index;
807
808 if (i < 1) return self.condition;
809 i -= 1;
930810
931 pub fn iterate(self: &NodeFor, index: usize) ?&Node {
932 var i = index;
811 if (self.payload) |payload| {
812 if (i < 1) return payload;
813 i -= 1;
814 }
933815
934 if (i < 1) return self.array_expr;
935 i -= 1;
816 if (self.continue_expr) |continue_expr| {
817 if (i < 1) return continue_expr;
818 i -= 1;
819 }
936820
937 if (self.payload) |payload| {
938 if (i < 1) return &payload.base;
821 if (i < 1) return self.body;
939822 i -= 1;
823
824 if (self.@"else") |@"else"| {
825 if (i < 1) return &@"else".base;
826 i -= 1;
827 }
828
829 return null;
940830 }
941831
942 if (i < 1) return self.body;
943 i -= 1;
832 pub fn firstToken(self: &While) Token {
833 if (self.label) |label| {
834 return label;
835 }
944836
945 if (self.@"else") |@"else"| {
946 if (i < 1) return &@"else".base;
947 i -= 1;
837 if (self.inline_token) |inline_token| {
838 return inline_token;
839 }
840
841 return self.while_token;
948842 }
949843
950 return null;
951 }
844 pub fn lastToken(self: &While) Token {
845 if (self.@"else") |@"else"| {
846 return @"else".body.lastToken();
847 }
952848
953 pub fn firstToken(self: &NodeFor) Token {
954 if (self.label) |label| {
955 return label;
849 return self.body.lastToken();
956850 }
851 };
852
853 pub const For = struct {
854 base: Node,
855 label: ?Token,
856 inline_token: ?Token,
857 for_token: Token,
858 array_expr: &Node,
859 payload: ?&Node,
860 body: &Node,
861 @"else": ?&Else,
862
863 pub fn iterate(self: &For, index: usize) ?&Node {
864 var i = index;
865
866 if (i < 1) return self.array_expr;
867 i -= 1;
868
869 if (self.payload) |payload| {
870 if (i < 1) return payload;
871 i -= 1;
872 }
873
874 if (i < 1) return self.body;
875 i -= 1;
876
877 if (self.@"else") |@"else"| {
878 if (i < 1) return &@"else".base;
879 i -= 1;
880 }
957881
958 if (self.inline_token) |inline_token| {
959 return inline_token;
882 return null;
960883 }
961884
962 return self.for_token;
963 }
885 pub fn firstToken(self: &For) Token {
886 if (self.label) |label| {
887 return label;
888 }
889
890 if (self.inline_token) |inline_token| {
891 return inline_token;
892 }
964893
965 pub fn lastToken(self: &NodeFor) Token {
966 if (self.@"else") |@"else"| {
967 return @"else".body.lastToken();
894 return self.for_token;
968895 }
969896
970 return self.body.lastToken();
971 }
972};
897 pub fn lastToken(self: &For) Token {
898 if (self.@"else") |@"else"| {
899 return @"else".body.lastToken();
900 }
973901
974pub const NodeIf = struct {
975 base: Node,
976 if_token: Token,
977 condition: &Node,
978 payload: ?&NodePointerPayload,
979 body: &Node,
980 @"else": ?&NodeElse,
902 return self.body.lastToken();
903 }
904 };
981905
982 pub fn iterate(self: &NodeIf, index: usize) ?&Node {
983 var i = index;
906 pub const If = struct {
907 base: Node,
908 if_token: Token,
909 condition: &Node,
910 payload: ?&Node,
911 body: &Node,
912 @"else": ?&Else,
984913
985 if (i < 1) return self.condition;
986 i -= 1;
914 pub fn iterate(self: &If, index: usize) ?&Node {
915 var i = index;
987916
988 if (self.payload) |payload| {
989 if (i < 1) return &payload.base;
917 if (i < 1) return self.condition;
990918 i -= 1;
991 }
992919
993 if (i < 1) return self.body;
994 i -= 1;
920 if (self.payload) |payload| {
921 if (i < 1) return payload;
922 i -= 1;
923 }
995924
996 if (self.@"else") |@"else"| {
997 if (i < 1) return &@"else".base;
925 if (i < 1) return self.body;
998926 i -= 1;
999 }
1000927
1001 return null;
1002 }
928 if (self.@"else") |@"else"| {
929 if (i < 1) return &@"else".base;
930 i -= 1;
931 }
1003932
1004 pub fn firstToken(self: &NodeIf) Token {
1005 return self.if_token;
1006 }
933 return null;
934 }
1007935
1008 pub fn lastToken(self: &NodeIf) Token {
1009 if (self.@"else") |@"else"| {
1010 return @"else".body.lastToken();
936 pub fn firstToken(self: &If) Token {
937 return self.if_token;
1011938 }
1012939
1013 return self.body.lastToken();
1014 }
1015};
940 pub fn lastToken(self: &If) Token {
941 if (self.@"else") |@"else"| {
942 return @"else".body.lastToken();
943 }
1016944
1017pub const NodeInfixOp = struct {
1018 base: Node,
1019 op_token: Token,
1020 lhs: &Node,
1021 op: InfixOp,
1022 rhs: &Node,
1023
1024 const InfixOp = union(enum) {
1025 Add,
1026 AddWrap,
1027 ArrayCat,
1028 ArrayMult,
1029 Assign,
1030 AssignBitAnd,
1031 AssignBitOr,
1032 AssignBitShiftLeft,
1033 AssignBitShiftRight,
1034 AssignBitXor,
1035 AssignDiv,
1036 AssignMinus,
1037 AssignMinusWrap,
1038 AssignMod,
1039 AssignPlus,
1040 AssignPlusWrap,
1041 AssignTimes,
1042 AssignTimesWarp,
1043 BangEqual,
1044 BitAnd,
1045 BitOr,
1046 BitShiftLeft,
1047 BitShiftRight,
1048 BitXor,
1049 BoolAnd,
1050 BoolOr,
1051 Catch: ?&NodePayload,
1052 Div,
1053 EqualEqual,
1054 ErrorUnion,
1055 GreaterOrEqual,
1056 GreaterThan,
1057 LessOrEqual,
1058 LessThan,
1059 MergeErrorSets,
1060 Mod,
1061 Mult,
1062 MultWrap,
1063 Period,
1064 Range,
1065 Sub,
1066 SubWrap,
1067 UnwrapMaybe,
945 return self.body.lastToken();
946 }
1068947 };
1069948
1070 pub fn iterate(self: &NodeInfixOp, index: usize) ?&Node {
1071 var i = index;
949 pub const InfixOp = struct {
950 base: Node,
951 op_token: Token,
952 lhs: &Node,
953 op: Op,
954 rhs: &Node,
955
956 pub const Op = union(enum) {
957 Add,
958 AddWrap,
959 ArrayCat,
960 ArrayMult,
961 Assign,
962 AssignBitAnd,
963 AssignBitOr,
964 AssignBitShiftLeft,
965 AssignBitShiftRight,
966 AssignBitXor,
967 AssignDiv,
968 AssignMinus,
969 AssignMinusWrap,
970 AssignMod,
971 AssignPlus,
972 AssignPlusWrap,
973 AssignTimes,
974 AssignTimesWarp,
975 BangEqual,
976 BitAnd,
977 BitOr,
978 BitShiftLeft,
979 BitShiftRight,
980 BitXor,
981 BoolAnd,
982 BoolOr,
983 Catch: ?&Node,
984 Div,
985 EqualEqual,
986 ErrorUnion,
987 GreaterOrEqual,
988 GreaterThan,
989 LessOrEqual,
990 LessThan,
991 MergeErrorSets,
992 Mod,
993 Mult,
994 MultWrap,
995 Period,
996 Range,
997 Sub,
998 SubWrap,
999 UnwrapMaybe,
1000 };
10721001
1073 if (i < 1) return self.lhs;
1074 i -= 1;
1002 pub fn iterate(self: &InfixOp, index: usize) ?&Node {
1003 var i = index;
10751004
1076 switch (self.op) {
1077 InfixOp.Catch => |maybe_payload| {
1078 if (maybe_payload) |payload| {
1079 if (i < 1) return &payload.base;
1080 i -= 1;
1081 }
1082 },
1083
1084 InfixOp.Add,
1085 InfixOp.AddWrap,
1086 InfixOp.ArrayCat,
1087 InfixOp.ArrayMult,
1088 InfixOp.Assign,
1089 InfixOp.AssignBitAnd,
1090 InfixOp.AssignBitOr,
1091 InfixOp.AssignBitShiftLeft,
1092 InfixOp.AssignBitShiftRight,
1093 InfixOp.AssignBitXor,
1094 InfixOp.AssignDiv,
1095 InfixOp.AssignMinus,
1096 InfixOp.AssignMinusWrap,
1097 InfixOp.AssignMod,
1098 InfixOp.AssignPlus,
1099 InfixOp.AssignPlusWrap,
1100 InfixOp.AssignTimes,
1101 InfixOp.AssignTimesWarp,
1102 InfixOp.BangEqual,
1103 InfixOp.BitAnd,
1104 InfixOp.BitOr,
1105 InfixOp.BitShiftLeft,
1106 InfixOp.BitShiftRight,
1107 InfixOp.BitXor,
1108 InfixOp.BoolAnd,
1109 InfixOp.BoolOr,
1110 InfixOp.Div,
1111 InfixOp.EqualEqual,
1112 InfixOp.ErrorUnion,
1113 InfixOp.GreaterOrEqual,
1114 InfixOp.GreaterThan,
1115 InfixOp.LessOrEqual,
1116 InfixOp.LessThan,
1117 InfixOp.MergeErrorSets,
1118 InfixOp.Mod,
1119 InfixOp.Mult,
1120 InfixOp.MultWrap,
1121 InfixOp.Period,
1122 InfixOp.Range,
1123 InfixOp.Sub,
1124 InfixOp.SubWrap,
1125 InfixOp.UnwrapMaybe => {},
1126 }
1127
1128 if (i < 1) return self.rhs;
1129 i -= 1;
1130
1131 return null;
1132 }
1005 if (i < 1) return self.lhs;
1006 i -= 1;
11331007
1134 pub fn firstToken(self: &NodeInfixOp) Token {
1135 return self.lhs.firstToken();
1136 }
1008 switch (self.op) {
1009 Op.Catch => |maybe_payload| {
1010 if (maybe_payload) |payload| {
1011 if (i < 1) return payload;
1012 i -= 1;
1013 }
1014 },
1015
1016 Op.Add,
1017 Op.AddWrap,
1018 Op.ArrayCat,
1019 Op.ArrayMult,
1020 Op.Assign,
1021 Op.AssignBitAnd,
1022 Op.AssignBitOr,
1023 Op.AssignBitShiftLeft,
1024 Op.AssignBitShiftRight,
1025 Op.AssignBitXor,
1026 Op.AssignDiv,
1027 Op.AssignMinus,
1028 Op.AssignMinusWrap,
1029 Op.AssignMod,
1030 Op.AssignPlus,
1031 Op.AssignPlusWrap,
1032 Op.AssignTimes,
1033 Op.AssignTimesWarp,
1034 Op.BangEqual,
1035 Op.BitAnd,
1036 Op.BitOr,
1037 Op.BitShiftLeft,
1038 Op.BitShiftRight,
1039 Op.BitXor,
1040 Op.BoolAnd,
1041 Op.BoolOr,
1042 Op.Div,
1043 Op.EqualEqual,
1044 Op.ErrorUnion,
1045 Op.GreaterOrEqual,
1046 Op.GreaterThan,
1047 Op.LessOrEqual,
1048 Op.LessThan,
1049 Op.MergeErrorSets,
1050 Op.Mod,
1051 Op.Mult,
1052 Op.MultWrap,
1053 Op.Period,
1054 Op.Range,
1055 Op.Sub,
1056 Op.SubWrap,
1057 Op.UnwrapMaybe => {},
1058 }
11371059
1138 pub fn lastToken(self: &NodeInfixOp) Token {
1139 return self.rhs.lastToken();
1140 }
1141};
1060 if (i < 1) return self.rhs;
1061 i -= 1;
11421062
1143pub const NodePrefixOp = struct {
1144 base: Node,
1145 op_token: Token,
1146 op: PrefixOp,
1147 rhs: &Node,
1148
1149 const PrefixOp = union(enum) {
1150 AddrOf: AddrOfInfo,
1151 ArrayType: &Node,
1152 Await,
1153 BitNot,
1154 BoolNot,
1155 Cancel,
1156 Deref,
1157 MaybeType,
1158 Negation,
1159 NegationWrap,
1160 Resume,
1161 SliceType: AddrOfInfo,
1162 Try,
1163 UnwrapMaybe,
1164 };
1063 return null;
1064 }
11651065
1166 const AddrOfInfo = struct {
1167 align_expr: ?&Node,
1168 bit_offset_start_token: ?Token,
1169 bit_offset_end_token: ?Token,
1170 const_token: ?Token,
1171 volatile_token: ?Token,
1066 pub fn firstToken(self: &InfixOp) Token {
1067 return self.lhs.firstToken();
1068 }
1069
1070 pub fn lastToken(self: &InfixOp) Token {
1071 return self.rhs.lastToken();
1072 }
11721073 };
11731074
1174 pub fn iterate(self: &NodePrefixOp, index: usize) ?&Node {
1175 var i = index;
1075 pub const PrefixOp = struct {
1076 base: Node,
1077 op_token: Token,
1078 op: Op,
1079 rhs: &Node,
1080
1081 const Op = union(enum) {
1082 AddrOf: AddrOfInfo,
1083 ArrayType: &Node,
1084 Await,
1085 BitNot,
1086 BoolNot,
1087 Cancel,
1088 Deref,
1089 MaybeType,
1090 Negation,
1091 NegationWrap,
1092 Resume,
1093 SliceType: AddrOfInfo,
1094 Try,
1095 UnwrapMaybe,
1096 };
1097
1098 const AddrOfInfo = struct {
1099 align_expr: ?&Node,
1100 bit_offset_start_token: ?Token,
1101 bit_offset_end_token: ?Token,
1102 const_token: ?Token,
1103 volatile_token: ?Token,
1104 };
11761105
1177 switch (self.op) {
1178 PrefixOp.SliceType => |addr_of_info| {
1179 if (addr_of_info.align_expr) |align_expr| {
1180 if (i < 1) return align_expr;
1106 pub fn iterate(self: &PrefixOp, index: usize) ?&Node {
1107 var i = index;
1108
1109 switch (self.op) {
1110 Op.SliceType => |addr_of_info| {
1111 if (addr_of_info.align_expr) |align_expr| {
1112 if (i < 1) return align_expr;
1113 i -= 1;
1114 }
1115 },
1116 Op.AddrOf => |addr_of_info| {
1117 if (addr_of_info.align_expr) |align_expr| {
1118 if (i < 1) return align_expr;
1119 i -= 1;
1120 }
1121 },
1122 Op.ArrayType => |size_expr| {
1123 if (i < 1) return size_expr;
11811124 i -= 1;
1182 }
1183 },
1184 PrefixOp.AddrOf => |addr_of_info| {
1185 if (addr_of_info.align_expr) |align_expr| {
1186 if (i < 1) return align_expr;
1187 i -= 1;
1188 }
1189 },
1190 PrefixOp.ArrayType => |size_expr| {
1191 if (i < 1) return size_expr;
1192 i -= 1;
1193 },
1194 PrefixOp.Await,
1195 PrefixOp.BitNot,
1196 PrefixOp.BoolNot,
1197 PrefixOp.Cancel,
1198 PrefixOp.Deref,
1199 PrefixOp.MaybeType,
1200 PrefixOp.Negation,
1201 PrefixOp.NegationWrap,
1202 PrefixOp.Try,
1203 PrefixOp.Resume,
1204 PrefixOp.UnwrapMaybe => {},
1205 }
1206
1207 if (i < 1) return self.rhs;
1208 i -= 1;
1209
1210 return null;
1211 }
1125 },
1126 Op.Await,
1127 Op.BitNot,
1128 Op.BoolNot,
1129 Op.Cancel,
1130 Op.Deref,
1131 Op.MaybeType,
1132 Op.Negation,
1133 Op.NegationWrap,
1134 Op.Try,
1135 Op.Resume,
1136 Op.UnwrapMaybe => {},
1137 }
12121138
1213 pub fn firstToken(self: &NodePrefixOp) Token {
1214 return self.op_token;
1215 }
1139 if (i < 1) return self.rhs;
1140 i -= 1;
12161141
1217 pub fn lastToken(self: &NodePrefixOp) Token {
1218 return self.rhs.lastToken();
1219 }
1220};
1142 return null;
1143 }
12211144
1222pub const NodeFieldInitializer = struct {
1223 base: Node,
1224 period_token: Token,
1225 name_token: Token,
1226 expr: &Node,
1145 pub fn firstToken(self: &PrefixOp) Token {
1146 return self.op_token;
1147 }
12271148
1228 pub fn iterate(self: &NodeFieldInitializer, index: usize) ?&Node {
1229 var i = index;
1149 pub fn lastToken(self: &PrefixOp) Token {
1150 return self.rhs.lastToken();
1151 }
1152 };
12301153
1231 if (i < 1) return self.expr;
1232 i -= 1;
1154 pub const FieldInitializer = struct {
1155 base: Node,
1156 period_token: Token,
1157 name_token: Token,
1158 expr: &Node,
12331159
1234 return null;
1235 }
1160 pub fn iterate(self: &FieldInitializer, index: usize) ?&Node {
1161 var i = index;
12361162
1237 pub fn firstToken(self: &NodeFieldInitializer) Token {
1238 return self.period_token;
1239 }
1163 if (i < 1) return self.expr;
1164 i -= 1;
12401165
1241 pub fn lastToken(self: &NodeFieldInitializer) Token {
1242 return self.expr.lastToken();
1243 }
1244};
1166 return null;
1167 }
12451168
1246pub const NodeSuffixOp = struct {
1247 base: Node,
1248 lhs: &Node,
1249 op: SuffixOp,
1250 rtoken: Token,
1251
1252 const SuffixOp = union(enum) {
1253 Call: CallInfo,
1254 ArrayAccess: &Node,
1255 Slice: SliceRange,
1256 ArrayInitializer: ArrayList(&Node),
1257 StructInitializer: ArrayList(&NodeFieldInitializer),
1258 };
1169 pub fn firstToken(self: &FieldInitializer) Token {
1170 return self.period_token;
1171 }
12591172
1260 const CallInfo = struct {
1261 params: ArrayList(&Node),
1262 async_attr: ?&NodeAsyncAttribute,
1173 pub fn lastToken(self: &FieldInitializer) Token {
1174 return self.expr.lastToken();
1175 }
12631176 };
12641177
1265 const SliceRange = struct {
1266 start: &Node,
1267 end: ?&Node,
1268 };
1178 pub const SuffixOp = struct {
1179 base: Node,
1180 lhs: &Node,
1181 op: Op,
1182 rtoken: Token,
1183
1184 const Op = union(enum) {
1185 Call: CallInfo,
1186 ArrayAccess: &Node,
1187 Slice: SliceRange,
1188 ArrayInitializer: ArrayList(&Node),
1189 StructInitializer: ArrayList(&FieldInitializer),
1190 };
1191
1192 const CallInfo = struct {
1193 params: ArrayList(&Node),
1194 async_attr: ?&AsyncAttribute,
1195 };
12691196
1270 pub fn iterate(self: &NodeSuffixOp, index: usize) ?&Node {
1271 var i = index;
1197 const SliceRange = struct {
1198 start: &Node,
1199 end: ?&Node,
1200 };
12721201
1273 if (i < 1) return self.lhs;
1274 i -= 1;
1202 pub fn iterate(self: &SuffixOp, index: usize) ?&Node {
1203 var i = index;
12751204
1276 switch (self.op) {
1277 SuffixOp.Call => |call_info| {
1278 if (i < call_info.params.len) return call_info.params.at(i);
1279 i -= call_info.params.len;
1280 },
1281 SuffixOp.ArrayAccess => |index_expr| {
1282 if (i < 1) return index_expr;
1283 i -= 1;
1284 },
1285 SuffixOp.Slice => |range| {
1286 if (i < 1) return range.start;
1287 i -= 1;
1205 if (i < 1) return self.lhs;
1206 i -= 1;
12881207
1289 if (range.end) |end| {
1290 if (i < 1) return end;
1208 switch (self.op) {
1209 Op.Call => |call_info| {
1210 if (i < call_info.params.len) return call_info.params.at(i);
1211 i -= call_info.params.len;
1212 },
1213 Op.ArrayAccess => |index_expr| {
1214 if (i < 1) return index_expr;
1215 i -= 1;
1216 },
1217 Op.Slice => |range| {
1218 if (i < 1) return range.start;
12911219 i -= 1;
1292 }
1293 },
1294 SuffixOp.ArrayInitializer => |exprs| {
1295 if (i < exprs.len) return exprs.at(i);
1296 i -= exprs.len;
1297 },
1298 SuffixOp.StructInitializer => |fields| {
1299 if (i < fields.len) return &fields.at(i).base;
1300 i -= fields.len;
1301 },
1302 }
1303
1304 return null;
1305 }
13061220
1307 pub fn firstToken(self: &NodeSuffixOp) Token {
1308 return self.lhs.firstToken();
1309 }
1221 if (range.end) |end| {
1222 if (i < 1) return end;
1223 i -= 1;
1224 }
1225 },
1226 Op.ArrayInitializer => |exprs| {
1227 if (i < exprs.len) return exprs.at(i);
1228 i -= exprs.len;
1229 },
1230 Op.StructInitializer => |fields| {
1231 if (i < fields.len) return &fields.at(i).base;
1232 i -= fields.len;
1233 },
1234 }
13101235
1311 pub fn lastToken(self: &NodeSuffixOp) Token {
1312 return self.rtoken;
1313 }
1314};
1236 return null;
1237 }
13151238
1316pub const NodeGroupedExpression = struct {
1317 base: Node,
1318 lparen: Token,
1319 expr: &Node,
1320 rparen: Token,
1239 pub fn firstToken(self: &SuffixOp) Token {
1240 return self.lhs.firstToken();
1241 }
13211242
1322 pub fn iterate(self: &NodeGroupedExpression, index: usize) ?&Node {
1323 var i = index;
1243 pub fn lastToken(self: &SuffixOp) Token {
1244 return self.rtoken;
1245 }
1246 };
13241247
1325 if (i < 1) return self.expr;
1326 i -= 1;
1248 pub const GroupedExpression = struct {
1249 base: Node,
1250 lparen: Token,
1251 expr: &Node,
1252 rparen: Token,
13271253
1328 return null;
1329 }
1254 pub fn iterate(self: &GroupedExpression, index: usize) ?&Node {
1255 var i = index;
13301256
1331 pub fn firstToken(self: &NodeGroupedExpression) Token {
1332 return self.lparen;
1333 }
1257 if (i < 1) return self.expr;
1258 i -= 1;
13341259
1335 pub fn lastToken(self: &NodeGroupedExpression) Token {
1336 return self.rparen;
1337 }
1338};
1260 return null;
1261 }
13391262
1340pub const NodeControlFlowExpression = struct {
1341 base: Node,
1342 ltoken: Token,
1343 kind: Kind,
1344 rhs: ?&Node,
1263 pub fn firstToken(self: &GroupedExpression) Token {
1264 return self.lparen;
1265 }
13451266
1346 const Kind = union(enum) {
1347 Break: ?Token,
1348 Continue: ?Token,
1349 Return,
1267 pub fn lastToken(self: &GroupedExpression) Token {
1268 return self.rparen;
1269 }
13501270 };
13511271
1352 pub fn iterate(self: &NodeControlFlowExpression, index: usize) ?&Node {
1353 var i = index;
1272 pub const ControlFlowExpression = struct {
1273 base: Node,
1274 ltoken: Token,
1275 kind: Kind,
1276 rhs: ?&Node,
13541277
1355 if (self.rhs) |rhs| {
1356 if (i < 1) return rhs;
1357 i -= 1;
1358 }
1278 const Kind = union(enum) {
1279 Break: ?&Node,
1280 Continue: ?&Node,
1281 Return,
1282 };
13591283
1360 return null;
1361 }
1284 pub fn iterate(self: &ControlFlowExpression, index: usize) ?&Node {
1285 var i = index;
1286
1287 switch (self.kind) {
1288 Kind.Break => |maybe_label| {
1289 if (maybe_label) |label| {
1290 if (i < 1) return label;
1291 i -= 1;
1292 }
1293 },
1294 Kind.Continue => |maybe_label| {
1295 if (maybe_label) |label| {
1296 if (i < 1) return label;
1297 i -= 1;
1298 }
1299 },
1300 Kind.Return => {},
1301 }
13621302
1363 pub fn firstToken(self: &NodeControlFlowExpression) Token {
1364 return self.ltoken;
1365 }
1303 if (self.rhs) |rhs| {
1304 if (i < 1) return rhs;
1305 i -= 1;
1306 }
13661307
1367 pub fn lastToken(self: &NodeControlFlowExpression) Token {
1368 if (self.rhs) |rhs| {
1369 return rhs.lastToken();
1308 return null;
13701309 }
13711310
1372 switch (self.kind) {
1373 Kind.Break => |maybe_blk_token| {
1374 if (maybe_blk_token) |blk_token| {
1375 return blk_token;
1376 }
1377 },
1378 Kind.Continue => |maybe_blk_token| {
1379 if (maybe_blk_token) |blk_token| {
1380 return blk_token;
1381 }
1382 },
1383 Kind.Return => return self.ltoken,
1311 pub fn firstToken(self: &ControlFlowExpression) Token {
1312 return self.ltoken;
13841313 }
13851314
1386 return self.ltoken;
1387 }
1388};
1389
1390pub const NodeSuspend = struct {
1391 base: Node,
1392 suspend_token: Token,
1393 payload: ?&NodePayload,
1394 body: ?&Node,
1315 pub fn lastToken(self: &ControlFlowExpression) Token {
1316 if (self.rhs) |rhs| {
1317 return rhs.lastToken();
1318 }
13951319
1396 pub fn iterate(self: &NodeSuspend, index: usize) ?&Node {
1397 var i = index;
1320 switch (self.kind) {
1321 Kind.Break => |maybe_label| {
1322 if (maybe_label) |label| {
1323 return label.lastToken();
1324 }
1325 },
1326 Kind.Continue => |maybe_label| {
1327 if (maybe_label) |label| {
1328 return label.lastToken();
1329 }
1330 },
1331 Kind.Return => return self.ltoken,
1332 }
13981333
1399 if (self.payload) |payload| {
1400 if (i < 1) return &payload.base;
1401 i -= 1;
1334 return self.ltoken;
14021335 }
1336 };
14031337
1404 if (self.body) |body| {
1405 if (i < 1) return body;
1406 i -= 1;
1407 }
1338 pub const Suspend = struct {
1339 base: Node,
1340 suspend_token: Token,
1341 payload: ?&Node,
1342 body: ?&Node,
14081343
1409 return null;
1410 }
1344 pub fn iterate(self: &Suspend, index: usize) ?&Node {
1345 var i = index;
14111346
1412 pub fn firstToken(self: &NodeSuspend) Token {
1413 return self.suspend_token;
1414 }
1347 if (self.payload) |payload| {
1348 if (i < 1) return payload;
1349 i -= 1;
1350 }
14151351
1416 pub fn lastToken(self: &NodeSuspend) Token {
1417 if (self.body) |body| {
1418 return body.lastToken();
1352 if (self.body) |body| {
1353 if (i < 1) return body;
1354 i -= 1;
1355 }
1356
1357 return null;
14191358 }
14201359
1421 if (self.payload) |payload| {
1422 return payload.lastToken();
1360 pub fn firstToken(self: &Suspend) Token {
1361 return self.suspend_token;
14231362 }
14241363
1425 return self.suspend_token;
1426 }
1427};
1364 pub fn lastToken(self: &Suspend) Token {
1365 if (self.body) |body| {
1366 return body.lastToken();
1367 }
14281368
1429pub const NodeIntegerLiteral = struct {
1430 base: Node,
1431 token: Token,
1369 if (self.payload) |payload| {
1370 return payload.lastToken();
1371 }
14321372
1433 pub fn iterate(self: &NodeIntegerLiteral, index: usize) ?&Node {
1434 return null;
1435 }
1373 return self.suspend_token;
1374 }
1375 };
14361376
1437 pub fn firstToken(self: &NodeIntegerLiteral) Token {
1438 return self.token;
1439 }
1377 pub const IntegerLiteral = struct {
1378 base: Node,
1379 token: Token,
14401380
1441 pub fn lastToken(self: &NodeIntegerLiteral) Token {
1442 return self.token;
1443 }
1444};
1381 pub fn iterate(self: &IntegerLiteral, index: usize) ?&Node {
1382 return null;
1383 }
14451384
1446pub const NodeFloatLiteral = struct {
1447 base: Node,
1448 token: Token,
1385 pub fn firstToken(self: &IntegerLiteral) Token {
1386 return self.token;
1387 }
14491388
1450 pub fn iterate(self: &NodeFloatLiteral, index: usize) ?&Node {
1451 return null;
1452 }
1389 pub fn lastToken(self: &IntegerLiteral) Token {
1390 return self.token;
1391 }
1392 };
14531393
1454 pub fn firstToken(self: &NodeFloatLiteral) Token {
1455 return self.token;
1456 }
1394 pub const FloatLiteral = struct {
1395 base: Node,
1396 token: Token,
14571397
1458 pub fn lastToken(self: &NodeFloatLiteral) Token {
1459 return self.token;
1460 }
1461};
1398 pub fn iterate(self: &FloatLiteral, index: usize) ?&Node {
1399 return null;
1400 }
14621401
1463pub const NodeBuiltinCall = struct {
1464 base: Node,
1465 builtin_token: Token,
1466 params: ArrayList(&Node),
1467 rparen_token: Token,
1402 pub fn firstToken(self: &FloatLiteral) Token {
1403 return self.token;
1404 }
14681405
1469 pub fn iterate(self: &NodeBuiltinCall, index: usize) ?&Node {
1470 var i = index;
1406 pub fn lastToken(self: &FloatLiteral) Token {
1407 return self.token;
1408 }
1409 };
14711410
1472 if (i < self.params.len) return self.params.at(i);
1473 i -= self.params.len;
1411 pub const BuiltinCall = struct {
1412 base: Node,
1413 builtin_token: Token,
1414 params: ArrayList(&Node),
1415 rparen_token: Token,
14741416
1475 return null;
1476 }
1417 pub fn iterate(self: &BuiltinCall, index: usize) ?&Node {
1418 var i = index;
14771419
1478 pub fn firstToken(self: &NodeBuiltinCall) Token {
1479 return self.builtin_token;
1480 }
1420 if (i < self.params.len) return self.params.at(i);
1421 i -= self.params.len;
14811422
1482 pub fn lastToken(self: &NodeBuiltinCall) Token {
1483 return self.rparen_token;
1484 }
1485};
1423 return null;
1424 }
14861425
1487pub const NodeStringLiteral = struct {
1488 base: Node,
1489 token: Token,
1426 pub fn firstToken(self: &BuiltinCall) Token {
1427 return self.builtin_token;
1428 }
14901429
1491 pub fn iterate(self: &NodeStringLiteral, index: usize) ?&Node {
1492 return null;
1493 }
1430 pub fn lastToken(self: &BuiltinCall) Token {
1431 return self.rparen_token;
1432 }
1433 };
14941434
1495 pub fn firstToken(self: &NodeStringLiteral) Token {
1496 return self.token;
1497 }
1435 pub const StringLiteral = struct {
1436 base: Node,
1437 token: Token,
14981438
1499 pub fn lastToken(self: &NodeStringLiteral) Token {
1500 return self.token;
1501 }
1502};
1439 pub fn iterate(self: &StringLiteral, index: usize) ?&Node {
1440 return null;
1441 }
15031442
1504pub const NodeMultilineStringLiteral = struct {
1505 base: Node,
1506 tokens: ArrayList(Token),
1443 pub fn firstToken(self: &StringLiteral) Token {
1444 return self.token;
1445 }
15071446
1508 pub fn iterate(self: &NodeMultilineStringLiteral, index: usize) ?&Node {
1509 return null;
1510 }
1447 pub fn lastToken(self: &StringLiteral) Token {
1448 return self.token;
1449 }
1450 };
15111451
1512 pub fn firstToken(self: &NodeMultilineStringLiteral) Token {
1513 return self.tokens.at(0);
1514 }
1452 pub const MultilineStringLiteral = struct {
1453 base: Node,
1454 tokens: ArrayList(Token),
15151455
1516 pub fn lastToken(self: &NodeMultilineStringLiteral) Token {
1517 return self.tokens.at(self.tokens.len - 1);
1518 }
1519};
1456 pub fn iterate(self: &MultilineStringLiteral, index: usize) ?&Node {
1457 return null;
1458 }
15201459
1521pub const NodeCharLiteral = struct {
1522 base: Node,
1523 token: Token,
1460 pub fn firstToken(self: &MultilineStringLiteral) Token {
1461 return self.tokens.at(0);
1462 }
15241463
1525 pub fn iterate(self: &NodeCharLiteral, index: usize) ?&Node {
1526 return null;
1527 }
1464 pub fn lastToken(self: &MultilineStringLiteral) Token {
1465 return self.tokens.at(self.tokens.len - 1);
1466 }
1467 };
15281468
1529 pub fn firstToken(self: &NodeCharLiteral) Token {
1530 return self.token;
1531 }
1469 pub const CharLiteral = struct {
1470 base: Node,
1471 token: Token,
15321472
1533 pub fn lastToken(self: &NodeCharLiteral) Token {
1534 return self.token;
1535 }
1536};
1473 pub fn iterate(self: &CharLiteral, index: usize) ?&Node {
1474 return null;
1475 }
15371476
1538pub const NodeBoolLiteral = struct {
1539 base: Node,
1540 token: Token,
1477 pub fn firstToken(self: &CharLiteral) Token {
1478 return self.token;
1479 }
15411480
1542 pub fn iterate(self: &NodeBoolLiteral, index: usize) ?&Node {
1543 return null;
1544 }
1481 pub fn lastToken(self: &CharLiteral) Token {
1482 return self.token;
1483 }
1484 };
15451485
1546 pub fn firstToken(self: &NodeBoolLiteral) Token {
1547 return self.token;
1548 }
1486 pub const BoolLiteral = struct {
1487 base: Node,
1488 token: Token,
15491489
1550 pub fn lastToken(self: &NodeBoolLiteral) Token {
1551 return self.token;
1552 }
1553};
1490 pub fn iterate(self: &BoolLiteral, index: usize) ?&Node {
1491 return null;
1492 }
15541493
1555pub const NodeNullLiteral = struct {
1556 base: Node,
1557 token: Token,
1494 pub fn firstToken(self: &BoolLiteral) Token {
1495 return self.token;
1496 }
15581497
1559 pub fn iterate(self: &NodeNullLiteral, index: usize) ?&Node {
1560 return null;
1561 }
1498 pub fn lastToken(self: &BoolLiteral) Token {
1499 return self.token;
1500 }
1501 };
15621502
1563 pub fn firstToken(self: &NodeNullLiteral) Token {
1564 return self.token;
1565 }
1503 pub const NullLiteral = struct {
1504 base: Node,
1505 token: Token,
15661506
1567 pub fn lastToken(self: &NodeNullLiteral) Token {
1568 return self.token;
1569 }
1570};
1507 pub fn iterate(self: &NullLiteral, index: usize) ?&Node {
1508 return null;
1509 }
15711510
1572pub const NodeUndefinedLiteral = struct {
1573 base: Node,
1574 token: Token,
1511 pub fn firstToken(self: &NullLiteral) Token {
1512 return self.token;
1513 }
15751514
1576 pub fn iterate(self: &NodeUndefinedLiteral, index: usize) ?&Node {
1577 return null;
1578 }
1515 pub fn lastToken(self: &NullLiteral) Token {
1516 return self.token;
1517 }
1518 };
15791519
1580 pub fn firstToken(self: &NodeUndefinedLiteral) Token {
1581 return self.token;
1582 }
1520 pub const UndefinedLiteral = struct {
1521 base: Node,
1522 token: Token,
15831523
1584 pub fn lastToken(self: &NodeUndefinedLiteral) Token {
1585 return self.token;
1586 }
1587};
1524 pub fn iterate(self: &UndefinedLiteral, index: usize) ?&Node {
1525 return null;
1526 }
15881527
1589pub const NodeThisLiteral = struct {
1590 base: Node,
1591 token: Token,
1528 pub fn firstToken(self: &UndefinedLiteral) Token {
1529 return self.token;
1530 }
15921531
1593 pub fn iterate(self: &NodeThisLiteral, index: usize) ?&Node {
1594 return null;
1595 }
1532 pub fn lastToken(self: &UndefinedLiteral) Token {
1533 return self.token;
1534 }
1535 };
15961536
1597 pub fn firstToken(self: &NodeThisLiteral) Token {
1598 return self.token;
1599 }
1537 pub const ThisLiteral = struct {
1538 base: Node,
1539 token: Token,
16001540
1601 pub fn lastToken(self: &NodeThisLiteral) Token {
1602 return self.token;
1603 }
1604};
1541 pub fn iterate(self: &ThisLiteral, index: usize) ?&Node {
1542 return null;
1543 }
16051544
1606pub const NodeAsmOutput = struct {
1607 base: Node,
1608 symbolic_name: &NodeIdentifier,
1609 constraint: &Node,
1610 kind: Kind,
1545 pub fn firstToken(self: &ThisLiteral) Token {
1546 return self.token;
1547 }
16111548
1612 const Kind = union(enum) {
1613 Variable: &NodeIdentifier,
1614 Return: &Node
1549 pub fn lastToken(self: &ThisLiteral) Token {
1550 return self.token;
1551 }
16151552 };
16161553
1617 pub fn iterate(self: &NodeAsmOutput, index: usize) ?&Node {
1618 var i = index;
1554 pub const AsmOutput = struct {
1555 base: Node,
1556 symbolic_name: &Node,
1557 constraint: &Node,
1558 kind: Kind,
16191559
1620 if (i < 1) return &self.symbolic_name.base;
1621 i -= 1;
1560 const Kind = union(enum) {
1561 Variable: &Identifier,
1562 Return: &Node
1563 };
16221564
1623 if (i < 1) return self.constraint;
1624 i -= 1;
1565 pub fn iterate(self: &AsmOutput, index: usize) ?&Node {
1566 var i = index;
16251567
1626 switch (self.kind) {
1627 Kind.Variable => |variable_name| {
1628 if (i < 1) return &variable_name.base;
1629 i -= 1;
1630 },
1631 Kind.Return => |return_type| {
1632 if (i < 1) return return_type;
1633 i -= 1;
1568 if (i < 1) return self.symbolic_name;
1569 i -= 1;
1570
1571 if (i < 1) return self.constraint;
1572 i -= 1;
1573
1574 switch (self.kind) {
1575 Kind.Variable => |variable_name| {
1576 if (i < 1) return &variable_name.base;
1577 i -= 1;
1578 },
1579 Kind.Return => |return_type| {
1580 if (i < 1) return return_type;
1581 i -= 1;
1582 }
16341583 }
1635 }
16361584
1637 return null;
1638 }
1585 return null;
1586 }
16391587
1640 pub fn firstToken(self: &NodeAsmOutput) Token {
1641 return self.symbolic_name.firstToken();
1642 }
1588 pub fn firstToken(self: &AsmOutput) Token {
1589 return self.symbolic_name.firstToken();
1590 }
16431591
1644 pub fn lastToken(self: &NodeAsmOutput) Token {
1645 return switch (self.kind) {
1646 Kind.Variable => |variable_name| variable_name.lastToken(),
1647 Kind.Return => |return_type| return_type.lastToken(),
1648 };
1649 }
1650};
1592 pub fn lastToken(self: &AsmOutput) Token {
1593 return switch (self.kind) {
1594 Kind.Variable => |variable_name| variable_name.lastToken(),
1595 Kind.Return => |return_type| return_type.lastToken(),
1596 };
1597 }
1598 };
16511599
1652pub const NodeAsmInput = struct {
1653 base: Node,
1654 symbolic_name: &NodeIdentifier,
1655 constraint: &Node,
1656 expr: &Node,
1600 pub const AsmInput = struct {
1601 base: Node,
1602 symbolic_name: &Node,
1603 constraint: &Node,
1604 expr: &Node,
16571605
1658 pub fn iterate(self: &NodeAsmInput, index: usize) ?&Node {
1659 var i = index;
1606 pub fn iterate(self: &AsmInput, index: usize) ?&Node {
1607 var i = index;
16601608
1661 if (i < 1) return &self.symbolic_name.base;
1662 i -= 1;
1609 if (i < 1) return self.symbolic_name;
1610 i -= 1;
16631611
1664 if (i < 1) return self.constraint;
1665 i -= 1;
1612 if (i < 1) return self.constraint;
1613 i -= 1;
16661614
1667 if (i < 1) return self.expr;
1668 i -= 1;
1615 if (i < 1) return self.expr;
1616 i -= 1;
16691617
1670 return null;
1671 }
1618 return null;
1619 }
16721620
1673 pub fn firstToken(self: &NodeAsmInput) Token {
1674 return self.symbolic_name.firstToken();
1675 }
1621 pub fn firstToken(self: &AsmInput) Token {
1622 return self.symbolic_name.firstToken();
1623 }
16761624
1677 pub fn lastToken(self: &NodeAsmInput) Token {
1678 return self.expr.lastToken();
1679 }
1680};
1625 pub fn lastToken(self: &AsmInput) Token {
1626 return self.expr.lastToken();
1627 }
1628 };
16811629
1682pub const NodeAsm = struct {
1683 base: Node,
1684 asm_token: Token,
1685 is_volatile: bool,
1686 template: &Node,
1687 //tokens: ArrayList(AsmToken),
1688 outputs: ArrayList(&NodeAsmOutput),
1689 inputs: ArrayList(&NodeAsmInput),
1690 cloppers: ArrayList(&Node),
1691 rparen: Token,
1630 pub const Asm = struct {
1631 base: Node,
1632 asm_token: Token,
1633 volatile_token: ?Token,
1634 template: &Node,
1635 //tokens: ArrayList(AsmToken),
1636 outputs: ArrayList(&AsmOutput),
1637 inputs: ArrayList(&AsmInput),
1638 cloppers: ArrayList(&Node),
1639 rparen: Token,
16921640
1693 pub fn iterate(self: &NodeAsm, index: usize) ?&Node {
1694 var i = index;
1641 pub fn iterate(self: &Asm, index: usize) ?&Node {
1642 var i = index;
16951643
1696 if (i < self.outputs.len) return &self.outputs.at(index).base;
1697 i -= self.outputs.len;
1644 if (i < self.outputs.len) return &self.outputs.at(index).base;
1645 i -= self.outputs.len;
16981646
1699 if (i < self.inputs.len) return &self.inputs.at(index).base;
1700 i -= self.inputs.len;
1647 if (i < self.inputs.len) return &self.inputs.at(index).base;
1648 i -= self.inputs.len;
17011649
1702 if (i < self.cloppers.len) return self.cloppers.at(index);
1703 i -= self.cloppers.len;
1650 if (i < self.cloppers.len) return self.cloppers.at(index);
1651 i -= self.cloppers.len;
17041652
1705 return null;
1706 }
1653 return null;
1654 }
17071655
1708 pub fn firstToken(self: &NodeAsm) Token {
1709 return self.asm_token;
1710 }
1656 pub fn firstToken(self: &Asm) Token {
1657 return self.asm_token;
1658 }
17111659
1712 pub fn lastToken(self: &NodeAsm) Token {
1713 return self.rparen;
1714 }
1715};
1660 pub fn lastToken(self: &Asm) Token {
1661 return self.rparen;
1662 }
1663 };
17161664
1717pub const NodeUnreachable = struct {
1718 base: Node,
1719 token: Token,
1665 pub const Unreachable = struct {
1666 base: Node,
1667 token: Token,
17201668
1721 pub fn iterate(self: &NodeUnreachable, index: usize) ?&Node {
1722 return null;
1723 }
1669 pub fn iterate(self: &Unreachable, index: usize) ?&Node {
1670 return null;
1671 }
17241672
1725 pub fn firstToken(self: &NodeUnreachable) Token {
1726 return self.token;
1727 }
1673 pub fn firstToken(self: &Unreachable) Token {
1674 return self.token;
1675 }
17281676
1729 pub fn lastToken(self: &NodeUnreachable) Token {
1730 return self.token;
1731 }
1732};
1677 pub fn lastToken(self: &Unreachable) Token {
1678 return self.token;
1679 }
1680 };
17331681
1734pub const NodeErrorType = struct {
1735 base: Node,
1736 token: Token,
1682 pub const ErrorType = struct {
1683 base: Node,
1684 token: Token,
17371685
1738 pub fn iterate(self: &NodeErrorType, index: usize) ?&Node {
1739 return null;
1740 }
1686 pub fn iterate(self: &ErrorType, index: usize) ?&Node {
1687 return null;
1688 }
17411689
1742 pub fn firstToken(self: &NodeErrorType) Token {
1743 return self.token;
1744 }
1690 pub fn firstToken(self: &ErrorType) Token {
1691 return self.token;
1692 }
17451693
1746 pub fn lastToken(self: &NodeErrorType) Token {
1747 return self.token;
1748 }
1749};
1694 pub fn lastToken(self: &ErrorType) Token {
1695 return self.token;
1696 }
1697 };
17501698
1751pub const NodeVarType = struct {
1752 base: Node,
1753 token: Token,
1699 pub const VarType = struct {
1700 base: Node,
1701 token: Token,
17541702
1755 pub fn iterate(self: &NodeVarType, index: usize) ?&Node {
1756 return null;
1757 }
1703 pub fn iterate(self: &VarType, index: usize) ?&Node {
1704 return null;
1705 }
17581706
1759 pub fn firstToken(self: &NodeVarType) Token {
1760 return self.token;
1761 }
1707 pub fn firstToken(self: &VarType) Token {
1708 return self.token;
1709 }
17621710
1763 pub fn lastToken(self: &NodeVarType) Token {
1764 return self.token;
1765 }
1766};
1711 pub fn lastToken(self: &VarType) Token {
1712 return self.token;
1713 }
1714 };
17671715
1768pub const NodeLineComment = struct {
1769 base: Node,
1770 lines: ArrayList(Token),
1716 pub const LineComment = struct {
1717 base: Node,
1718 lines: ArrayList(Token),
17711719
1772 pub fn iterate(self: &NodeLineComment, index: usize) ?&Node {
1773 return null;
1774 }
1720 pub fn iterate(self: &LineComment, index: usize) ?&Node {
1721 return null;
1722 }
17751723
1776 pub fn firstToken(self: &NodeLineComment) Token {
1777 return self.lines.at(0);
1778 }
1724 pub fn firstToken(self: &LineComment) Token {
1725 return self.lines.at(0);
1726 }
17791727
1780 pub fn lastToken(self: &NodeLineComment) Token {
1781 return self.lines.at(self.lines.len - 1);
1782 }
1783};
1728 pub fn lastToken(self: &LineComment) Token {
1729 return self.lines.at(self.lines.len - 1);
1730 }
1731 };
17841732
1785pub const NodeTestDecl = struct {
1786 base: Node,
1787 test_token: Token,
1788 name: &Node,
1789 body_node: &Node,
1733 pub const TestDecl = struct {
1734 base: Node,
1735 comments: ?&LineComment,
1736 test_token: Token,
1737 name: &Node,
1738 body_node: &Node,
17901739
1791 pub fn iterate(self: &NodeTestDecl, index: usize) ?&Node {
1792 var i = index;
1740 pub fn iterate(self: &TestDecl, index: usize) ?&Node {
1741 var i = index;
17931742
1794 if (i < 1) return self.body_node;
1795 i -= 1;
1743 if (i < 1) return self.body_node;
1744 i -= 1;
17961745
1797 return null;
1798 }
1746 return null;
1747 }
17991748
1800 pub fn firstToken(self: &NodeTestDecl) Token {
1801 return self.test_token;
1802 }
1749 pub fn firstToken(self: &TestDecl) Token {
1750 return self.test_token;
1751 }
18031752
1804 pub fn lastToken(self: &NodeTestDecl) Token {
1805 return self.body_node.lastToken();
1806 }
1753 pub fn lastToken(self: &TestDecl) Token {
1754 return self.body_node.lastToken();
1755 }
1756 };
18071757};
1758
std/zig/parser.zig+2360-2275
......@@ -18,10 +18,9 @@ pub const Parser = struct {
1818 put_back_tokens: [2]Token,
1919 put_back_count: usize,
2020 source_file_name: []const u8,
21 pending_line_comment_node: ?&ast.NodeLineComment,
2221
2322 pub const Tree = struct {
24 root_node: &ast.NodeRoot,
23 root_node: &ast.Node.Root,
2524 arena_allocator: std.heap.ArenaAllocator,
2625
2726 pub fn deinit(self: &Tree) void {
......@@ -44,7 +43,6 @@ pub const Parser = struct {
4443 .put_back_count = 0,
4544 .source_file_name = source_file_name,
4645 .utility_bytes = []align(utility_bytes_align) u8{},
47 .pending_line_comment_node = null,
4846 };
4947 }
5048
......@@ -59,29 +57,31 @@ pub const Parser = struct {
5957 lib_name: ?&ast.Node,
6058 };
6159
62 const ContainerExternCtx = struct {
63 dest_ptr: DestPtr,
64 ltoken: Token,
65 layout: ast.NodeContainerDecl.Layout,
60 const VarDeclCtx = struct {
61 mut_token: Token,
62 visib_token: ?Token,
63 comptime_token: ?Token,
64 extern_export_token: ?Token,
65 lib_name: ?&ast.Node,
66 list: &ArrayList(&ast.Node),
67 comments: ?&ast.Node.LineComment,
6668 };
6769
68 const DestPtr = union(enum) {
69 Field: &&ast.Node,
70 NullableField: &?&ast.Node,
70 const TopLevelExternOrFieldCtx = struct {
71 visib_token: Token,
72 container_decl: &ast.Node.ContainerDecl,
73 };
7174
72 pub fn store(self: &const DestPtr, value: &ast.Node) void {
73 switch (*self) {
74 DestPtr.Field => |ptr| *ptr = value,
75 DestPtr.NullableField => |ptr| *ptr = value,
76 }
77 }
75 const ExternTypeCtx = struct {
76 opt_ctx: OptionalCtx,
77 extern_token: Token,
78 comments: ?&ast.Node.LineComment,
79 };
7880
79 pub fn get(self: &const DestPtr) &ast.Node {
80 switch (*self) {
81 DestPtr.Field => |ptr| return *ptr,
82 DestPtr.NullableField => |ptr| return ??*ptr,
83 }
84 }
81 const ContainerKindCtx = struct {
82 opt_ctx: OptionalCtx,
83 ltoken: Token,
84 layout: ast.Node.ContainerDecl.Layout,
8585 };
8686
8787 const ExpectTokenSave = struct {
......@@ -89,13 +89,9 @@ pub const Parser = struct {
8989 ptr: &Token,
9090 };
9191
92 const RevertState = struct {
93 parser: Parser,
94 tokenizer: Tokenizer,
95
96 // We expect, that if something is optional, then there is a field,
97 // that needs to be set to null, when we revert.
98 ptr: &?&ast.Node,
92 const OptionalTokenSave = struct {
93 id: Token.Id,
94 ptr: &?Token,
9995 };
10096
10197 const ExprListCtx = struct {
......@@ -104,11 +100,6 @@ pub const Parser = struct {
104100 ptr: &Token,
105101 };
106102
107 const ElseCtx = struct {
108 payload: ?DestPtr,
109 body: DestPtr,
110 };
111
112103 fn ListSave(comptime T: type) type {
113104 return struct {
114105 list: &ArrayList(T),
......@@ -116,27 +107,79 @@ pub const Parser = struct {
116107 };
117108 }
118109
110 const MaybeLabeledExpressionCtx = struct {
111 label: Token,
112 opt_ctx: OptionalCtx,
113 };
114
119115 const LabelCtx = struct {
120116 label: ?Token,
121 dest_ptr: DestPtr,
117 opt_ctx: OptionalCtx,
122118 };
123119
124120 const InlineCtx = struct {
125121 label: ?Token,
126122 inline_token: ?Token,
127 dest_ptr: DestPtr,
123 opt_ctx: OptionalCtx,
128124 };
129125
130126 const LoopCtx = struct {
131127 label: ?Token,
132128 inline_token: ?Token,
133129 loop_token: Token,
134 dest_ptr: DestPtr,
130 opt_ctx: OptionalCtx,
135131 };
136132
137133 const AsyncEndCtx = struct {
138 dest_ptr: DestPtr,
139 attribute: &ast.NodeAsyncAttribute,
134 ctx: OptionalCtx,
135 attribute: &ast.Node.AsyncAttribute,
136 };
137
138 const ErrorTypeOrSetDeclCtx = struct {
139 opt_ctx: OptionalCtx,
140 error_token: Token,
141 };
142
143 const ParamDeclEndCtx = struct {
144 fn_proto: &ast.Node.FnProto,
145 param_decl: &ast.Node.ParamDecl,
146 };
147
148 const ComptimeStatementCtx = struct {
149 comptime_token: Token,
150 block: &ast.Node.Block,
151 };
152
153 const OptionalCtx = union(enum) {
154 Optional: &?&ast.Node,
155 RequiredNull: &?&ast.Node,
156 Required: &&ast.Node,
157
158 pub fn store(self: &const OptionalCtx, value: &ast.Node) void {
159 switch (*self) {
160 OptionalCtx.Optional => |ptr| *ptr = value,
161 OptionalCtx.RequiredNull => |ptr| *ptr = value,
162 OptionalCtx.Required => |ptr| *ptr = value,
163 }
164 }
165
166 pub fn get(self: &const OptionalCtx) ?&ast.Node {
167 switch (*self) {
168 OptionalCtx.Optional => |ptr| return *ptr,
169 OptionalCtx.RequiredNull => |ptr| return ??*ptr,
170 OptionalCtx.Required => |ptr| return *ptr,
171 }
172 }
173
174 pub fn toRequired(self: &const OptionalCtx) OptionalCtx {
175 switch (*self) {
176 OptionalCtx.Optional => |ptr| {
177 return OptionalCtx { .RequiredNull = ptr };
178 },
179 OptionalCtx.RequiredNull => |ptr| return *self,
180 OptionalCtx.Required => |ptr| return *self,
181 }
182 }
140183 };
141184
142185 const State = union(enum) {
......@@ -144,92 +187,116 @@ pub const Parser = struct {
144187 TopLevelExtern: TopLevelDeclCtx,
145188 TopLevelLibname: TopLevelDeclCtx,
146189 TopLevelDecl: TopLevelDeclCtx,
147 ContainerExtern: ContainerExternCtx,
148 ContainerDecl: &ast.NodeContainerDecl,
149 SliceOrArrayAccess: &ast.NodeSuffixOp,
150 AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo,
151 VarDecl: &ast.NodeVarDecl,
152 VarDeclAlign: &ast.NodeVarDecl,
153 VarDeclEq: &ast.NodeVarDecl,
154 IfToken: @TagType(Token.Id),
155 IfTokenSave: ExpectTokenSave,
156 ExpectToken: @TagType(Token.Id),
157 ExpectTokenSave: ExpectTokenSave,
158 FnProto: &ast.NodeFnProto,
159 FnProtoAlign: &ast.NodeFnProto,
160 FnProtoReturnType: &ast.NodeFnProto,
161 ParamDecl: &ast.NodeFnProto,
162 ParamDeclComma,
163 FnDef: &ast.NodeFnProto,
190 TopLevelExternOrField: TopLevelExternOrFieldCtx,
191
192 ContainerKind: ContainerKindCtx,
193 ContainerInitArgStart: &ast.Node.ContainerDecl,
194 ContainerInitArg: &ast.Node.ContainerDecl,
195 ContainerDecl: &ast.Node.ContainerDecl,
196
197 VarDecl: VarDeclCtx,
198 VarDeclAlign: &ast.Node.VarDecl,
199 VarDeclEq: &ast.Node.VarDecl,
200
201 FnDef: &ast.Node.FnProto,
202 FnProto: &ast.Node.FnProto,
203 FnProtoAlign: &ast.Node.FnProto,
204 FnProtoReturnType: &ast.Node.FnProto,
205
206 ParamDecl: &ast.Node.FnProto,
207 ParamDeclAliasOrComptime: &ast.Node.ParamDecl,
208 ParamDeclName: &ast.Node.ParamDecl,
209 ParamDeclEnd: ParamDeclEndCtx,
210 ParamDeclComma: &ast.Node.FnProto,
211
212 MaybeLabeledExpression: MaybeLabeledExpressionCtx,
164213 LabeledExpression: LabelCtx,
165214 Inline: InlineCtx,
166215 While: LoopCtx,
167 For: LoopCtx,
168 Block: &ast.NodeBlock,
169 Else: &?&ast.NodeElse,
170216 WhileContinueExpr: &?&ast.Node,
171 Statement: &ast.NodeBlock,
172 Semicolon: &const &const ast.Node,
173 AsmOutputItems: &ArrayList(&ast.NodeAsmOutput),
174 AsmInputItems: &ArrayList(&ast.NodeAsmInput),
217 For: LoopCtx,
218 Else: &?&ast.Node.Else,
219
220 Block: &ast.Node.Block,
221 Statement: &ast.Node.Block,
222 ComptimeStatement: ComptimeStatementCtx,
223 Semicolon: &&ast.Node,
224
225 AsmOutputItems: &ArrayList(&ast.Node.AsmOutput),
226 AsmOutputReturnOrType: &ast.Node.AsmOutput,
227 AsmInputItems: &ArrayList(&ast.Node.AsmInput),
175228 AsmClopperItems: &ArrayList(&ast.Node),
229
176230 ExprListItemOrEnd: ExprListCtx,
177231 ExprListCommaOrEnd: ExprListCtx,
178 FieldInitListItemOrEnd: ListSave(&ast.NodeFieldInitializer),
179 FieldInitListCommaOrEnd: ListSave(&ast.NodeFieldInitializer),
180 FieldListCommaOrEnd: &ast.NodeContainerDecl,
181 IdentifierListItemOrEnd: ListSave(&ast.NodeIdentifier),
182 IdentifierListCommaOrEnd: ListSave(&ast.NodeIdentifier),
183 SwitchCaseOrEnd: ListSave(&ast.NodeSwitchCase),
184 SuspendBody: &ast.NodeSuspend,
185 AsyncEnd: AsyncEndCtx,
186 Payload: &?&ast.NodePayload,
187 PointerPayload: &?&ast.NodePointerPayload,
188 PointerIndexPayload: &?&ast.NodePointerIndexPayload,
189 SwitchCaseCommaOrEnd: ListSave(&ast.NodeSwitchCase),
232 FieldInitListItemOrEnd: ListSave(&ast.Node.FieldInitializer),
233 FieldInitListCommaOrEnd: ListSave(&ast.Node.FieldInitializer),
234 FieldListCommaOrEnd: &ast.Node.ContainerDecl,
235 IdentifierListItemOrEnd: ListSave(&ast.Node),
236 IdentifierListCommaOrEnd: ListSave(&ast.Node),
237 SwitchCaseOrEnd: ListSave(&ast.Node.SwitchCase),
238 SwitchCaseCommaOrEnd: ListSave(&ast.Node.SwitchCase),
239 SwitchCaseFirstItem: &ArrayList(&ast.Node),
190240 SwitchCaseItem: &ArrayList(&ast.Node),
191241 SwitchCaseItemCommaOrEnd: &ArrayList(&ast.Node),
192242
193 /// A state that can be appended before any other State. If an error occures,
194 /// the parser will first try looking for the closest optional state. If an
195 /// optional state is found, the parser will revert to the state it was in
196 /// when the optional was added. This will polute the arena allocator with
197 /// "leaked" nodes. TODO: Figure out if it's nessesary to handle leaked nodes.
198 Optional: RevertState,
199
200 Expression: DestPtr,
201 RangeExpressionBegin: DestPtr,
202 RangeExpressionEnd: DestPtr,
203 AssignmentExpressionBegin: DestPtr,
204 AssignmentExpressionEnd: DestPtr,
205 UnwrapExpressionBegin: DestPtr,
206 UnwrapExpressionEnd: DestPtr,
207 BoolOrExpressionBegin: DestPtr,
208 BoolOrExpressionEnd: DestPtr,
209 BoolAndExpressionBegin: DestPtr,
210 BoolAndExpressionEnd: DestPtr,
211 ComparisonExpressionBegin: DestPtr,
212 ComparisonExpressionEnd: DestPtr,
213 BinaryOrExpressionBegin: DestPtr,
214 BinaryOrExpressionEnd: DestPtr,
215 BinaryXorExpressionBegin: DestPtr,
216 BinaryXorExpressionEnd: DestPtr,
217 BinaryAndExpressionBegin: DestPtr,
218 BinaryAndExpressionEnd: DestPtr,
219 BitShiftExpressionBegin: DestPtr,
220 BitShiftExpressionEnd: DestPtr,
221 AdditionExpressionBegin: DestPtr,
222 AdditionExpressionEnd: DestPtr,
223 MultiplyExpressionBegin: DestPtr,
224 MultiplyExpressionEnd: DestPtr,
225 CurlySuffixExpressionBegin: DestPtr,
226 CurlySuffixExpressionEnd: DestPtr,
227 TypeExprBegin: DestPtr,
228 TypeExprEnd: DestPtr,
229 PrefixOpExpression: DestPtr,
230 SuffixOpExpressionBegin: DestPtr,
231 SuffixOpExpressionEnd: DestPtr,
232 PrimaryExpression: DestPtr,
243 SuspendBody: &ast.Node.Suspend,
244 AsyncAllocator: &ast.Node.AsyncAttribute,
245 AsyncEnd: AsyncEndCtx,
246
247 ExternType: ExternTypeCtx,
248 SliceOrArrayAccess: &ast.Node.SuffixOp,
249 SliceOrArrayType: &ast.Node.PrefixOp,
250 AddrOfModifiers: &ast.Node.PrefixOp.AddrOfInfo,
251
252 Payload: OptionalCtx,
253 PointerPayload: OptionalCtx,
254 PointerIndexPayload: OptionalCtx,
255
256 Expression: OptionalCtx,
257 RangeExpressionBegin: OptionalCtx,
258 RangeExpressionEnd: OptionalCtx,
259 AssignmentExpressionBegin: OptionalCtx,
260 AssignmentExpressionEnd: OptionalCtx,
261 UnwrapExpressionBegin: OptionalCtx,
262 UnwrapExpressionEnd: OptionalCtx,
263 BoolOrExpressionBegin: OptionalCtx,
264 BoolOrExpressionEnd: OptionalCtx,
265 BoolAndExpressionBegin: OptionalCtx,
266 BoolAndExpressionEnd: OptionalCtx,
267 ComparisonExpressionBegin: OptionalCtx,
268 ComparisonExpressionEnd: OptionalCtx,
269 BinaryOrExpressionBegin: OptionalCtx,
270 BinaryOrExpressionEnd: OptionalCtx,
271 BinaryXorExpressionBegin: OptionalCtx,
272 BinaryXorExpressionEnd: OptionalCtx,
273 BinaryAndExpressionBegin: OptionalCtx,
274 BinaryAndExpressionEnd: OptionalCtx,
275 BitShiftExpressionBegin: OptionalCtx,
276 BitShiftExpressionEnd: OptionalCtx,
277 AdditionExpressionBegin: OptionalCtx,
278 AdditionExpressionEnd: OptionalCtx,
279 MultiplyExpressionBegin: OptionalCtx,
280 MultiplyExpressionEnd: OptionalCtx,
281 CurlySuffixExpressionBegin: OptionalCtx,
282 CurlySuffixExpressionEnd: OptionalCtx,
283 TypeExprBegin: OptionalCtx,
284 TypeExprEnd: OptionalCtx,
285 PrefixOpExpression: OptionalCtx,
286 SuffixOpExpressionBegin: OptionalCtx,
287 SuffixOpExpressionEnd: OptionalCtx,
288 PrimaryExpression: OptionalCtx,
289
290 ErrorTypeOrSetDecl: ErrorTypeOrSetDeclCtx,
291 StringLiteral: OptionalCtx,
292 Identifier: OptionalCtx,
293
294
295 IfToken: @TagType(Token.Id),
296 IfTokenSave: ExpectTokenSave,
297 ExpectToken: @TagType(Token.Id),
298 ExpectTokenSave: ExpectTokenSave,
299 OptionalTokenSave: OptionalTokenSave,
233300 };
234301
235302 /// Returns an AST tree, allocated with the parser's allocator.
......@@ -243,8 +310,8 @@ pub const Parser = struct {
243310 errdefer arena_allocator.deinit();
244311
245312 const arena = &arena_allocator.allocator;
246 const root_node = try self.createNode(arena, ast.NodeRoot,
247 ast.NodeRoot {
313 const root_node = try self.createNode(arena, ast.Node.Root,
314 ast.Node.Root {
248315 .base = undefined,
249316 .decls = ArrayList(&ast.Node).init(arena),
250317 // initialized when we get the eof token
......@@ -267,66 +334,43 @@ pub const Parser = struct {
267334 // warn("\n");
268335 //}
269336
270 // look for line comments
271 while (true) {
272 if (self.eatToken(Token.Id.LineComment)) |line_comment| {
273 const node = blk: {
274 if (self.pending_line_comment_node) |comment_node| {
275 break :blk comment_node;
276 } else {
277 const comment_node = try arena.create(ast.NodeLineComment);
278 *comment_node = ast.NodeLineComment {
279 .base = ast.Node {
280 .id = ast.Node.Id.LineComment,
281 .comment = null,
282 },
283 .lines = ArrayList(Token).init(arena),
284 };
285 self.pending_line_comment_node = comment_node;
286 break :blk comment_node;
287 }
288 };
289 try node.lines.append(line_comment);
290 continue;
291 }
292 break;
293 }
294
295337 // This gives us 1 free append that can't fail
296338 const state = stack.pop();
297339
298340 switch (state) {
299341 State.TopLevel => {
342 const comments = try self.eatComments(arena);
300343 const token = self.getNextToken();
301344 switch (token.id) {
302345 Token.Id.Keyword_test => {
303346 stack.append(State.TopLevel) catch unreachable;
304347
305 const name_token = self.getNextToken();
306 const name = (try self.parseStringLiteral(arena, name_token)) ?? {
307 try self.parseError(&stack, name_token, "expected string literal, found {}", @tagName(name_token.id));
308 continue;
309 };
310 const lbrace = (try self.expectToken(&stack, Token.Id.LBrace)) ?? continue;
311
312 const block = try self.createNode(arena, ast.NodeBlock,
313 ast.NodeBlock {
348 const block = try self.createNode(arena, ast.Node.Block,
349 ast.Node.Block {
314350 .base = undefined,
315351 .label = null,
316 .lbrace = lbrace,
352 .lbrace = undefined,
317353 .statements = ArrayList(&ast.Node).init(arena),
318354 .rbrace = undefined,
319355 }
320356 );
321 _ = try self.createAttachNode(arena, &root_node.decls, ast.NodeTestDecl,
322 ast.NodeTestDecl {
357 const test_node = try self.createAttachNode(arena, &root_node.decls, ast.Node.TestDecl,
358 ast.Node.TestDecl {
323359 .base = undefined,
360 .comments = comments,
324361 .test_token = token,
325 .name = name,
362 .name = undefined,
326363 .body_node = &block.base,
327364 }
328365 );
329366 stack.append(State { .Block = block }) catch unreachable;
367 try stack.append(State {
368 .ExpectTokenSave = ExpectTokenSave {
369 .id = Token.Id.LBrace,
370 .ptr = &block.rbrace,
371 }
372 });
373 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &test_node.name } });
330374 continue;
331375 },
332376 Token.Id.Eof => {
......@@ -346,15 +390,30 @@ pub const Parser = struct {
346390 continue;
347391 },
348392 Token.Id.Keyword_comptime => {
349 const node = try self.createAttachNode(arena, &root_node.decls, ast.NodeComptime,
350 ast.NodeComptime {
393 const block = try self.createNode(arena, ast.Node.Block,
394 ast.Node.Block {
395 .base = undefined,
396 .label = null,
397 .lbrace = undefined,
398 .statements = ArrayList(&ast.Node).init(arena),
399 .rbrace = undefined,
400 }
401 );
402 const node = try self.createAttachNode(arena, &root_node.decls, ast.Node.Comptime,
403 ast.Node.Comptime {
351404 .base = undefined,
352405 .comptime_token = token,
353 .expr = undefined,
406 .expr = &block.base,
354407 }
355408 );
356409 stack.append(State.TopLevel) catch unreachable;
357 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
410 try stack.append(State { .Block = block });
411 try stack.append(State {
412 .ExpectTokenSave = ExpectTokenSave {
413 .id = Token.Id.LBrace,
414 .ptr = &block.rbrace,
415 }
416 });
358417 continue;
359418 },
360419 else => {
......@@ -404,7 +463,6 @@ pub const Parser = struct {
404463 }
405464 }
406465 },
407
408466 State.TopLevelLibname => |ctx| {
409467 const lib_name = blk: {
410468 const lib_name_token = self.getNextToken();
......@@ -422,19 +480,19 @@ pub const Parser = struct {
422480 .lib_name = lib_name,
423481 },
424482 }) catch unreachable;
483 continue;
425484 },
426
427485 State.TopLevelDecl => |ctx| {
486 const comments = try self.eatComments(arena);
428487 const token = self.getNextToken();
429488 switch (token.id) {
430489 Token.Id.Keyword_use => {
431490 if (ctx.extern_export_inline_token != null) {
432 try self.parseError(&stack, token, "Invalid token {}", @tagName((??ctx.extern_export_inline_token).id));
433 continue;
491 return self.parseError(token, "Invalid token {}", @tagName((??ctx.extern_export_inline_token).id));
434492 }
435493
436 const node = try self.createAttachNode(arena, ctx.decls, ast.NodeUse,
437 ast.NodeUse {
494 const node = try self.createAttachNode(arena, ctx.decls, ast.Node.Use,
495 ast.Node.Use {
438496 .base = undefined,
439497 .visib_token = ctx.visib_token,
440498 .expr = undefined,
......@@ -447,63 +505,35 @@ pub const Parser = struct {
447505 .ptr = &node.semicolon_token,
448506 }
449507 }) catch unreachable;
450 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
508 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
451509 continue;
452510 },
453511 Token.Id.Keyword_var, Token.Id.Keyword_const => {
454512 if (ctx.extern_export_inline_token) |extern_export_inline_token| {
455513 if (extern_export_inline_token.id == Token.Id.Keyword_inline) {
456 try self.parseError(&stack, token, "Invalid token {}", @tagName(extern_export_inline_token.id));
457 continue;
514 return self.parseError(token, "Invalid token {}", @tagName(extern_export_inline_token.id));
458515 }
459516 }
460517
461 const var_decl_node = try self.createAttachNode(arena, ctx.decls, ast.NodeVarDecl,
462 ast.NodeVarDecl {
463 .base = undefined,
518 stack.append(State {
519 .VarDecl = VarDeclCtx {
520 .comments = comments,
464521 .visib_token = ctx.visib_token,
465 .mut_token = token,
522 .lib_name = ctx.lib_name,
466523 .comptime_token = null,
467524 .extern_export_token = ctx.extern_export_inline_token,
468 .type_node = null,
469 .align_node = null,
470 .init_node = null,
471 .lib_name = ctx.lib_name,
472 // initialized later
473 .name_token = undefined,
474 .eq_token = undefined,
475 .semicolon_token = undefined,
476 }
477 );
478 stack.append(State { .VarDecl = var_decl_node }) catch unreachable;
479 continue;
480 },
481 Token.Id.Keyword_fn => {
482 const fn_proto = try self.createAttachNode(arena, ctx.decls, ast.NodeFnProto,
483 ast.NodeFnProto {
484 .base = undefined,
485 .visib_token = ctx.visib_token,
486 .name_token = null,
487 .fn_token = token,
488 .params = ArrayList(&ast.Node).init(arena),
489 .return_type = undefined,
490 .var_args_token = null,
491 .extern_export_inline_token = ctx.extern_export_inline_token,
492 .cc_token = null,
493 .async_attr = null,
494 .body_node = null,
495 .lib_name = ctx.lib_name,
496 .align_expr = null,
525 .mut_token = token,
526 .list = ctx.decls
497527 }
498 );
499 stack.append(State { .FnDef = fn_proto }) catch unreachable;
500 try stack.append(State { .FnProto = fn_proto });
528 }) catch unreachable;
501529 continue;
502530 },
503 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
504 const fn_proto = try self.createAttachNode(arena, ctx.decls, ast.NodeFnProto,
505 ast.NodeFnProto {
531 Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc,
532 Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => {
533 const fn_proto = try self.createAttachNode(arena, ctx.decls, ast.Node.FnProto,
534 ast.Node.FnProto {
506535 .base = undefined,
536 .comments = comments,
507537 .visib_token = ctx.visib_token,
508538 .name_token = null,
509539 .fn_token = undefined,
......@@ -511,7 +541,7 @@ pub const Parser = struct {
511541 .return_type = undefined,
512542 .var_args_token = null,
513543 .extern_export_inline_token = ctx.extern_export_inline_token,
514 .cc_token = token,
544 .cc_token = null,
515545 .async_attr = null,
516546 .body_node = null,
517547 .lib_name = ctx.lib_name,
......@@ -520,144 +550,101 @@ pub const Parser = struct {
520550 );
521551 stack.append(State { .FnDef = fn_proto }) catch unreachable;
522552 try stack.append(State { .FnProto = fn_proto });
523 try stack.append(State {
524 .ExpectTokenSave = ExpectTokenSave {
525 .id = Token.Id.Keyword_fn,
526 .ptr = &fn_proto.fn_token,
527 }
528 });
529 continue;
530 },
531 Token.Id.Keyword_async => {
532 const async_node = try self.createNode(arena, ast.NodeAsyncAttribute,
533 ast.NodeAsyncAttribute {
534 .base = undefined,
535 .async_token = token,
536 .allocator_type = null,
537 .rangle_bracket = null,
538 }
539 );
540553
541 const fn_proto = try self.createAttachNode(arena, ctx.decls, ast.NodeFnProto,
542 ast.NodeFnProto {
543 .base = undefined,
544 .visib_token = ctx.visib_token,
545 .name_token = null,
546 .fn_token = undefined,
547 .params = ArrayList(&ast.Node).init(arena),
548 .return_type = undefined,
549 .var_args_token = null,
550 .extern_export_inline_token = ctx.extern_export_inline_token,
551 .cc_token = null,
552 .async_attr = async_node,
553 .body_node = null,
554 .lib_name = ctx.lib_name,
555 .align_expr = null,
556 }
557 );
558 stack.append(State { .FnDef = fn_proto }) catch unreachable;
559 try stack.append(State { .FnProto = fn_proto });
560 try stack.append(State {
561 .ExpectTokenSave = ExpectTokenSave {
562 .id = Token.Id.Keyword_fn,
563 .ptr = &fn_proto.fn_token,
564 }
565 });
554 switch (token.id) {
555 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
556 fn_proto.cc_token = token;
557 try stack.append(State {
558 .ExpectTokenSave = ExpectTokenSave {
559 .id = Token.Id.Keyword_fn,
560 .ptr = &fn_proto.fn_token,
561 }
562 });
563 continue;
564 },
565 Token.Id.Keyword_async => {
566 const async_node = try self.createNode(arena, ast.Node.AsyncAttribute,
567 ast.Node.AsyncAttribute {
568 .base = undefined,
569 .async_token = token,
570 .allocator_type = null,
571 .rangle_bracket = null,
572 }
573 );
574 fn_proto.async_attr = async_node;
566575
567 const langle_bracket = self.getNextToken();
568 if (langle_bracket.id != Token.Id.AngleBracketLeft) {
569 self.putBackToken(langle_bracket);
570 continue;
576 try stack.append(State {
577 .ExpectTokenSave = ExpectTokenSave {
578 .id = Token.Id.Keyword_fn,
579 .ptr = &fn_proto.fn_token,
580 }
581 });
582 try stack.append(State { .AsyncAllocator = async_node });
583 continue;
584 },
585 Token.Id.Keyword_fn => {
586 fn_proto.fn_token = token;
587 continue;
588 },
589 else => unreachable,
571590 }
572
573 async_node.rangle_bracket = Token(undefined);
574 try stack.append(State {
575 .ExpectTokenSave = ExpectTokenSave {
576 .id = Token.Id.AngleBracketRight,
577 .ptr = &??async_node.rangle_bracket,
578 }
579 });
580 try stack.append(State { .TypeExprBegin = DestPtr { .NullableField = &async_node.allocator_type } });
581 continue;
582591 },
583592 else => {
584 try self.parseError(&stack, token, "expected variable declaration or function, found {}", @tagName(token.id));
585 continue;
593 return self.parseError(token, "expected variable declaration or function, found {}", @tagName(token.id));
586594 },
587595 }
588596 },
589 State.VarDecl => |var_decl| {
590 stack.append(State { .VarDeclAlign = var_decl }) catch unreachable;
591 try stack.append(State { .TypeExprBegin = DestPtr {.NullableField = &var_decl.type_node} });
592 try stack.append(State { .IfToken = Token.Id.Colon });
593 try stack.append(State {
594 .ExpectTokenSave = ExpectTokenSave {
595 .id = Token.Id.Identifier,
596 .ptr = &var_decl.name_token,
597 }
598 });
599 continue;
600 },
601 State.VarDeclAlign => |var_decl| {
602 stack.append(State { .VarDeclEq = var_decl }) catch unreachable;
597 State.TopLevelExternOrField => |ctx| {
598 if (self.eatToken(Token.Id.Identifier)) |identifier| {
599 std.debug.assert(ctx.container_decl.kind == ast.Node.ContainerDecl.Kind.Struct);
600 const node = try self.createAttachNode(arena, &ctx.container_decl.fields_and_decls, ast.Node.StructField,
601 ast.Node.StructField {
602 .base = undefined,
603 .visib_token = ctx.visib_token,
604 .name_token = identifier,
605 .type_expr = undefined,
606 }
607 );
603608
604 const next_token = self.getNextToken();
605 if (next_token.id == Token.Id.Keyword_align) {
606 try stack.append(State { .ExpectToken = Token.Id.RParen });
607 try stack.append(State { .Expression = DestPtr{.NullableField = &var_decl.align_node} });
608 try stack.append(State { .ExpectToken = Token.Id.LParen });
609 stack.append(State { .FieldListCommaOrEnd = ctx.container_decl }) catch unreachable;
610 try stack.append(State { .Expression = OptionalCtx { .Required = &node.type_expr } });
611 try stack.append(State { .ExpectToken = Token.Id.Colon });
609612 continue;
610613 }
611614
612 self.putBackToken(next_token);
613 continue;
614 },
615 State.VarDeclEq => |var_decl| {
616 const token = self.getNextToken();
617 switch (token.id) {
618 Token.Id.Equal => {
619 var_decl.eq_token = token;
620 stack.append(State {
621 .ExpectTokenSave = ExpectTokenSave {
622 .id = Token.Id.Semicolon,
623 .ptr = &var_decl.semicolon_token,
624 },
625 }) catch unreachable;
626 try stack.append(State { .Expression = DestPtr {.NullableField = &var_decl.init_node} });
627 continue;
628 },
629 Token.Id.Semicolon => {
630 var_decl.semicolon_token = token;
631 continue;
632 },
633 else => {
634 try self.parseError(&stack, token, "expected '=' or ';', found {}", @tagName(token.id));
635 continue;
615 stack.append(State{ .ContainerDecl = ctx.container_decl }) catch unreachable;
616 try stack.append(State {
617 .TopLevelExtern = TopLevelDeclCtx {
618 .decls = &ctx.container_decl.fields_and_decls,
619 .visib_token = ctx.visib_token,
620 .extern_export_inline_token = null,
621 .lib_name = null,
636622 }
637 }
623 });
624 continue;
638625 },
639626
640 State.ContainerExtern => |ctx| {
627
628 State.ContainerKind => |ctx| {
641629 const token = self.getNextToken();
642 const node = try self.createToDestNode(arena, ctx.dest_ptr, ast.NodeContainerDecl,
643 ast.NodeContainerDecl {
630 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.ContainerDecl,
631 ast.Node.ContainerDecl {
644632 .base = undefined,
645633 .ltoken = ctx.ltoken,
646634 .layout = ctx.layout,
647635 .kind = switch (token.id) {
648 Token.Id.Keyword_struct => ast.NodeContainerDecl.Kind.Struct,
649 Token.Id.Keyword_union => ast.NodeContainerDecl.Kind.Union,
650 Token.Id.Keyword_enum => ast.NodeContainerDecl.Kind.Enum,
636 Token.Id.Keyword_struct => ast.Node.ContainerDecl.Kind.Struct,
637 Token.Id.Keyword_union => ast.Node.ContainerDecl.Kind.Union,
638 Token.Id.Keyword_enum => ast.Node.ContainerDecl.Kind.Enum,
651639 else => {
652 try self.parseError(&stack, token, "expected {}, {} or {}, found {}",
640 return self.parseError(token, "expected {}, {} or {}, found {}",
653641 @tagName(Token.Id.Keyword_struct),
654642 @tagName(Token.Id.Keyword_union),
655643 @tagName(Token.Id.Keyword_enum),
656644 @tagName(token.id));
657 continue;
658645 },
659646 },
660 .init_arg_expr = undefined,
647 .init_arg_expr = ast.Node.ContainerDecl.InitArg.None,
661648 .fields_and_decls = ArrayList(&ast.Node).init(arena),
662649 .rbrace_token = undefined,
663650 }
......@@ -665,43 +652,42 @@ pub const Parser = struct {
665652
666653 stack.append(State { .ContainerDecl = node }) catch unreachable;
667654 try stack.append(State { .ExpectToken = Token.Id.LBrace });
655 try stack.append(State { .ContainerInitArgStart = node });
656 continue;
657 },
668658
669 const lparen = self.getNextToken();
670 if (lparen.id != Token.Id.LParen) {
671 self.putBackToken(lparen);
672 node.init_arg_expr = ast.NodeContainerDecl.InitArg.None;
659 State.ContainerInitArgStart => |container_decl| {
660 if (self.eatToken(Token.Id.LParen) == null) {
673661 continue;
674662 }
675663
676 try stack.append(State { .ExpectToken = Token.Id.RParen });
664 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
665 try stack.append(State { .ContainerInitArg = container_decl });
666 continue;
667 },
677668
669 State.ContainerInitArg => |container_decl| {
678670 const init_arg_token = self.getNextToken();
679671 switch (init_arg_token.id) {
680672 Token.Id.Keyword_enum => {
681 node.init_arg_expr = ast.NodeContainerDecl.InitArg.Enum;
673 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg.Enum;
682674 },
683675 else => {
684676 self.putBackToken(init_arg_token);
685 node.init_arg_expr = ast.NodeContainerDecl.InitArg { .Type = undefined };
686 try stack.append(State {
687 .Expression = DestPtr {
688 .Field = &node.init_arg_expr.Type
689 }
690 });
677 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg { .Type = undefined };
678 stack.append(State { .Expression = OptionalCtx { .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;
691679 },
692680 }
693681 continue;
694682 },
695
696683 State.ContainerDecl => |container_decl| {
697684 const token = self.getNextToken();
698
699685 switch (token.id) {
700686 Token.Id.Identifier => {
701687 switch (container_decl.kind) {
702 ast.NodeContainerDecl.Kind.Struct => {
703 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeStructField,
704 ast.NodeStructField {
688 ast.Node.ContainerDecl.Kind.Struct => {
689 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.Node.StructField,
690 ast.Node.StructField {
705691 .base = undefined,
706692 .visib_token = null,
707693 .name_token = token,
......@@ -710,13 +696,13 @@ pub const Parser = struct {
710696 );
711697
712698 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
713 try stack.append(State { .Expression = DestPtr { .Field = &node.type_expr } });
699 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.type_expr } });
714700 try stack.append(State { .ExpectToken = Token.Id.Colon });
715701 continue;
716702 },
717 ast.NodeContainerDecl.Kind.Union => {
718 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeUnionTag,
719 ast.NodeUnionTag {
703 ast.Node.ContainerDecl.Kind.Union => {
704 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.Node.UnionTag,
705 ast.Node.UnionTag {
720706 .base = undefined,
721707 .name_token = token,
722708 .type_expr = null,
......@@ -724,19 +710,13 @@ pub const Parser = struct {
724710 );
725711
726712 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
727
728 const next = self.getNextToken();
729 if (next.id != Token.Id.Colon) {
730 self.putBackToken(next);
731 continue;
732 }
733
734 try stack.append(State { .Expression = DestPtr { .NullableField = &node.type_expr } });
713 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &node.type_expr } });
714 try stack.append(State { .IfToken = Token.Id.Colon });
735715 continue;
736716 },
737 ast.NodeContainerDecl.Kind.Enum => {
738 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeEnumTag,
739 ast.NodeEnumTag {
717 ast.Node.ContainerDecl.Kind.Enum => {
718 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.Node.EnumTag,
719 ast.Node.EnumTag {
740720 .base = undefined,
741721 .name_token = token,
742722 .value = null,
......@@ -744,52 +724,36 @@ pub const Parser = struct {
744724 );
745725
746726 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
747
748 const next = self.getNextToken();
749 if (next.id != Token.Id.Equal) {
750 self.putBackToken(next);
751 continue;
752 }
753
754 try stack.append(State { .Expression = DestPtr { .NullableField = &node.value } });
727 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &node.value } });
728 try stack.append(State { .IfToken = Token.Id.Equal });
755729 continue;
756730 },
757731 }
758732 },
759733 Token.Id.Keyword_pub => {
760 if (self.eatToken(Token.Id.Identifier)) |identifier| {
761 switch (container_decl.kind) {
762 ast.NodeContainerDecl.Kind.Struct => {
763 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeStructField,
764 ast.NodeStructField {
765 .base = undefined,
766 .visib_token = token,
767 .name_token = identifier,
768 .type_expr = undefined,
769 }
770 );
771
772 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
773 try stack.append(State { .Expression = DestPtr { .Field = &node.type_expr } });
774 try stack.append(State { .ExpectToken = Token.Id.Colon });
775 continue;
776 },
777 else => {
778 self.putBackToken(identifier);
779 }
780 }
781 }
782
783 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
784 try stack.append(State {
785 .TopLevelExtern = TopLevelDeclCtx {
786 .decls = &container_decl.fields_and_decls,
787 .visib_token = token,
788 .extern_export_inline_token = null,
789 .lib_name = null,
734 switch (container_decl.kind) {
735 ast.Node.ContainerDecl.Kind.Struct => {
736 try stack.append(State {
737 .TopLevelExternOrField = TopLevelExternOrFieldCtx {
738 .visib_token = token,
739 .container_decl = container_decl,
740 }
741 });
742 continue;
743 },
744 else => {
745 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
746 try stack.append(State {
747 .TopLevelExtern = TopLevelDeclCtx {
748 .decls = &container_decl.fields_and_decls,
749 .visib_token = token,
750 .extern_export_inline_token = null,
751 .lib_name = null,
752 }
753 });
754 continue;
790755 }
791 });
792 continue;
756 }
793757 },
794758 Token.Id.Keyword_export => {
795759 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
......@@ -823,1054 +787,845 @@ pub const Parser = struct {
823787 }
824788 },
825789
826 State.ExpectToken => |token_id| {
827 _ = (try self.expectToken(&stack, token_id)) ?? continue;
828 continue;
829 },
830790
831 State.ExpectTokenSave => |expect_token_save| {
832 *expect_token_save.ptr = (try self.expectToken(&stack, expect_token_save.id)) ?? continue;
833 continue;
834 },
791 State.VarDecl => |ctx| {
792 const var_decl = try self.createAttachNode(arena, ctx.list, ast.Node.VarDecl,
793 ast.Node.VarDecl {
794 .base = undefined,
795 .comments = ctx.comments,
796 .visib_token = ctx.visib_token,
797 .mut_token = ctx.mut_token,
798 .comptime_token = ctx.comptime_token,
799 .extern_export_token = ctx.extern_export_token,
800 .type_node = null,
801 .align_node = null,
802 .init_node = null,
803 .lib_name = ctx.lib_name,
804 // initialized later
805 .name_token = undefined,
806 .eq_token = undefined,
807 .semicolon_token = undefined,
808 }
809 );
835810
836 State.IfToken => |token_id| {
837 const token = self.getNextToken();
838 if (@TagType(Token.Id)(token.id) != token_id) {
839 self.putBackToken(token);
840 _ = stack.pop();
841 continue;
842 }
811 stack.append(State { .VarDeclAlign = var_decl }) catch unreachable;
812 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &var_decl.type_node} });
813 try stack.append(State { .IfToken = Token.Id.Colon });
814 try stack.append(State {
815 .ExpectTokenSave = ExpectTokenSave {
816 .id = Token.Id.Identifier,
817 .ptr = &var_decl.name_token,
818 }
819 });
843820 continue;
844821 },
822 State.VarDeclAlign => |var_decl| {
823 stack.append(State { .VarDeclEq = var_decl }) catch unreachable;
845824
846 State.IfTokenSave => |if_token_save| {
847 const token = self.getNextToken();
848 if (@TagType(Token.Id)(token.id) != if_token_save.id) {
849 self.putBackToken(token);
850 _ = stack.pop();
825 const next_token = self.getNextToken();
826 if (next_token.id == Token.Id.Keyword_align) {
827 try stack.append(State { .ExpectToken = Token.Id.RParen });
828 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.align_node} });
829 try stack.append(State { .ExpectToken = Token.Id.LParen });
851830 continue;
852831 }
853832
854 *if_token_save.ptr = token;
833 self.putBackToken(next_token);
855834 continue;
856835 },
857
858 State.Optional => { },
859
860 State.Expression => |dest_ptr| {
836 State.VarDeclEq => |var_decl| {
861837 const token = self.getNextToken();
862838 switch (token.id) {
863 Token.Id.Keyword_return => {
864 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeControlFlowExpression,
865 ast.NodeControlFlowExpression {
866 .base = undefined,
867 .ltoken = token,
868 .kind = ast.NodeControlFlowExpression.Kind.Return,
869 .rhs = undefined,
870 }
871 );
872
873 // TODO: Find another way to do optional expressions
874 stack.append(State {
875 .Optional = RevertState {
876 .parser = *self,
877 .tokenizer = *self.tokenizer,
878 .ptr = &node.rhs,
879 }
880 }) catch unreachable;
881 try stack.append(State { .Expression = DestPtr { .NullableField = &node.rhs } });
882 continue;
883 },
884 Token.Id.Keyword_break, Token.Id.Keyword_continue => {
885 const label = blk: {
886 const colon = self.getNextToken();
887 if (colon.id != Token.Id.Colon) {
888 self.putBackToken(colon);
889 break :blk null;
890 }
891
892 break :blk (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
893 };
894
895 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeControlFlowExpression,
896 ast.NodeControlFlowExpression {
897 .base = undefined,
898 .ltoken = token,
899 .kind = switch (token.id) {
900 Token.Id.Keyword_break => ast.NodeControlFlowExpression.Kind { .Break = label },
901 Token.Id.Keyword_continue => ast.NodeControlFlowExpression.Kind { .Continue = label },
902 else => unreachable,
903 },
904 .rhs = undefined,
905 }
906 );
907
908 // TODO: Find another way to do optional expressions
839 Token.Id.Equal => {
840 var_decl.eq_token = token;
909841 stack.append(State {
910 .Optional = RevertState {
911 .parser = *self,
912 .tokenizer = *self.tokenizer,
913 .ptr = &node.rhs,
914 }
842 .ExpectTokenSave = ExpectTokenSave {
843 .id = Token.Id.Semicolon,
844 .ptr = &var_decl.semicolon_token,
845 },
915846 }) catch unreachable;
916 try stack.append(State { .Expression = DestPtr { .NullableField = &node.rhs } });
847 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.init_node } });
917848 continue;
918849 },
919 Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
920 const node = try self.createToDestNode(arena, dest_ptr, ast.NodePrefixOp,
921 ast.NodePrefixOp {
922 .base = undefined,
923 .op_token = token,
924 .op = switch (token.id) {
925 Token.Id.Keyword_try => ast.NodePrefixOp.PrefixOp { .Try = void{} },
926 Token.Id.Keyword_cancel => ast.NodePrefixOp.PrefixOp { .Cancel = void{} },
927 Token.Id.Keyword_resume => ast.NodePrefixOp.PrefixOp { .Resume = void{} },
928 else => unreachable,
929 },
930 .rhs = undefined,
931 }
932 );
933
934 stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }) catch unreachable;
850 Token.Id.Semicolon => {
851 var_decl.semicolon_token = token;
935852 continue;
936853 },
937854 else => {
938 if (!try self.parseBlockExpr(&stack, arena, dest_ptr, token)) {
939 self.putBackToken(token);
940 stack.append(State { .UnwrapExpressionBegin = dest_ptr }) catch unreachable;
941 }
942 continue;
855 return self.parseError(token, "expected '=' or ';', found {}", @tagName(token.id));
943856 }
944857 }
945858 },
946859
947 State.RangeExpressionBegin => |dest_ptr| {
948 stack.append(State { .RangeExpressionEnd = dest_ptr }) catch unreachable;
949 try stack.append(State { .Expression = dest_ptr });
950 continue;
951 },
952
953 State.RangeExpressionEnd => |dest_ptr| {
954 if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
955 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
956 ast.NodeInfixOp {
957 .base = undefined,
958 .lhs = dest_ptr.get(),
959 .op_token = ellipsis3,
960 .op = ast.NodeInfixOp.InfixOp.Range,
961 .rhs = undefined,
962 }
963 );
964 stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }) catch unreachable;
965 }
966
967 continue;
968 },
969
970 State.AssignmentExpressionBegin => |dest_ptr| {
971 stack.append(State { .AssignmentExpressionEnd = dest_ptr }) catch unreachable;
972 try stack.append(State { .Expression = dest_ptr });
973 continue;
974 },
975
976 State.AssignmentExpressionEnd => |dest_ptr| {
977 const token = self.getNextToken();
978 if (tokenIdToAssignment(token.id)) |ass_id| {
979 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
980 ast.NodeInfixOp {
981 .base = undefined,
982 .lhs = dest_ptr.get(),
983 .op_token = token,
984 .op = ass_id,
985 .rhs = undefined,
986 }
987 );
988 stack.append(State { .AssignmentExpressionEnd = dest_ptr }) catch unreachable;
989 try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } });
990 continue;
991 } else {
992 self.putBackToken(token);
993 continue;
994 }
995 },
996
997 State.UnwrapExpressionBegin => |dest_ptr| {
998 stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable;
999 try stack.append(State { .BoolOrExpressionBegin = dest_ptr });
1000 continue;
1001 },
1002860
1003 State.UnwrapExpressionEnd => |dest_ptr| {
861 State.FnDef => |fn_proto| {
1004862 const token = self.getNextToken();
1005 switch (token.id) {
1006 Token.Id.Keyword_catch, Token.Id.QuestionMarkQuestionMark => {
1007 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1008 ast.NodeInfixOp {
863 switch(token.id) {
864 Token.Id.LBrace => {
865 const block = try self.createNode(arena, ast.Node.Block,
866 ast.Node.Block {
1009867 .base = undefined,
1010 .lhs = dest_ptr.get(),
1011 .op_token = token,
1012 .op = switch (token.id) {
1013 Token.Id.Keyword_catch => ast.NodeInfixOp.InfixOp { .Catch = null },
1014 Token.Id.QuestionMarkQuestionMark => ast.NodeInfixOp.InfixOp { .UnwrapMaybe = void{} },
1015 else => unreachable,
1016 },
1017 .rhs = undefined,
868 .label = null,
869 .lbrace = token,
870 .statements = ArrayList(&ast.Node).init(arena),
871 .rbrace = undefined,
1018872 }
1019873 );
1020
1021 stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable;
1022 try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } });
1023
1024 if (node.op == ast.NodeInfixOp.InfixOp.Catch) {
1025 try stack.append(State { .Payload = &node.op.Catch });
1026 }
874 fn_proto.body_node = &block.base;
875 stack.append(State { .Block = block }) catch unreachable;
1027876 continue;
1028877 },
878 Token.Id.Semicolon => continue,
1029879 else => {
1030 self.putBackToken(token);
1031 continue;
880 return self.parseError(token, "expected ';' or '{{', found {}", @tagName(token.id));
1032881 },
1033882 }
1034883 },
884 State.FnProto => |fn_proto| {
885 stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable;
886 try stack.append(State { .ParamDecl = fn_proto });
887 try stack.append(State { .ExpectToken = Token.Id.LParen });
1035888
1036 State.BoolOrExpressionBegin => |dest_ptr| {
1037 stack.append(State { .BoolOrExpressionEnd = dest_ptr }) catch unreachable;
1038 try stack.append(State { .BoolAndExpressionBegin = dest_ptr });
889 if (self.eatToken(Token.Id.Identifier)) |name_token| {
890 fn_proto.name_token = name_token;
891 }
1039892 continue;
1040893 },
894 State.FnProtoAlign => |fn_proto| {
895 stack.append(State { .FnProtoReturnType = fn_proto }) catch unreachable;
1041896
1042 State.BoolOrExpressionEnd => |dest_ptr| {
897 if (self.eatToken(Token.Id.Keyword_align)) |align_token| {
898 try stack.append(State { .ExpectToken = Token.Id.RParen });
899 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &fn_proto.align_expr } });
900 try stack.append(State { .ExpectToken = Token.Id.LParen });
901 }
902 continue;
903 },
904 State.FnProtoReturnType => |fn_proto| {
1043905 const token = self.getNextToken();
1044906 switch (token.id) {
1045 Token.Id.Keyword_or => {
1046 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1047 ast.NodeInfixOp {
1048 .base = undefined,
1049 .lhs = dest_ptr.get(),
1050 .op_token = token,
1051 .op = ast.NodeInfixOp.InfixOp.BoolOr,
1052 .rhs = undefined,
1053 }
1054 );
1055 stack.append(State { .BoolOrExpressionEnd = dest_ptr }) catch unreachable;
1056 try stack.append(State { .BoolAndExpressionBegin = DestPtr { .Field = &node.rhs } });
907 Token.Id.Bang => {
908 fn_proto.return_type = ast.Node.FnProto.ReturnType { .InferErrorSet = undefined };
909 stack.append(State {
910 .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.InferErrorSet },
911 }) catch unreachable;
1057912 continue;
1058913 },
1059914 else => {
915 // TODO: this is a special case. Remove this when #760 is fixed
916 if (token.id == Token.Id.Keyword_error) {
917 if (self.isPeekToken(Token.Id.LBrace)) {
918 fn_proto.return_type = ast.Node.FnProto.ReturnType {
919 .Explicit = &(try self.createLiteral(arena, ast.Node.ErrorType, token)).base
920 };
921 continue;
922 }
923 }
924
1060925 self.putBackToken(token);
926 fn_proto.return_type = ast.Node.FnProto.ReturnType { .Explicit = undefined };
927 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.Explicit }, }) catch unreachable;
1061928 continue;
1062929 },
1063930 }
1064931 },
1065932
1066 State.BoolAndExpressionBegin => |dest_ptr| {
1067 stack.append(State { .BoolAndExpressionEnd = dest_ptr }) catch unreachable;
1068 try stack.append(State { .ComparisonExpressionBegin = dest_ptr });
1069 continue;
1070 },
1071933
1072 State.BoolAndExpressionEnd => |dest_ptr| {
1073 const token = self.getNextToken();
1074 switch (token.id) {
1075 Token.Id.Keyword_and => {
1076 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1077 ast.NodeInfixOp {
1078 .base = undefined,
1079 .lhs = dest_ptr.get(),
1080 .op_token = token,
1081 .op = ast.NodeInfixOp.InfixOp.BoolAnd,
1082 .rhs = undefined,
1083 }
1084 );
1085 stack.append(State { .BoolAndExpressionEnd = dest_ptr }) catch unreachable;
1086 try stack.append(State { .ComparisonExpressionBegin = DestPtr { .Field = &node.rhs } });
1087 continue;
1088 },
1089 else => {
1090 self.putBackToken(token);
1091 continue;
934 State.ParamDecl => |fn_proto| {
935 if (self.eatToken(Token.Id.RParen)) |_| {
936 continue;
937 }
938 const param_decl = try self.createAttachNode(arena, &fn_proto.params, ast.Node.ParamDecl,
939 ast.Node.ParamDecl {
940 .base = undefined,
941 .comptime_token = null,
942 .noalias_token = null,
943 .name_token = null,
944 .type_node = undefined,
945 .var_args_token = null,
1092946 },
947 );
948
949 stack.append(State {
950 .ParamDeclEnd = ParamDeclEndCtx {
951 .param_decl = param_decl,
952 .fn_proto = fn_proto,
953 }
954 }) catch unreachable;
955 try stack.append(State { .ParamDeclName = param_decl });
956 try stack.append(State { .ParamDeclAliasOrComptime = param_decl });
957 continue;
958 },
959 State.ParamDeclAliasOrComptime => |param_decl| {
960 if (self.eatToken(Token.Id.Keyword_comptime)) |comptime_token| {
961 param_decl.comptime_token = comptime_token;
962 } else if (self.eatToken(Token.Id.Keyword_noalias)) |noalias_token| {
963 param_decl.noalias_token = noalias_token;
964 }
965 continue;
966 },
967 State.ParamDeclName => |param_decl| {
968 // TODO: Here, we eat two tokens in one state. This means that we can't have
969 // comments between these two tokens.
970 if (self.eatToken(Token.Id.Identifier)) |ident_token| {
971 if (self.eatToken(Token.Id.Colon)) |_| {
972 param_decl.name_token = ident_token;
973 } else {
974 self.putBackToken(ident_token);
975 }
1093976 }
977 continue;
1094978 },
979 State.ParamDeclEnd => |ctx| {
980 if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
981 ctx.param_decl.var_args_token = ellipsis3;
982 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
983 continue;
984 }
1095985
1096 State.ComparisonExpressionBegin => |dest_ptr| {
1097 stack.append(State { .ComparisonExpressionEnd = dest_ptr }) catch unreachable;
1098 try stack.append(State { .BinaryOrExpressionBegin = dest_ptr });
986 try stack.append(State { .ParamDeclComma = ctx.fn_proto });
987 try stack.append(State {
988 .TypeExprBegin = OptionalCtx { .Required = &ctx.param_decl.type_node }
989 });
990 continue;
991 },
992 State.ParamDeclComma => |fn_proto| {
993 if ((try self.expectCommaOrEnd(Token.Id.RParen)) == null) {
994 stack.append(State { .ParamDecl = fn_proto }) catch unreachable;
995 }
1099996 continue;
1100997 },
1101998
1102 State.ComparisonExpressionEnd => |dest_ptr| {
1103 const token = self.getNextToken();
1104 if (tokenIdToComparison(token.id)) |comp_id| {
1105 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1106 ast.NodeInfixOp {
1107 .base = undefined,
1108 .lhs = dest_ptr.get(),
1109 .op_token = token,
1110 .op = comp_id,
1111 .rhs = undefined,
999 State.MaybeLabeledExpression => |ctx| {
1000 if (self.eatToken(Token.Id.Colon)) |_| {
1001 stack.append(State {
1002 .LabeledExpression = LabelCtx {
1003 .label = ctx.label,
1004 .opt_ctx = ctx.opt_ctx,
11121005 }
1113 );
1114 stack.append(State { .ComparisonExpressionEnd = dest_ptr }) catch unreachable;
1115 try stack.append(State { .BinaryOrExpressionBegin = DestPtr { .Field = &node.rhs } });
1116 continue;
1117 } else {
1118 self.putBackToken(token);
1006 }) catch unreachable;
11191007 continue;
11201008 }
1121 },
11221009
1123 State.BinaryOrExpressionBegin => |dest_ptr| {
1124 stack.append(State { .BinaryOrExpressionEnd = dest_ptr }) catch unreachable;
1125 try stack.append(State { .BinaryXorExpressionBegin = dest_ptr });
1010 _ = try self.createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.Identifier, ctx.label);
11261011 continue;
11271012 },
1128
1129 State.BinaryOrExpressionEnd => |dest_ptr| {
1013 State.LabeledExpression => |ctx| {
11301014 const token = self.getNextToken();
11311015 switch (token.id) {
1132 Token.Id.Pipe => {
1133 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1134 ast.NodeInfixOp {
1016 Token.Id.LBrace => {
1017 const block = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.Block,
1018 ast.Node.Block {
11351019 .base = undefined,
1136 .lhs = dest_ptr.get(),
1137 .op_token = token,
1138 .op = ast.NodeInfixOp.InfixOp.BitOr,
1139 .rhs = undefined,
1020 .label = ctx.label,
1021 .lbrace = token,
1022 .statements = ArrayList(&ast.Node).init(arena),
1023 .rbrace = undefined,
11401024 }
11411025 );
1142 stack.append(State { .BinaryOrExpressionEnd = dest_ptr }) catch unreachable;
1143 try stack.append(State { .BinaryXorExpressionBegin = DestPtr { .Field = &node.rhs } });
1026 stack.append(State { .Block = block }) catch unreachable;
11441027 continue;
11451028 },
1146 else => {
1147 self.putBackToken(token);
1029 Token.Id.Keyword_while => {
1030 stack.append(State {
1031 .While = LoopCtx {
1032 .label = ctx.label,
1033 .inline_token = null,
1034 .loop_token = token,
1035 .opt_ctx = ctx.opt_ctx.toRequired(),
1036 }
1037 }) catch unreachable;
11481038 continue;
11491039 },
1150 }
1151 },
1152
1153 State.BinaryXorExpressionBegin => |dest_ptr| {
1154 stack.append(State { .BinaryXorExpressionEnd = dest_ptr }) catch unreachable;
1155 try stack.append(State { .BinaryAndExpressionBegin = dest_ptr });
1156 continue;
1157 },
1158
1159 State.BinaryXorExpressionEnd => |dest_ptr| {
1160 const token = self.getNextToken();
1161 switch (token.id) {
1162 Token.Id.Caret => {
1163 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1164 ast.NodeInfixOp {
1165 .base = undefined,
1166 .lhs = dest_ptr.get(),
1167 .op_token = token,
1168 .op = ast.NodeInfixOp.InfixOp.BitXor,
1169 .rhs = undefined,
1040 Token.Id.Keyword_for => {
1041 stack.append(State {
1042 .For = LoopCtx {
1043 .label = ctx.label,
1044 .inline_token = null,
1045 .loop_token = token,
1046 .opt_ctx = ctx.opt_ctx.toRequired(),
11701047 }
1171 );
1172 stack.append(State { .BinaryXorExpressionEnd = dest_ptr }) catch unreachable;
1173 try stack.append(State { .BinaryAndExpressionBegin = DestPtr { .Field = &node.rhs } });
1048 }) catch unreachable;
1049 continue;
1050 },
1051 Token.Id.Keyword_inline => {
1052 stack.append(State {
1053 .Inline = InlineCtx {
1054 .label = ctx.label,
1055 .inline_token = token,
1056 .opt_ctx = ctx.opt_ctx.toRequired(),
1057 }
1058 }) catch unreachable;
11741059 continue;
11751060 },
11761061 else => {
1062 if (ctx.opt_ctx != OptionalCtx.Optional) {
1063 return self.parseError(token, "expected 'while', 'for', 'inline' or '{{', found {}", @tagName(token.id));
1064 }
1065
11771066 self.putBackToken(token);
11781067 continue;
11791068 },
11801069 }
11811070 },
1182
1183 State.BinaryAndExpressionBegin => |dest_ptr| {
1184 stack.append(State { .BinaryAndExpressionEnd = dest_ptr }) catch unreachable;
1185 try stack.append(State { .BitShiftExpressionBegin = dest_ptr });
1186 continue;
1187 },
1188
1189 State.BinaryAndExpressionEnd => |dest_ptr| {
1071 State.Inline => |ctx| {
11901072 const token = self.getNextToken();
11911073 switch (token.id) {
1192 Token.Id.Ampersand => {
1193 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1194 ast.NodeInfixOp {
1195 .base = undefined,
1196 .lhs = dest_ptr.get(),
1197 .op_token = token,
1198 .op = ast.NodeInfixOp.InfixOp.BitAnd,
1199 .rhs = undefined,
1074 Token.Id.Keyword_while => {
1075 stack.append(State {
1076 .While = LoopCtx {
1077 .inline_token = ctx.inline_token,
1078 .label = ctx.label,
1079 .loop_token = token,
1080 .opt_ctx = ctx.opt_ctx.toRequired(),
12001081 }
1201 );
1202 stack.append(State { .BinaryAndExpressionEnd = dest_ptr }) catch unreachable;
1203 try stack.append(State { .BitShiftExpressionBegin = DestPtr { .Field = &node.rhs } });
1082 }) catch unreachable;
1083 continue;
1084 },
1085 Token.Id.Keyword_for => {
1086 stack.append(State {
1087 .For = LoopCtx {
1088 .inline_token = ctx.inline_token,
1089 .label = ctx.label,
1090 .loop_token = token,
1091 .opt_ctx = ctx.opt_ctx.toRequired(),
1092 }
1093 }) catch unreachable;
12041094 continue;
12051095 },
12061096 else => {
1097 if (ctx.opt_ctx != OptionalCtx.Optional) {
1098 return self.parseError(token, "expected 'while' or 'for', found {}", @tagName(token.id));
1099 }
1100
12071101 self.putBackToken(token);
12081102 continue;
12091103 },
12101104 }
12111105 },
1212
1213 State.BitShiftExpressionBegin => |dest_ptr| {
1214 stack.append(State { .BitShiftExpressionEnd = dest_ptr }) catch unreachable;
1215 try stack.append(State { .AdditionExpressionBegin = dest_ptr });
1106 State.While => |ctx| {
1107 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.While,
1108 ast.Node.While {
1109 .base = undefined,
1110 .label = ctx.label,
1111 .inline_token = ctx.inline_token,
1112 .while_token = ctx.loop_token,
1113 .condition = undefined,
1114 .payload = null,
1115 .continue_expr = null,
1116 .body = undefined,
1117 .@"else" = null,
1118 }
1119 );
1120 stack.append(State { .Else = &node.@"else" }) catch unreachable;
1121 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
1122 try stack.append(State { .WhileContinueExpr = &node.continue_expr });
1123 try stack.append(State { .IfToken = Token.Id.Colon });
1124 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
1125 try stack.append(State { .ExpectToken = Token.Id.RParen });
1126 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
1127 try stack.append(State { .ExpectToken = Token.Id.LParen });
12161128 continue;
12171129 },
1218
1219 State.BitShiftExpressionEnd => |dest_ptr| {
1220 const token = self.getNextToken();
1221 if (tokenIdToBitShift(token.id)) |bitshift_id| {
1222 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1223 ast.NodeInfixOp {
1224 .base = undefined,
1225 .lhs = dest_ptr.get(),
1226 .op_token = token,
1227 .op = bitshift_id,
1228 .rhs = undefined,
1229 }
1230 );
1231 stack.append(State { .BitShiftExpressionEnd = dest_ptr }) catch unreachable;
1232 try stack.append(State { .AdditionExpressionBegin = DestPtr { .Field = &node.rhs } });
1233 continue;
1234 } else {
1235 self.putBackToken(token);
1236 continue;
1237 }
1238 },
1239
1240 State.AdditionExpressionBegin => |dest_ptr| {
1241 stack.append(State { .AdditionExpressionEnd = dest_ptr }) catch unreachable;
1242 try stack.append(State { .MultiplyExpressionBegin = dest_ptr });
1130 State.WhileContinueExpr => |dest| {
1131 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
1132 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = dest } });
1133 try stack.append(State { .ExpectToken = Token.Id.LParen });
12431134 continue;
12441135 },
1245
1246 State.AdditionExpressionEnd => |dest_ptr| {
1247 const token = self.getNextToken();
1248 if (tokenIdToAddition(token.id)) |add_id| {
1249 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1250 ast.NodeInfixOp {
1251 .base = undefined,
1252 .lhs = dest_ptr.get(),
1253 .op_token = token,
1254 .op = add_id,
1255 .rhs = undefined,
1256 }
1257 );
1258 stack.append(State { .AdditionExpressionEnd = dest_ptr }) catch unreachable;
1259 try stack.append(State { .MultiplyExpressionBegin = DestPtr { .Field = &node.rhs } });
1260 continue;
1261 } else {
1262 self.putBackToken(token);
1263 continue;
1264 }
1265 },
1266
1267 State.MultiplyExpressionBegin => |dest_ptr| {
1268 stack.append(State { .MultiplyExpressionEnd = dest_ptr }) catch unreachable;
1269 try stack.append(State { .CurlySuffixExpressionBegin = dest_ptr });
1136 State.For => |ctx| {
1137 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.For,
1138 ast.Node.For {
1139 .base = undefined,
1140 .label = ctx.label,
1141 .inline_token = ctx.inline_token,
1142 .for_token = ctx.loop_token,
1143 .array_expr = undefined,
1144 .payload = null,
1145 .body = undefined,
1146 .@"else" = null,
1147 }
1148 );
1149 stack.append(State { .Else = &node.@"else" }) catch unreachable;
1150 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
1151 try stack.append(State { .PointerIndexPayload = OptionalCtx { .Optional = &node.payload } });
1152 try stack.append(State { .ExpectToken = Token.Id.RParen });
1153 try stack.append(State { .Expression = OptionalCtx { .Required = &node.array_expr } });
1154 try stack.append(State { .ExpectToken = Token.Id.LParen });
12701155 continue;
12711156 },
1272
1273 State.MultiplyExpressionEnd => |dest_ptr| {
1274 const token = self.getNextToken();
1275 if (tokenIdToMultiply(token.id)) |mult_id| {
1276 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1277 ast.NodeInfixOp {
1157 State.Else => |dest| {
1158 if (self.eatToken(Token.Id.Keyword_else)) |else_token| {
1159 const node = try self.createNode(arena, ast.Node.Else,
1160 ast.Node.Else {
12781161 .base = undefined,
1279 .lhs = dest_ptr.get(),
1280 .op_token = token,
1281 .op = mult_id,
1282 .rhs = undefined,
1162 .else_token = else_token,
1163 .payload = null,
1164 .body = undefined,
12831165 }
12841166 );
1285 stack.append(State { .MultiplyExpressionEnd = dest_ptr }) catch unreachable;
1286 try stack.append(State { .CurlySuffixExpressionBegin = DestPtr { .Field = &node.rhs } });
1287 continue;
1288 } else {
1289 self.putBackToken(token);
1290 continue;
1291 }
1292 },
1293
1294 State.CurlySuffixExpressionBegin => |dest_ptr| {
1295 stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;
1296 try stack.append(State { .TypeExprBegin = dest_ptr });
1297 continue;
1298 },
1299
1300 State.CurlySuffixExpressionEnd => |dest_ptr| {
1301 if (self.eatToken(Token.Id.LBrace) == null) {
1302 continue;
1303 }
1167 *dest = node;
13041168
1305 if (self.isPeekToken(Token.Id.Period)) {
1306 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSuffixOp,
1307 ast.NodeSuffixOp {
1308 .base = undefined,
1309 .lhs = dest_ptr.get(),
1310 .op = ast.NodeSuffixOp.SuffixOp {
1311 .StructInitializer = ArrayList(&ast.NodeFieldInitializer).init(arena),
1312 },
1313 .rtoken = undefined,
1314 }
1315 );
1316 stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;
1317 try stack.append(State {
1318 .FieldInitListItemOrEnd = ListSave(&ast.NodeFieldInitializer) {
1319 .list = &node.op.StructInitializer,
1320 .ptr = &node.rtoken,
1321 }
1322 });
1169 stack.append(State { .Expression = OptionalCtx { .Required = &node.body } }) catch unreachable;
1170 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
13231171 continue;
13241172 } else {
1325 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSuffixOp,
1326 ast.NodeSuffixOp {
1327 .base = undefined,
1328 .lhs = dest_ptr.get(),
1329 .op = ast.NodeSuffixOp.SuffixOp {
1330 .ArrayInitializer = ArrayList(&ast.Node).init(arena),
1331 },
1332 .rtoken = undefined,
1333 }
1334 );
1335 stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;
1336 try stack.append(State {
1337 .ExprListItemOrEnd = ExprListCtx {
1338 .list = &node.op.ArrayInitializer,
1339 .end = Token.Id.RBrace,
1340 .ptr = &node.rtoken,
1341 }
1342 });
13431173 continue;
13441174 }
13451175 },
13461176
1347 State.TypeExprBegin => |dest_ptr| {
1348 stack.append(State { .TypeExprEnd = dest_ptr }) catch unreachable;
1349 try stack.append(State { .PrefixOpExpression = dest_ptr });
1350 continue;
1351 },
13521177
1353 State.TypeExprEnd => |dest_ptr| {
1178 State.Block => |block| {
13541179 const token = self.getNextToken();
13551180 switch (token.id) {
1356 Token.Id.Bang => {
1357 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1358 ast.NodeInfixOp {
1359 .base = undefined,
1360 .lhs = dest_ptr.get(),
1361 .op_token = token,
1362 .op = ast.NodeInfixOp.InfixOp.ErrorUnion,
1363 .rhs = undefined,
1364 }
1365 );
1366 stack.append(State { .TypeExprEnd = dest_ptr }) catch unreachable;
1367 try stack.append(State { .PrefixOpExpression = DestPtr { .Field = &node.rhs } });
1181 Token.Id.RBrace => {
1182 block.rbrace = token;
13681183 continue;
13691184 },
13701185 else => {
13711186 self.putBackToken(token);
1187 stack.append(State { .Block = block }) catch unreachable;
1188 try stack.append(State { .Statement = block });
13721189 continue;
13731190 },
13741191 }
13751192 },
1376
1377 State.PrefixOpExpression => |dest_ptr| {
1378 const token = self.getNextToken();
1379 if (tokenIdToPrefixOp(token.id)) |prefix_id| {
1380 var node = try self.createToDestNode(arena, dest_ptr, ast.NodePrefixOp,
1381 ast.NodePrefixOp {
1382 .base = undefined,
1383 .op_token = token,
1384 .op = prefix_id,
1385 .rhs = undefined,
1386 }
1387 );
1388
1389 if (token.id == Token.Id.AsteriskAsterisk) {
1390 const child = try self.createNode(arena, ast.NodePrefixOp,
1391 ast.NodePrefixOp {
1392 .base = undefined,
1393 .op_token = token,
1394 .op = prefix_id,
1395 .rhs = undefined,
1396 }
1397 );
1398 node.rhs = &child.base;
1399 node = child;
1400 }
1401
1402 stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable;
1403 if (node.op == ast.NodePrefixOp.PrefixOp.AddrOf) {
1404 try stack.append(State { .AddrOfModifiers = &node.op.AddrOf });
1405 }
1406 continue;
1407 } else {
1408 self.putBackToken(token);
1409 stack.append(State { .SuffixOpExpressionBegin = dest_ptr }) catch unreachable;
1410 continue;
1411 }
1412 },
1413
1414 State.SuffixOpExpressionBegin => |dest_ptr| {
1193 State.Statement => |block| {
1194 const comments = try self.eatComments(arena);
14151195 const token = self.getNextToken();
14161196 switch (token.id) {
1417 Token.Id.Keyword_async => {
1418 const async_node = try self.createNode(arena, ast.NodeAsyncAttribute,
1419 ast.NodeAsyncAttribute {
1420 .base = undefined,
1421 .async_token = token,
1422 .allocator_type = null,
1423 .rangle_bracket = null,
1424 }
1425 );
1197 Token.Id.Keyword_comptime => {
14261198 stack.append(State {
1427 .AsyncEnd = AsyncEndCtx {
1428 .dest_ptr = dest_ptr,
1429 .attribute = async_node,
1199 .ComptimeStatement = ComptimeStatementCtx {
1200 .comptime_token = token,
1201 .block = block,
14301202 }
14311203 }) catch unreachable;
1432 try stack.append(State { .SuffixOpExpressionEnd = dest_ptr });
1433 try stack.append(State { .PrimaryExpression = dest_ptr });
1434
1435 const langle_bracket = self.getNextToken();
1436 if (langle_bracket.id != Token.Id.AngleBracketLeft) {
1437 self.putBackToken(langle_bracket);
1438 continue;
1439 }
1440
1441 async_node.rangle_bracket = Token(undefined);
1442 try stack.append(State {
1443 .ExpectTokenSave = ExpectTokenSave {
1444 .id = Token.Id.AngleBracketRight,
1445 .ptr = &??async_node.rangle_bracket,
1446 }
1447 });
1448 try stack.append(State { .TypeExprBegin = DestPtr { .NullableField = &async_node.allocator_type } });
14491204 continue;
14501205 },
1451 else => {
1452 self.putBackToken(token);
1453 stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
1454 try stack.append(State { .PrimaryExpression = dest_ptr });
1206 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1207 stack.append(State {
1208 .VarDecl = VarDeclCtx {
1209 .comments = comments,
1210 .visib_token = null,
1211 .comptime_token = null,
1212 .extern_export_token = null,
1213 .lib_name = null,
1214 .mut_token = token,
1215 .list = &block.statements,
1216 }
1217 }) catch unreachable;
14551218 continue;
1456 }
1457 }
1458 },
1459
1460 State.SuffixOpExpressionEnd => |dest_ptr| {
1461 const token = self.getNextToken();
1462 switch (token.id) {
1463 Token.Id.LParen => {
1464 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSuffixOp,
1465 ast.NodeSuffixOp {
1219 },
1220 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
1221 const node = try self.createAttachNode(arena, &block.statements, ast.Node.Defer,
1222 ast.Node.Defer {
14661223 .base = undefined,
1467 .lhs = dest_ptr.get(),
1468 .op = ast.NodeSuffixOp.SuffixOp {
1469 .Call = ast.NodeSuffixOp.CallInfo {
1470 .params = ArrayList(&ast.Node).init(arena),
1471 .async_attr = null,
1472 }
1224 .defer_token = token,
1225 .kind = switch (token.id) {
1226 Token.Id.Keyword_defer => ast.Node.Defer.Kind.Unconditional,
1227 Token.Id.Keyword_errdefer => ast.Node.Defer.Kind.Error,
1228 else => unreachable,
14731229 },
1474 .rtoken = undefined,
1230 .expr = undefined,
14751231 }
14761232 );
1477 stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
1478 try stack.append(State {
1479 .ExprListItemOrEnd = ExprListCtx {
1480 .list = &node.op.Call.params,
1481 .end = Token.Id.RParen,
1482 .ptr = &node.rtoken,
1483 }
1484 });
1233 stack.append(State { .Semicolon = &&node.base }) catch unreachable;
1234 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
14851235 continue;
14861236 },
1487 Token.Id.LBracket => {
1488 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSuffixOp,
1489 ast.NodeSuffixOp {
1237 Token.Id.LBrace => {
1238 const inner_block = try self.createAttachNode(arena, &block.statements, ast.Node.Block,
1239 ast.Node.Block {
14901240 .base = undefined,
1491 .lhs = dest_ptr.get(),
1492 .op = ast.NodeSuffixOp.SuffixOp {
1493 .ArrayAccess = undefined,
1494 },
1495 .rtoken = undefined
1241 .label = null,
1242 .lbrace = token,
1243 .statements = ArrayList(&ast.Node).init(arena),
1244 .rbrace = undefined,
14961245 }
14971246 );
1498 stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
1499 try stack.append(State { .SliceOrArrayAccess = node });
1500 try stack.append(State { .Expression = DestPtr { .Field = &node.op.ArrayAccess }});
1247 stack.append(State { .Block = inner_block }) catch unreachable;
15011248 continue;
15021249 },
1503 Token.Id.Period => {
1504 const identifier = try self.createLiteral(arena, ast.NodeIdentifier, Token(undefined));
1505 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1506 ast.NodeInfixOp {
1507 .base = undefined,
1508 .lhs = dest_ptr.get(),
1509 .op_token = token,
1510 .op = ast.NodeInfixOp.InfixOp.Period,
1511 .rhs = &identifier.base,
1512 }
1513 );
1514 stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
1515 try stack.append(State {
1516 .ExpectTokenSave = ExpectTokenSave {
1517 .id = Token.Id.Identifier,
1518 .ptr = &identifier.token
1250 else => {
1251 self.putBackToken(token);
1252 const statememt = try block.statements.addOne();
1253 stack.append(State { .Semicolon = statememt }) catch unreachable;
1254 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = statememt } });
1255 continue;
1256 }
1257 }
1258 },
1259 State.ComptimeStatement => |ctx| {
1260 const comments = try self.eatComments(arena);
1261 const token = self.getNextToken();
1262 switch (token.id) {
1263 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1264 stack.append(State {
1265 .VarDecl = VarDeclCtx {
1266 .comments = comments,
1267 .visib_token = null,
1268 .comptime_token = ctx.comptime_token,
1269 .extern_export_token = null,
1270 .lib_name = null,
1271 .mut_token = token,
1272 .list = &ctx.block.statements,
15191273 }
1520 });
1274 }) catch unreachable;
15211275 continue;
15221276 },
15231277 else => {
15241278 self.putBackToken(token);
1279 self.putBackToken(ctx.comptime_token);
1280 const statememt = try ctx.block.statements.addOne();
1281 stack.append(State { .Semicolon = statememt }) catch unreachable;
1282 try stack.append(State { .Expression = OptionalCtx { .Required = statememt } });
15251283 continue;
1526 },
1284 }
1285 }
1286 },
1287 State.Semicolon => |node_ptr| {
1288 const node = *node_ptr;
1289 if (requireSemiColon(node)) {
1290 stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable;
1291 continue;
15271292 }
1293 continue;
15281294 },
15291295
1530 State.PrimaryExpression => |dest_ptr| {
1296
1297 State.AsmOutputItems => |items| {
1298 const lbracket = self.getNextToken();
1299 if (lbracket.id != Token.Id.LBracket) {
1300 self.putBackToken(lbracket);
1301 continue;
1302 }
1303
1304 const node = try self.createNode(arena, ast.Node.AsmOutput,
1305 ast.Node.AsmOutput {
1306 .base = undefined,
1307 .symbolic_name = undefined,
1308 .constraint = undefined,
1309 .kind = undefined,
1310 }
1311 );
1312 try items.append(node);
1313
1314 stack.append(State { .AsmOutputItems = items }) catch unreachable;
1315 try stack.append(State { .IfToken = Token.Id.Comma });
1316 try stack.append(State { .ExpectToken = Token.Id.RParen });
1317 try stack.append(State { .AsmOutputReturnOrType = node });
1318 try stack.append(State { .ExpectToken = Token.Id.LParen });
1319 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1320 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1321 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1322 continue;
1323 },
1324 State.AsmOutputReturnOrType => |node| {
15311325 const token = self.getNextToken();
15321326 switch (token.id) {
1533 Token.Id.IntegerLiteral => {
1534 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeStringLiteral, token)).base);
1535 continue;
1536 },
1537 Token.Id.FloatLiteral => {
1538 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeFloatLiteral, token)).base);
1539 continue;
1540 },
1541 Token.Id.CharLiteral => {
1542 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeCharLiteral, token)).base);
1543 continue;
1544 },
1545 Token.Id.Keyword_undefined => {
1546 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeUndefinedLiteral, token)).base);
1547 continue;
1548 },
1549 Token.Id.Keyword_true, Token.Id.Keyword_false => {
1550 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeBoolLiteral, token)).base);
1551 continue;
1552 },
1553 Token.Id.Keyword_null => {
1554 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeNullLiteral, token)).base);
1555 continue;
1556 },
1557 Token.Id.Keyword_this => {
1558 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeThisLiteral, token)).base);
1559 continue;
1560 },
1561 Token.Id.Keyword_var => {
1562 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeVarType, token)).base);
1563 continue;
1564 },
1565 Token.Id.Keyword_unreachable => {
1566 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeUnreachable, token)).base);
1327 Token.Id.Identifier => {
1328 node.kind = ast.Node.AsmOutput.Kind { .Variable = try self.createLiteral(arena, ast.Node.Identifier, token) };
15671329 continue;
15681330 },
1569 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
1570 dest_ptr.store((try self.parseStringLiteral(arena, token)) ?? unreachable);
1571 },
1572 Token.Id.LParen => {
1573 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeGroupedExpression,
1574 ast.NodeGroupedExpression {
1575 .base = undefined,
1576 .lparen = token,
1577 .expr = undefined,
1578 .rparen = undefined,
1579 }
1580 );
1581 stack.append(State {
1582 .ExpectTokenSave = ExpectTokenSave {
1583 .id = Token.Id.RParen,
1584 .ptr = &node.rparen,
1585 }
1586 }) catch unreachable;
1587 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
1331 Token.Id.Arrow => {
1332 node.kind = ast.Node.AsmOutput.Kind { .Return = undefined };
1333 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.kind.Return } });
15881334 continue;
15891335 },
1590 Token.Id.Builtin => {
1591 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeBuiltinCall,
1592 ast.NodeBuiltinCall {
1593 .base = undefined,
1594 .builtin_token = token,
1595 .params = ArrayList(&ast.Node).init(arena),
1596 .rparen_token = undefined,
1597 }
1598 );
1599 stack.append(State {
1600 .ExprListItemOrEnd = ExprListCtx {
1601 .list = &node.params,
1602 .end = Token.Id.RParen,
1603 .ptr = &node.rparen_token,
1604 }
1605 }) catch unreachable;
1606 try stack.append(State { .ExpectToken = Token.Id.LParen, });
1607 continue;
1336 else => {
1337 return self.parseError(token, "expected '->' or {}, found {}",
1338 @tagName(Token.Id.Identifier),
1339 @tagName(token.id));
16081340 },
1609 Token.Id.LBracket => {
1610 const rbracket_token = self.getNextToken();
1611 if (rbracket_token.id == Token.Id.RBracket) {
1612 const node = try self.createToDestNode(arena, dest_ptr, ast.NodePrefixOp,
1613 ast.NodePrefixOp {
1614 .base = undefined,
1615 .op_token = token,
1616 .op = ast.NodePrefixOp.PrefixOp{
1617 .SliceType = ast.NodePrefixOp.AddrOfInfo {
1618 .align_expr = null,
1619 .bit_offset_start_token = null,
1620 .bit_offset_end_token = null,
1621 .const_token = null,
1622 .volatile_token = null,
1623 }
1624 },
1625 .rhs = undefined,
1626 }
1627 );
1628 dest_ptr.store(&node.base);
1629 stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable;
1630 try stack.append(State { .AddrOfModifiers = &node.op.SliceType });
1631 continue;
1632 }
1341 }
1342 },
1343 State.AsmInputItems => |items| {
1344 const lbracket = self.getNextToken();
1345 if (lbracket.id != Token.Id.LBracket) {
1346 self.putBackToken(lbracket);
1347 continue;
1348 }
16331349
1634 self.putBackToken(rbracket_token);
1350 const node = try self.createNode(arena, ast.Node.AsmInput,
1351 ast.Node.AsmInput {
1352 .base = undefined,
1353 .symbolic_name = undefined,
1354 .constraint = undefined,
1355 .expr = undefined,
1356 }
1357 );
1358 try items.append(node);
16351359
1636 const node = try self.createToDestNode(arena, dest_ptr, ast.NodePrefixOp,
1637 ast.NodePrefixOp {
1638 .base = undefined,
1639 .op_token = token,
1640 .op = ast.NodePrefixOp.PrefixOp{
1641 .ArrayType = undefined,
1642 },
1643 .rhs = undefined,
1644 }
1645 );
1646 stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable;
1647 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1648 try stack.append(State { .Expression = DestPtr { .Field = &node.op.ArrayType } });
1360 stack.append(State { .AsmInputItems = items }) catch unreachable;
1361 try stack.append(State { .IfToken = Token.Id.Comma });
1362 try stack.append(State { .ExpectToken = Token.Id.RParen });
1363 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
1364 try stack.append(State { .ExpectToken = Token.Id.LParen });
1365 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1366 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1367 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1368 continue;
1369 },
1370 State.AsmClopperItems => |items| {
1371 stack.append(State { .AsmClopperItems = items }) catch unreachable;
1372 try stack.append(State { .IfToken = Token.Id.Comma });
1373 try stack.append(State { .StringLiteral = OptionalCtx { .Required = try items.addOne() } });
1374 continue;
1375 },
16491376
1650 },
1651 Token.Id.Keyword_error => {
1652 if (self.eatToken(Token.Id.LBrace) == null) {
1653 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeErrorType, token)).base);
1654 continue;
1655 }
16561377
1657 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeErrorSetDecl,
1658 ast.NodeErrorSetDecl {
1659 .base = undefined,
1660 .error_token = token,
1661 .decls = ArrayList(&ast.NodeIdentifier).init(arena),
1662 .rbrace_token = undefined,
1663 }
1664 );
1378 State.ExprListItemOrEnd => |list_state| {
1379 if (self.eatToken(list_state.end)) |token| {
1380 *list_state.ptr = token;
1381 continue;
1382 }
16651383
1666 stack.append(State {
1667 .IdentifierListItemOrEnd = ListSave(&ast.NodeIdentifier) {
1668 .list = &node.decls,
1669 .ptr = &node.rbrace_token,
1670 }
1671 }) catch unreachable;
1672 continue;
1673 },
1674 Token.Id.Keyword_packed => {
1675 stack.append(State {
1676 .ContainerExtern = ContainerExternCtx {
1677 .dest_ptr = dest_ptr,
1678 .ltoken = token,
1679 .layout = ast.NodeContainerDecl.Layout.Packed,
1680 },
1681 }) catch unreachable;
1682 },
1683 Token.Id.Keyword_extern => {
1684 const next = self.getNextToken();
1685 if (next.id == Token.Id.Keyword_fn) {
1686 const fn_proto = try self.createToDestNode(arena, dest_ptr, ast.NodeFnProto,
1687 ast.NodeFnProto {
1688 .base = undefined,
1689 .visib_token = null,
1690 .name_token = null,
1691 .fn_token = next,
1692 .params = ArrayList(&ast.Node).init(arena),
1693 .return_type = undefined,
1694 .var_args_token = null,
1695 .extern_export_inline_token = token,
1696 .cc_token = null,
1697 .async_attr = null,
1698 .body_node = null,
1699 .lib_name = null,
1700 .align_expr = null,
1701 }
1702 );
1703 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1704 continue;
1705 }
1384 stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable;
1385 try stack.append(State { .Expression = OptionalCtx { .Required = try list_state.list.addOne() } });
1386 continue;
1387 },
1388 State.ExprListCommaOrEnd => |list_state| {
1389 if (try self.expectCommaOrEnd(list_state.end)) |end| {
1390 *list_state.ptr = end;
1391 continue;
1392 } else {
1393 stack.append(State { .ExprListItemOrEnd = list_state }) catch unreachable;
1394 continue;
1395 }
1396 },
1397 State.FieldInitListItemOrEnd => |list_state| {
1398 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1399 *list_state.ptr = rbrace;
1400 continue;
1401 }
17061402
1707 self.putBackToken(next);
1708 stack.append(State {
1709 .ContainerExtern = ContainerExternCtx {
1710 .dest_ptr = dest_ptr,
1711 .ltoken = token,
1712 .layout = ast.NodeContainerDecl.Layout.Extern,
1713 },
1714 }) catch unreachable;
1715 },
1716 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
1717 self.putBackToken(token);
1718 stack.append(State {
1719 .ContainerExtern = ContainerExternCtx {
1720 .dest_ptr = dest_ptr,
1721 .ltoken = token,
1722 .layout = ast.NodeContainerDecl.Layout.Auto,
1723 },
1724 }) catch unreachable;
1725 },
1726 Token.Id.Identifier => {
1727 const next = self.getNextToken();
1728 if (next.id != Token.Id.Colon) {
1729 self.putBackToken(next);
1730 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeIdentifier, token)).base);
1731 continue;
1403 const node = try self.createNode(arena, ast.Node.FieldInitializer,
1404 ast.Node.FieldInitializer {
1405 .base = undefined,
1406 .period_token = undefined,
1407 .name_token = undefined,
1408 .expr = undefined,
1409 }
1410 );
1411 try list_state.list.append(node);
1412
1413 stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
1414 try stack.append(State { .Expression = OptionalCtx{ .Required = &node.expr } });
1415 try stack.append(State { .ExpectToken = Token.Id.Equal });
1416 try stack.append(State {
1417 .ExpectTokenSave = ExpectTokenSave {
1418 .id = Token.Id.Identifier,
1419 .ptr = &node.name_token,
1420 }
1421 });
1422 try stack.append(State {
1423 .ExpectTokenSave = ExpectTokenSave {
1424 .id = Token.Id.Period,
1425 .ptr = &node.period_token,
1426 }
1427 });
1428 continue;
1429 },
1430 State.FieldInitListCommaOrEnd => |list_state| {
1431 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1432 *list_state.ptr = end;
1433 continue;
1434 } else {
1435 stack.append(State { .FieldInitListItemOrEnd = list_state }) catch unreachable;
1436 continue;
1437 }
1438 },
1439 State.FieldListCommaOrEnd => |container_decl| {
1440 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1441 container_decl.rbrace_token = end;
1442 continue;
1443 } else {
1444 stack.append(State { .ContainerDecl = container_decl }) catch unreachable;
1445 continue;
1446 }
1447 },
1448 State.IdentifierListItemOrEnd => |list_state| {
1449 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1450 *list_state.ptr = rbrace;
1451 continue;
1452 }
1453
1454 stack.append(State { .IdentifierListCommaOrEnd = list_state }) catch unreachable;
1455 try stack.append(State { .Identifier = OptionalCtx { .Required = try list_state.list.addOne() } });
1456 continue;
1457 },
1458 State.IdentifierListCommaOrEnd => |list_state| {
1459 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1460 *list_state.ptr = end;
1461 continue;
1462 } else {
1463 stack.append(State { .IdentifierListItemOrEnd = list_state }) catch unreachable;
1464 continue;
1465 }
1466 },
1467 State.SwitchCaseOrEnd => |list_state| {
1468 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1469 *list_state.ptr = rbrace;
1470 continue;
1471 }
1472
1473 const node = try self.createNode(arena, ast.Node.SwitchCase,
1474 ast.Node.SwitchCase {
1475 .base = undefined,
1476 .items = ArrayList(&ast.Node).init(arena),
1477 .payload = null,
1478 .expr = undefined,
1479 }
1480 );
1481 try list_state.list.append(node);
1482 stack.append(State { .SwitchCaseCommaOrEnd = list_state }) catch unreachable;
1483 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .Required = &node.expr } });
1484 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
1485 try stack.append(State { .SwitchCaseFirstItem = &node.items });
1486 continue;
1487 },
1488 State.SwitchCaseCommaOrEnd => |list_state| {
1489 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1490 *list_state.ptr = end;
1491 continue;
1492 } else {
1493 stack.append(State { .SwitchCaseOrEnd = list_state }) catch unreachable;
1494 continue;
1495 }
1496 },
1497 State.SwitchCaseFirstItem => |case_items| {
1498 const token = self.getNextToken();
1499 if (token.id == Token.Id.Keyword_else) {
1500 const else_node = try self.createAttachNode(arena, case_items, ast.Node.SwitchElse,
1501 ast.Node.SwitchElse {
1502 .base = undefined,
1503 .token = token,
17321504 }
1505 );
1506 try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
1507 continue;
1508 } else {
1509 self.putBackToken(token);
1510 try stack.append(State { .SwitchCaseItem = case_items });
1511 continue;
1512 }
1513 },
1514 State.SwitchCaseItem => |case_items| {
1515 stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
1516 try stack.append(State { .RangeExpressionBegin = OptionalCtx { .Required = try case_items.addOne() } });
1517 },
1518 State.SwitchCaseItemCommaOrEnd => |case_items| {
1519 if ((try self.expectCommaOrEnd(Token.Id.EqualAngleBracketRight)) == null) {
1520 stack.append(State { .SwitchCaseItem = case_items }) catch unreachable;
1521 }
1522 continue;
1523 },
17331524
1734 stack.append(State {
1735 .LabeledExpression = LabelCtx {
1736 .label = token,
1737 .dest_ptr = dest_ptr
1738 }
1739 }) catch unreachable;
1740 continue;
1741 },
1742 Token.Id.Keyword_fn => {
1743 const fn_proto = try self.createToDestNode(arena, dest_ptr, ast.NodeFnProto,
1744 ast.NodeFnProto {
1745 .base = undefined,
1746 .visib_token = null,
1747 .name_token = null,
1748 .fn_token = token,
1749 .params = ArrayList(&ast.Node).init(arena),
1750 .return_type = undefined,
1751 .var_args_token = null,
1752 .extern_export_inline_token = null,
1753 .cc_token = null,
1754 .async_attr = null,
1755 .body_node = null,
1756 .lib_name = null,
1757 .align_expr = null,
1758 }
1759 );
1760 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1761 continue;
1762 },
1763 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
1764 const fn_token = (try self.expectToken(&stack, Token.Id.Keyword_fn)) ?? continue;
1765 const fn_proto = try self.createToDestNode(arena, dest_ptr, ast.NodeFnProto,
1766 ast.NodeFnProto {
1767 .base = undefined,
1768 .visib_token = null,
1769 .name_token = null,
1770 .fn_token = fn_token,
1771 .params = ArrayList(&ast.Node).init(arena),
1772 .return_type = undefined,
1773 .var_args_token = null,
1774 .extern_export_inline_token = null,
1775 .cc_token = token,
1776 .async_attr = null,
1777 .body_node = null,
1778 .lib_name = null,
1779 .align_expr = null,
1780 }
1781 );
1782 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1783 continue;
1784 },
1785 Token.Id.Keyword_asm => {
1786 const is_volatile = blk: {
1787 const volatile_token = self.getNextToken();
1788 if (volatile_token.id != Token.Id.Keyword_volatile) {
1789 self.putBackToken(volatile_token);
1790 break :blk false;
1791 }
1792 break :blk true;
1793 };
1794 _ = (try self.expectToken(&stack, Token.Id.LParen)) ?? continue;
17951525
1796 const template_token = self.getNextToken();
1797 const template = (try self.parseStringLiteral(arena, template_token)) ?? {
1798 try self.parseError(&stack, template_token, "expected string literal, found {}", @tagName(template_token.id));
1799 continue;
1800 };
1801 // TODO parse template
1526 State.SuspendBody => |suspend_node| {
1527 if (suspend_node.payload != null) {
1528 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = &suspend_node.body } });
1529 }
1530 continue;
1531 },
1532 State.AsyncAllocator => |async_node| {
1533 if (self.eatToken(Token.Id.AngleBracketLeft) == null) {
1534 continue;
1535 }
18021536
1803 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeAsm,
1804 ast.NodeAsm {
1805 .base = undefined,
1806 .asm_token = token,
1807 .is_volatile = is_volatile,
1808 .template = template,
1809 //.tokens = ArrayList(ast.NodeAsm.AsmToken).init(arena),
1810 .outputs = ArrayList(&ast.NodeAsmOutput).init(arena),
1811 .inputs = ArrayList(&ast.NodeAsmInput).init(arena),
1812 .cloppers = ArrayList(&ast.Node).init(arena),
1813 .rparen = undefined,
1814 }
1815 );
1816 stack.append(State {
1817 .ExpectTokenSave = ExpectTokenSave {
1818 .id = Token.Id.RParen,
1819 .ptr = &node.rparen,
1820 }
1821 }) catch unreachable;
1822 try stack.append(State { .AsmClopperItems = &node.cloppers });
1823 try stack.append(State { .IfToken = Token.Id.Colon });
1824 try stack.append(State { .AsmInputItems = &node.inputs });
1825 try stack.append(State { .IfToken = Token.Id.Colon });
1826 try stack.append(State { .AsmOutputItems = &node.outputs });
1827 try stack.append(State { .IfToken = Token.Id.Colon });
1828 },
1829 Token.Id.Keyword_inline => {
1830 stack.append(State {
1831 .Inline = InlineCtx {
1832 .label = null,
1833 .inline_token = token,
1834 .dest_ptr = dest_ptr,
1835 }
1836 }) catch unreachable;
1537 async_node.rangle_bracket = Token(undefined);
1538 try stack.append(State {
1539 .ExpectTokenSave = ExpectTokenSave {
1540 .id = Token.Id.AngleBracketRight,
1541 .ptr = &??async_node.rangle_bracket,
1542 }
1543 });
1544 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &async_node.allocator_type } });
1545 continue;
1546 },
1547 State.AsyncEnd => |ctx| {
1548 const node = ctx.ctx.get() ?? continue;
1549
1550 switch (node.id) {
1551 ast.Node.Id.FnProto => {
1552 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", node);
1553 fn_proto.async_attr = ctx.attribute;
18371554 continue;
18381555 },
1839 else => {
1840 if (!try self.parseBlockExpr(&stack, arena, dest_ptr, token)) {
1841 try self.parseError(&stack, token, "expected primary expression, found {}", @tagName(token.id));
1556 ast.Node.Id.SuffixOp => {
1557 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", node);
1558 if (suffix_op.op == ast.Node.SuffixOp.Op.Call) {
1559 suffix_op.op.Call.async_attr = ctx.attribute;
1560 continue;
18421561 }
1843 continue;
1562
1563 return self.parseError(node.firstToken(), "expected {}, found {}.",
1564 @tagName(ast.Node.SuffixOp.Op.Call),
1565 @tagName(suffix_op.op));
1566 },
1567 else => {
1568 return self.parseError(node.firstToken(), "expected {} or {}, found {}.",
1569 @tagName(ast.Node.SuffixOp.Op.Call),
1570 @tagName(ast.Node.Id.FnProto),
1571 @tagName(node.id));
18441572 }
18451573 }
18461574 },
18471575
1576
1577 State.ExternType => |ctx| {
1578 if (self.eatToken(Token.Id.Keyword_fn)) |fn_token| {
1579 const fn_proto = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.FnProto,
1580 ast.Node.FnProto {
1581 .base = undefined,
1582 .comments = ctx.comments,
1583 .visib_token = null,
1584 .name_token = null,
1585 .fn_token = fn_token,
1586 .params = ArrayList(&ast.Node).init(arena),
1587 .return_type = undefined,
1588 .var_args_token = null,
1589 .extern_export_inline_token = ctx.extern_token,
1590 .cc_token = null,
1591 .async_attr = null,
1592 .body_node = null,
1593 .lib_name = null,
1594 .align_expr = null,
1595 }
1596 );
1597 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1598 continue;
1599 }
1600
1601 stack.append(State {
1602 .ContainerKind = ContainerKindCtx {
1603 .opt_ctx = ctx.opt_ctx,
1604 .ltoken = ctx.extern_token,
1605 .layout = ast.Node.ContainerDecl.Layout.Extern,
1606 },
1607 }) catch unreachable;
1608 continue;
1609 },
18481610 State.SliceOrArrayAccess => |node| {
18491611 var token = self.getNextToken();
1850
18511612 switch (token.id) {
18521613 Token.Id.Ellipsis2 => {
18531614 const start = node.op.ArrayAccess;
1854 node.op = ast.NodeSuffixOp.SuffixOp {
1855 .Slice = ast.NodeSuffixOp.SliceRange {
1615 node.op = ast.Node.SuffixOp.Op {
1616 .Slice = ast.Node.SuffixOp.SliceRange {
18561617 .start = start,
1857 .end = undefined,
1618 .end = null,
18581619 }
18591620 };
18601621
1861 const rbracket_token = self.getNextToken();
1862 if (rbracket_token.id != Token.Id.RBracket) {
1863 self.putBackToken(rbracket_token);
1864 stack.append(State {
1865 .ExpectTokenSave = ExpectTokenSave {
1866 .id = Token.Id.RBracket,
1867 .ptr = &node.rtoken,
1868 }
1869 }) catch unreachable;
1870 try stack.append(State { .Expression = DestPtr { .NullableField = &node.op.Slice.end } });
1871 } else {
1872 node.rtoken = rbracket_token;
1873 }
1622 stack.append(State {
1623 .ExpectTokenSave = ExpectTokenSave {
1624 .id = Token.Id.RBracket,
1625 .ptr = &node.rtoken,
1626 }
1627 }) catch unreachable;
1628 try stack.append(State { .Expression = OptionalCtx { .Optional = &node.op.Slice.end } });
18741629 continue;
18751630 },
18761631 Token.Id.RBracket => {
......@@ -1878,832 +1633,1137 @@ pub const Parser = struct {
18781633 continue;
18791634 },
18801635 else => {
1881 try self.parseError(&stack, token, "expected ']' or '..', found {}", @tagName(token.id));
1882 continue;
1636 return self.parseError(token, "expected ']' or '..', found {}", @tagName(token.id));
18831637 }
18841638 }
18851639 },
1886
1887
1888 State.AsmOutputItems => |items| {
1889 const lbracket = self.getNextToken();
1890 if (lbracket.id != Token.Id.LBracket) {
1891 self.putBackToken(lbracket);
1640 State.SliceOrArrayType => |node| {
1641 if (self.eatToken(Token.Id.RBracket)) |_| {
1642 node.op = ast.Node.PrefixOp.Op {
1643 .SliceType = ast.Node.PrefixOp.AddrOfInfo {
1644 .align_expr = null,
1645 .bit_offset_start_token = null,
1646 .bit_offset_end_token = null,
1647 .const_token = null,
1648 .volatile_token = null,
1649 }
1650 };
1651 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1652 try stack.append(State { .AddrOfModifiers = &node.op.SliceType });
18921653 continue;
18931654 }
18941655
1895 stack.append(State { .AsmOutputItems = items }) catch unreachable;
1896 try stack.append(State { .IfToken = Token.Id.Comma });
1897
1898 const symbolic_name = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
1899 _ = (try self.expectToken(&stack, Token.Id.RBracket)) ?? continue;
1900
1901 const constraint_token = self.getNextToken();
1902 const constraint = (try self.parseStringLiteral(arena, constraint_token)) ?? {
1903 try self.parseError(&stack, constraint_token, "expected string literal, found {}", @tagName(constraint_token.id));
1904 continue;
1905 };
1906
1907 _ = (try self.expectToken(&stack, Token.Id.LParen)) ?? continue;
1908 try stack.append(State { .ExpectToken = Token.Id.RParen });
1909
1910 const node = try self.createNode(arena, ast.NodeAsmOutput,
1911 ast.NodeAsmOutput {
1912 .base = undefined,
1913 .symbolic_name = try self.createLiteral(arena, ast.NodeIdentifier, symbolic_name),
1914 .constraint = constraint,
1915 .kind = undefined,
1916 }
1917 );
1918 try items.append(node);
1919
1920 const symbol_or_arrow = self.getNextToken();
1921 switch (symbol_or_arrow.id) {
1922 Token.Id.Identifier => {
1923 node.kind = ast.NodeAsmOutput.Kind { .Variable = try self.createLiteral(arena, ast.NodeIdentifier, symbol_or_arrow) };
1656 node.op = ast.Node.PrefixOp.Op { .ArrayType = undefined };
1657 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1658 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1659 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayType } });
1660 continue;
1661 },
1662 State.AddrOfModifiers => |addr_of_info| {
1663 var token = self.getNextToken();
1664 switch (token.id) {
1665 Token.Id.Keyword_align => {
1666 stack.append(state) catch unreachable;
1667 if (addr_of_info.align_expr != null) {
1668 return self.parseError(token, "multiple align qualifiers");
1669 }
1670 try stack.append(State { .ExpectToken = Token.Id.RParen });
1671 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &addr_of_info.align_expr} });
1672 try stack.append(State { .ExpectToken = Token.Id.LParen });
1673 continue;
19241674 },
1925 Token.Id.Arrow => {
1926 node.kind = ast.NodeAsmOutput.Kind { .Return = undefined };
1927 try stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.kind.Return } });
1675 Token.Id.Keyword_const => {
1676 stack.append(state) catch unreachable;
1677 if (addr_of_info.const_token != null) {
1678 return self.parseError(token, "duplicate qualifier: const");
1679 }
1680 addr_of_info.const_token = token;
1681 continue;
1682 },
1683 Token.Id.Keyword_volatile => {
1684 stack.append(state) catch unreachable;
1685 if (addr_of_info.volatile_token != null) {
1686 return self.parseError(token, "duplicate qualifier: volatile");
1687 }
1688 addr_of_info.volatile_token = token;
1689 continue;
19281690 },
19291691 else => {
1930 try self.parseError(&stack, symbol_or_arrow, "expected '->' or {}, found {}",
1931 @tagName(Token.Id.Identifier),
1932 @tagName(symbol_or_arrow.id));
1692 self.putBackToken(token);
19331693 continue;
19341694 },
19351695 }
19361696 },
19371697
1938 State.AsmInputItems => |items| {
1939 const lbracket = self.getNextToken();
1940 if (lbracket.id != Token.Id.LBracket) {
1941 self.putBackToken(lbracket);
1942 continue;
1943 }
1944
1945 stack.append(State { .AsmInputItems = items }) catch unreachable;
1946 try stack.append(State { .IfToken = Token.Id.Comma });
19471698
1948 const symbolic_name = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
1949 _ = (try self.expectToken(&stack, Token.Id.RBracket)) ?? continue;
1699 State.Payload => |opt_ctx| {
1700 const token = self.getNextToken();
1701 if (token.id != Token.Id.Pipe) {
1702 if (opt_ctx != OptionalCtx.Optional) {
1703 return self.parseError(token, "expected {}, found {}.",
1704 @tagName(Token.Id.Pipe),
1705 @tagName(token.id));
1706 }
19501707
1951 const constraint_token = self.getNextToken();
1952 const constraint = (try self.parseStringLiteral(arena, constraint_token)) ?? {
1953 try self.parseError(&stack, constraint_token, "expected string literal, found {}", @tagName(constraint_token.id));
1708 self.putBackToken(token);
19541709 continue;
1955 };
1956
1957 _ = (try self.expectToken(&stack, Token.Id.LParen)) ?? continue;
1958 try stack.append(State { .ExpectToken = Token.Id.RParen });
1710 }
19591711
1960 const node = try self.createNode(arena, ast.NodeAsmInput,
1961 ast.NodeAsmInput {
1712 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.Payload,
1713 ast.Node.Payload {
19621714 .base = undefined,
1963 .symbolic_name = try self.createLiteral(arena, ast.NodeIdentifier, symbolic_name),
1964 .constraint = constraint,
1965 .expr = undefined,
1715 .lpipe = token,
1716 .error_symbol = undefined,
1717 .rpipe = undefined
19661718 }
19671719 );
1968 try items.append(node);
1969 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
1970 },
1971
1972 State.AsmClopperItems => |items| {
1973 const string_token = self.getNextToken();
1974 const string = (try self.parseStringLiteral(arena, string_token)) ?? {
1975 self.putBackToken(string_token);
1976 continue;
1977 };
1978 try items.append(string);
19791720
1980 stack.append(State { .AsmClopperItems = items }) catch unreachable;
1981 try stack.append(State { .IfToken = Token.Id.Comma });
1721 stack.append(State {
1722 .ExpectTokenSave = ExpectTokenSave {
1723 .id = Token.Id.Pipe,
1724 .ptr = &node.rpipe,
1725 }
1726 }) catch unreachable;
1727 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.error_symbol } });
1728 continue;
19821729 },
1730 State.PointerPayload => |opt_ctx| {
1731 const token = self.getNextToken();
1732 if (token.id != Token.Id.Pipe) {
1733 if (opt_ctx != OptionalCtx.Optional) {
1734 return self.parseError(token, "expected {}, found {}.",
1735 @tagName(Token.Id.Pipe),
1736 @tagName(token.id));
1737 }
19831738
1984 State.ExprListItemOrEnd => |list_state| {
1985 var token = self.getNextToken();
1986
1987 const IdTag = @TagType(Token.Id);
1988 if (IdTag(list_state.end) == token.id) {
1989 *list_state.ptr = token;
1739 self.putBackToken(token);
19901740 continue;
19911741 }
19921742
1993 self.putBackToken(token);
1994 stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable;
1995 try stack.append(State { .Expression = DestPtr{ .Field = try list_state.list.addOne() } });
1743 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PointerPayload,
1744 ast.Node.PointerPayload {
1745 .base = undefined,
1746 .lpipe = token,
1747 .ptr_token = null,
1748 .value_symbol = undefined,
1749 .rpipe = undefined
1750 }
1751 );
1752
1753 stack.append(State {
1754 .ExpectTokenSave = ExpectTokenSave {
1755 .id = Token.Id.Pipe,
1756 .ptr = &node.rpipe,
1757 }
1758 }) catch unreachable;
1759 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1760 try stack.append(State {
1761 .OptionalTokenSave = OptionalTokenSave {
1762 .id = Token.Id.Asterisk,
1763 .ptr = &node.ptr_token,
1764 }
1765 });
1766 continue;
19961767 },
1768 State.PointerIndexPayload => |opt_ctx| {
1769 const token = self.getNextToken();
1770 if (token.id != Token.Id.Pipe) {
1771 if (opt_ctx != OptionalCtx.Optional) {
1772 return self.parseError(token, "expected {}, found {}.",
1773 @tagName(Token.Id.Pipe),
1774 @tagName(token.id));
1775 }
19971776
1998 State.FieldInitListItemOrEnd => |list_state| {
1999 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
2000 *list_state.ptr = rbrace;
1777 self.putBackToken(token);
20011778 continue;
20021779 }
20031780
2004 const node = try self.createNode(arena, ast.NodeFieldInitializer,
2005 ast.NodeFieldInitializer {
1781 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PointerIndexPayload,
1782 ast.Node.PointerIndexPayload {
20061783 .base = undefined,
2007 .period_token = undefined,
2008 .name_token = undefined,
2009 .expr = undefined,
1784 .lpipe = token,
1785 .ptr_token = null,
1786 .value_symbol = undefined,
1787 .index_symbol = null,
1788 .rpipe = undefined
20101789 }
20111790 );
2012 try list_state.list.append(node);
20131791
2014 stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
2015 try stack.append(State { .Expression = DestPtr{.Field = &node.expr} });
2016 try stack.append(State { .ExpectToken = Token.Id.Equal });
2017 try stack.append(State {
1792 stack.append(State {
20181793 .ExpectTokenSave = ExpectTokenSave {
2019 .id = Token.Id.Identifier,
2020 .ptr = &node.name_token,
1794 .id = Token.Id.Pipe,
1795 .ptr = &node.rpipe,
20211796 }
2022 });
1797 }) catch unreachable;
1798 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.index_symbol } });
1799 try stack.append(State { .IfToken = Token.Id.Comma });
1800 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
20231801 try stack.append(State {
2024 .ExpectTokenSave = ExpectTokenSave {
2025 .id = Token.Id.Period,
2026 .ptr = &node.period_token,
1802 .OptionalTokenSave = OptionalTokenSave {
1803 .id = Token.Id.Asterisk,
1804 .ptr = &node.ptr_token,
20271805 }
20281806 });
1807 continue;
20291808 },
20301809
2031 State.IdentifierListItemOrEnd => |list_state| {
2032 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
2033 *list_state.ptr = rbrace;
2034 continue;
2035 }
20361810
2037 const node = try self.createLiteral(arena, ast.NodeIdentifier, Token(undefined));
2038 try list_state.list.append(node);
1811 State.Expression => |opt_ctx| {
1812 const token = self.getNextToken();
1813 switch (token.id) {
1814 Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => {
1815 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.ControlFlowExpression,
1816 ast.Node.ControlFlowExpression {
1817 .base = undefined,
1818 .ltoken = token,
1819 .kind = undefined,
1820 .rhs = null,
1821 }
1822 );
20391823
2040 stack.append(State { .IdentifierListCommaOrEnd = list_state }) catch unreachable;
2041 try stack.append(State {
2042 .ExpectTokenSave = ExpectTokenSave {
2043 .id = Token.Id.Identifier,
2044 .ptr = &node.token,
1824 stack.append(State { .Expression = OptionalCtx { .Optional = &node.rhs } }) catch unreachable;
1825
1826 switch (token.id) {
1827 Token.Id.Keyword_break => {
1828 node.kind = ast.Node.ControlFlowExpression.Kind { .Break = null };
1829 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Break } });
1830 try stack.append(State { .IfToken = Token.Id.Colon });
1831 },
1832 Token.Id.Keyword_continue => {
1833 node.kind = ast.Node.ControlFlowExpression.Kind { .Continue = null };
1834 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Continue } });
1835 try stack.append(State { .IfToken = Token.Id.Colon });
1836 },
1837 Token.Id.Keyword_return => {
1838 node.kind = ast.Node.ControlFlowExpression.Kind.Return;
1839 },
1840 else => unreachable,
1841 }
1842 continue;
1843 },
1844 Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
1845 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
1846 ast.Node.PrefixOp {
1847 .base = undefined,
1848 .op_token = token,
1849 .op = switch (token.id) {
1850 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{} },
1851 Token.Id.Keyword_cancel => ast.Node.PrefixOp.Op { .Cancel = void{} },
1852 Token.Id.Keyword_resume => ast.Node.PrefixOp.Op { .Resume = void{} },
1853 else => unreachable,
1854 },
1855 .rhs = undefined,
1856 }
1857 );
1858
1859 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1860 continue;
1861 },
1862 else => {
1863 if (!try self.parseBlockExpr(&stack, arena, opt_ctx, token)) {
1864 self.putBackToken(token);
1865 stack.append(State { .UnwrapExpressionBegin = opt_ctx }) catch unreachable;
1866 }
1867 continue;
20451868 }
2046 });
1869 }
20471870 },
1871 State.RangeExpressionBegin => |opt_ctx| {
1872 stack.append(State { .RangeExpressionEnd = opt_ctx }) catch unreachable;
1873 try stack.append(State { .Expression = opt_ctx });
1874 continue;
1875 },
1876 State.RangeExpressionEnd => |opt_ctx| {
1877 const lhs = opt_ctx.get() ?? continue;
20481878
2049 State.SwitchCaseOrEnd => |list_state| {
2050 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
2051 *list_state.ptr = rbrace;
1879 if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
1880 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1881 ast.Node.InfixOp {
1882 .base = undefined,
1883 .lhs = lhs,
1884 .op_token = ellipsis3,
1885 .op = ast.Node.InfixOp.Op.Range,
1886 .rhs = undefined,
1887 }
1888 );
1889 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
20521890 continue;
20531891 }
1892 },
1893 State.AssignmentExpressionBegin => |opt_ctx| {
1894 stack.append(State { .AssignmentExpressionEnd = opt_ctx }) catch unreachable;
1895 try stack.append(State { .Expression = opt_ctx });
1896 continue;
1897 },
20541898
2055 const node = try self.createNode(arena, ast.NodeSwitchCase,
2056 ast.NodeSwitchCase {
2057 .base = undefined,
2058 .items = ArrayList(&ast.Node).init(arena),
2059 .payload = null,
2060 .expr = undefined,
2061 }
2062 );
2063 try list_state.list.append(node);
2064 stack.append(State { .SwitchCaseCommaOrEnd = list_state }) catch unreachable;
2065 try stack.append(State { .AssignmentExpressionBegin = DestPtr{ .Field = &node.expr } });
2066 try stack.append(State { .PointerPayload = &node.payload });
1899 State.AssignmentExpressionEnd => |opt_ctx| {
1900 const lhs = opt_ctx.get() ?? continue;
20671901
2068 const maybe_else = self.getNextToken();
2069 if (maybe_else.id == Token.Id.Keyword_else) {
2070 const else_node = try self.createAttachNode(arena, &node.items, ast.NodeSwitchElse,
2071 ast.NodeSwitchElse {
1902 const token = self.getNextToken();
1903 if (tokenIdToAssignment(token.id)) |ass_id| {
1904 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1905 ast.Node.InfixOp {
20721906 .base = undefined,
2073 .token = maybe_else,
1907 .lhs = lhs,
1908 .op_token = token,
1909 .op = ass_id,
1910 .rhs = undefined,
20741911 }
20751912 );
2076 try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
1913 stack.append(State { .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1914 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
1915 continue;
1916 } else {
1917 self.putBackToken(token);
1918 continue;
1919 }
1920 },
1921
1922 State.UnwrapExpressionBegin => |opt_ctx| {
1923 stack.append(State { .UnwrapExpressionEnd = opt_ctx }) catch unreachable;
1924 try stack.append(State { .BoolOrExpressionBegin = opt_ctx });
1925 continue;
1926 },
1927
1928 State.UnwrapExpressionEnd => |opt_ctx| {
1929 const lhs = opt_ctx.get() ?? continue;
1930
1931 const token = self.getNextToken();
1932 if (tokenIdToUnwrapExpr(token.id)) |unwrap_id| {
1933 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1934 ast.Node.InfixOp {
1935 .base = undefined,
1936 .lhs = lhs,
1937 .op_token = token,
1938 .op = unwrap_id,
1939 .rhs = undefined,
1940 }
1941 );
1942
1943 stack.append(State { .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1944 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
1945
1946 if (node.op == ast.Node.InfixOp.Op.Catch) {
1947 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.op.Catch } });
1948 }
20771949 continue;
20781950 } else {
2079 self.putBackToken(maybe_else);
2080 try stack.append(State { .SwitchCaseItem = &node.items });
1951 self.putBackToken(token);
20811952 continue;
20821953 }
20831954 },
20841955
2085 State.SwitchCaseItem => |case_items| {
2086 stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
2087 try stack.append(State { .RangeExpressionBegin = DestPtr{ .Field = try case_items.addOne() } });
1956 State.BoolOrExpressionBegin => |opt_ctx| {
1957 stack.append(State { .BoolOrExpressionEnd = opt_ctx }) catch unreachable;
1958 try stack.append(State { .BoolAndExpressionBegin = opt_ctx });
1959 continue;
20881960 },
20891961
2090 State.ExprListCommaOrEnd => |list_state| {
2091 try self.commaOrEnd(&stack, list_state.end, list_state.ptr, State { .ExprListItemOrEnd = list_state });
2092 continue;
1962 State.BoolOrExpressionEnd => |opt_ctx| {
1963 const lhs = opt_ctx.get() ?? continue;
1964
1965 if (self.eatToken(Token.Id.Keyword_or)) |or_token| {
1966 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1967 ast.Node.InfixOp {
1968 .base = undefined,
1969 .lhs = lhs,
1970 .op_token = or_token,
1971 .op = ast.Node.InfixOp.Op.BoolOr,
1972 .rhs = undefined,
1973 }
1974 );
1975 stack.append(State { .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1976 try stack.append(State { .BoolAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
1977 continue;
1978 }
20931979 },
20941980
2095 State.FieldInitListCommaOrEnd => |list_state| {
2096 try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .FieldInitListItemOrEnd = list_state });
1981 State.BoolAndExpressionBegin => |opt_ctx| {
1982 stack.append(State { .BoolAndExpressionEnd = opt_ctx }) catch unreachable;
1983 try stack.append(State { .ComparisonExpressionBegin = opt_ctx });
20971984 continue;
20981985 },
20991986
2100 State.FieldListCommaOrEnd => |container_decl| {
2101 try self.commaOrEnd(&stack, Token.Id.RBrace, &container_decl.rbrace_token,
2102 State { .ContainerDecl = container_decl });
2103 continue;
1987 State.BoolAndExpressionEnd => |opt_ctx| {
1988 const lhs = opt_ctx.get() ?? continue;
1989
1990 if (self.eatToken(Token.Id.Keyword_and)) |and_token| {
1991 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
1992 ast.Node.InfixOp {
1993 .base = undefined,
1994 .lhs = lhs,
1995 .op_token = and_token,
1996 .op = ast.Node.InfixOp.Op.BoolAnd,
1997 .rhs = undefined,
1998 }
1999 );
2000 stack.append(State { .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2001 try stack.append(State { .ComparisonExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2002 continue;
2003 }
21042004 },
21052005
2106 State.IdentifierListCommaOrEnd => |list_state| {
2107 try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .IdentifierListItemOrEnd = list_state });
2006 State.ComparisonExpressionBegin => |opt_ctx| {
2007 stack.append(State { .ComparisonExpressionEnd = opt_ctx }) catch unreachable;
2008 try stack.append(State { .BinaryOrExpressionBegin = opt_ctx });
21082009 continue;
21092010 },
21102011
2111 State.SwitchCaseCommaOrEnd => |list_state| {
2112 try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .SwitchCaseOrEnd = list_state });
2113 continue;
2012 State.ComparisonExpressionEnd => |opt_ctx| {
2013 const lhs = opt_ctx.get() ?? continue;
2014
2015 const token = self.getNextToken();
2016 if (tokenIdToComparison(token.id)) |comp_id| {
2017 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2018 ast.Node.InfixOp {
2019 .base = undefined,
2020 .lhs = lhs,
2021 .op_token = token,
2022 .op = comp_id,
2023 .rhs = undefined,
2024 }
2025 );
2026 stack.append(State { .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2027 try stack.append(State { .BinaryOrExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2028 continue;
2029 } else {
2030 self.putBackToken(token);
2031 continue;
2032 }
21142033 },
21152034
2116 State.SwitchCaseItemCommaOrEnd => |case_items| {
2117 try self.commaOrEnd(&stack, Token.Id.EqualAngleBracketRight, null, State { .SwitchCaseItem = case_items });
2035 State.BinaryOrExpressionBegin => |opt_ctx| {
2036 stack.append(State { .BinaryOrExpressionEnd = opt_ctx }) catch unreachable;
2037 try stack.append(State { .BinaryXorExpressionBegin = opt_ctx });
21182038 continue;
21192039 },
21202040
2121 State.Else => |dest| {
2122 const else_token = self.getNextToken();
2123 if (else_token.id != Token.Id.Keyword_else) {
2124 self.putBackToken(else_token);
2041 State.BinaryOrExpressionEnd => |opt_ctx| {
2042 const lhs = opt_ctx.get() ?? continue;
2043
2044 if (self.eatToken(Token.Id.Pipe)) |pipe| {
2045 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2046 ast.Node.InfixOp {
2047 .base = undefined,
2048 .lhs = lhs,
2049 .op_token = pipe,
2050 .op = ast.Node.InfixOp.Op.BitOr,
2051 .rhs = undefined,
2052 }
2053 );
2054 stack.append(State { .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2055 try stack.append(State { .BinaryXorExpressionBegin = OptionalCtx { .Required = &node.rhs } });
21252056 continue;
21262057 }
2058 },
21272059
2128 const node = try self.createNode(arena, ast.NodeElse,
2129 ast.NodeElse {
2130 .base = undefined,
2131 .else_token = else_token,
2132 .payload = null,
2133 .body = undefined,
2134 }
2135 );
2136 *dest = node;
2137
2138 stack.append(State { .Expression = DestPtr { .Field = &node.body } }) catch unreachable;
2139 try stack.append(State { .Payload = &node.payload });
2060 State.BinaryXorExpressionBegin => |opt_ctx| {
2061 stack.append(State { .BinaryXorExpressionEnd = opt_ctx }) catch unreachable;
2062 try stack.append(State { .BinaryAndExpressionBegin = opt_ctx });
2063 continue;
21402064 },
21412065
2142 State.WhileContinueExpr => |dest| {
2143 const colon = self.getNextToken();
2144 if (colon.id != Token.Id.Colon) {
2145 self.putBackToken(colon);
2066 State.BinaryXorExpressionEnd => |opt_ctx| {
2067 const lhs = opt_ctx.get() ?? continue;
2068
2069 if (self.eatToken(Token.Id.Caret)) |caret| {
2070 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2071 ast.Node.InfixOp {
2072 .base = undefined,
2073 .lhs = lhs,
2074 .op_token = caret,
2075 .op = ast.Node.InfixOp.Op.BitXor,
2076 .rhs = undefined,
2077 }
2078 );
2079 stack.append(State { .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2080 try stack.append(State { .BinaryAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
21462081 continue;
21472082 }
2148
2149 _ = (try self.expectToken(&stack, Token.Id.LParen)) ?? continue;
2150 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
2151 try stack.append(State { .AssignmentExpressionBegin = DestPtr { .NullableField = dest } });
21522083 },
21532084
2154 State.SuspendBody => |suspend_node| {
2155 if (suspend_node.payload != null) {
2156 try stack.append(State { .AssignmentExpressionBegin = DestPtr { .NullableField = &suspend_node.body } });
2157 }
2085 State.BinaryAndExpressionBegin => |opt_ctx| {
2086 stack.append(State { .BinaryAndExpressionEnd = opt_ctx }) catch unreachable;
2087 try stack.append(State { .BitShiftExpressionBegin = opt_ctx });
21582088 continue;
21592089 },
21602090
2161 State.AsyncEnd => |ctx| {
2162 const node = ctx.dest_ptr.get();
2091 State.BinaryAndExpressionEnd => |opt_ctx| {
2092 const lhs = opt_ctx.get() ?? continue;
21632093
2164 switch (node.id) {
2165 ast.Node.Id.FnProto => {
2166 const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", node);
2167 fn_proto.async_attr = ctx.attribute;
2168 },
2169 ast.Node.Id.SuffixOp => {
2170 const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", node);
2171 if (suffix_op.op == ast.NodeSuffixOp.SuffixOp.Call) {
2172 suffix_op.op.Call.async_attr = ctx.attribute;
2173 continue;
2094 if (self.eatToken(Token.Id.Ampersand)) |ampersand| {
2095 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2096 ast.Node.InfixOp {
2097 .base = undefined,
2098 .lhs = lhs,
2099 .op_token = ampersand,
2100 .op = ast.Node.InfixOp.Op.BitAnd,
2101 .rhs = undefined,
21742102 }
2175
2176 try self.parseError(&stack, node.firstToken(), "expected call or fn proto, found {}.",
2177 @tagName(suffix_op.op));
2178 continue;
2179 },
2180 else => {
2181 try self.parseError(&stack, node.firstToken(), "expected call or fn proto, found {}.",
2182 @tagName(node.id));
2183 continue;
2184 }
2103 );
2104 stack.append(State { .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2105 try stack.append(State { .BitShiftExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2106 continue;
21852107 }
21862108 },
21872109
2188 State.Payload => |dest| {
2189 const lpipe = self.getNextToken();
2190 if (lpipe.id != Token.Id.Pipe) {
2191 self.putBackToken(lpipe);
2110 State.BitShiftExpressionBegin => |opt_ctx| {
2111 stack.append(State { .BitShiftExpressionEnd = opt_ctx }) catch unreachable;
2112 try stack.append(State { .AdditionExpressionBegin = opt_ctx });
2113 continue;
2114 },
2115
2116 State.BitShiftExpressionEnd => |opt_ctx| {
2117 const lhs = opt_ctx.get() ?? continue;
2118
2119 const token = self.getNextToken();
2120 if (tokenIdToBitShift(token.id)) |bitshift_id| {
2121 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2122 ast.Node.InfixOp {
2123 .base = undefined,
2124 .lhs = lhs,
2125 .op_token = token,
2126 .op = bitshift_id,
2127 .rhs = undefined,
2128 }
2129 );
2130 stack.append(State { .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2131 try stack.append(State { .AdditionExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2132 continue;
2133 } else {
2134 self.putBackToken(token);
21922135 continue;
21932136 }
2137 },
21942138
2195 const error_symbol = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
2196 const rpipe = (try self.expectToken(&stack, Token.Id.Pipe)) ?? continue;
2197 *dest = try self.createNode(arena, ast.NodePayload,
2198 ast.NodePayload {
2199 .base = undefined,
2200 .lpipe = lpipe,
2201 .error_symbol = try self.createLiteral(arena, ast.NodeIdentifier, error_symbol),
2202 .rpipe = rpipe
2203 }
2204 );
2139 State.AdditionExpressionBegin => |opt_ctx| {
2140 stack.append(State { .AdditionExpressionEnd = opt_ctx }) catch unreachable;
2141 try stack.append(State { .MultiplyExpressionBegin = opt_ctx });
2142 continue;
22052143 },
22062144
2207 State.PointerPayload => |dest| {
2208 const lpipe = self.getNextToken();
2209 if (lpipe.id != Token.Id.Pipe) {
2210 self.putBackToken(lpipe);
2145 State.AdditionExpressionEnd => |opt_ctx| {
2146 const lhs = opt_ctx.get() ?? continue;
2147
2148 const token = self.getNextToken();
2149 if (tokenIdToAddition(token.id)) |add_id| {
2150 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2151 ast.Node.InfixOp {
2152 .base = undefined,
2153 .lhs = lhs,
2154 .op_token = token,
2155 .op = add_id,
2156 .rhs = undefined,
2157 }
2158 );
2159 stack.append(State { .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2160 try stack.append(State { .MultiplyExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2161 continue;
2162 } else {
2163 self.putBackToken(token);
22112164 continue;
22122165 }
2166 },
22132167
2214 const is_ptr = blk: {
2215 const asterik = self.getNextToken();
2216 if (asterik.id == Token.Id.Asterisk) {
2217 break :blk true;
2218 } else {
2219 self.putBackToken(asterik);
2220 break :blk false;
2221 }
2222 };
2223
2224 const value_symbol = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
2225 const rpipe = (try self.expectToken(&stack, Token.Id.Pipe)) ?? continue;
2226 *dest = try self.createNode(arena, ast.NodePointerPayload,
2227 ast.NodePointerPayload {
2228 .base = undefined,
2229 .lpipe = lpipe,
2230 .is_ptr = is_ptr,
2231 .value_symbol = try self.createLiteral(arena, ast.NodeIdentifier, value_symbol),
2232 .rpipe = rpipe
2233 }
2234 );
2168 State.MultiplyExpressionBegin => |opt_ctx| {
2169 stack.append(State { .MultiplyExpressionEnd = opt_ctx }) catch unreachable;
2170 try stack.append(State { .CurlySuffixExpressionBegin = opt_ctx });
2171 continue;
22352172 },
22362173
2237 State.PointerIndexPayload => |dest| {
2238 const lpipe = self.getNextToken();
2239 if (lpipe.id != Token.Id.Pipe) {
2240 self.putBackToken(lpipe);
2174 State.MultiplyExpressionEnd => |opt_ctx| {
2175 const lhs = opt_ctx.get() ?? continue;
2176
2177 const token = self.getNextToken();
2178 if (tokenIdToMultiply(token.id)) |mult_id| {
2179 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2180 ast.Node.InfixOp {
2181 .base = undefined,
2182 .lhs = lhs,
2183 .op_token = token,
2184 .op = mult_id,
2185 .rhs = undefined,
2186 }
2187 );
2188 stack.append(State { .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2189 try stack.append(State { .CurlySuffixExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2190 continue;
2191 } else {
2192 self.putBackToken(token);
22412193 continue;
22422194 }
2195 },
22432196
2244 const is_ptr = blk: {
2245 const asterik = self.getNextToken();
2246 if (asterik.id == Token.Id.Asterisk) {
2247 break :blk true;
2248 } else {
2249 self.putBackToken(asterik);
2250 break :blk false;
2251 }
2252 };
2197 State.CurlySuffixExpressionBegin => |opt_ctx| {
2198 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx }) catch unreachable;
2199 try stack.append(State { .IfToken = Token.Id.LBrace });
2200 try stack.append(State { .TypeExprBegin = opt_ctx });
2201 continue;
2202 },
22532203
2254 const value_symbol = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
2255 const index_symbol = blk: {
2256 const comma = self.getNextToken();
2257 if (comma.id != Token.Id.Comma) {
2258 self.putBackToken(comma);
2259 break :blk null;
2260 }
2204 State.CurlySuffixExpressionEnd => |opt_ctx| {
2205 const lhs = opt_ctx.get() ?? continue;
22612206
2262 const symbol = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
2263 break :blk try self.createLiteral(arena, ast.NodeIdentifier, symbol);
2264 };
2207 if (self.isPeekToken(Token.Id.Period)) {
2208 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2209 ast.Node.SuffixOp {
2210 .base = undefined,
2211 .lhs = lhs,
2212 .op = ast.Node.SuffixOp.Op {
2213 .StructInitializer = ArrayList(&ast.Node.FieldInitializer).init(arena),
2214 },
2215 .rtoken = undefined,
2216 }
2217 );
2218 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2219 try stack.append(State { .IfToken = Token.Id.LBrace });
2220 try stack.append(State {
2221 .FieldInitListItemOrEnd = ListSave(&ast.Node.FieldInitializer) {
2222 .list = &node.op.StructInitializer,
2223 .ptr = &node.rtoken,
2224 }
2225 });
2226 continue;
2227 }
22652228
2266 const rpipe = (try self.expectToken(&stack, Token.Id.Pipe)) ?? continue;
2267 *dest = try self.createNode(arena, ast.NodePointerIndexPayload,
2268 ast.NodePointerIndexPayload {
2229 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2230 ast.Node.SuffixOp {
22692231 .base = undefined,
2270 .lpipe = lpipe,
2271 .is_ptr = is_ptr,
2272 .value_symbol = try self.createLiteral(arena, ast.NodeIdentifier, value_symbol),
2273 .index_symbol = index_symbol,
2274 .rpipe = rpipe
2232 .lhs = lhs,
2233 .op = ast.Node.SuffixOp.Op {
2234 .ArrayInitializer = ArrayList(&ast.Node).init(arena),
2235 },
2236 .rtoken = undefined,
22752237 }
22762238 );
2239 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2240 try stack.append(State { .IfToken = Token.Id.LBrace });
2241 try stack.append(State {
2242 .ExprListItemOrEnd = ExprListCtx {
2243 .list = &node.op.ArrayInitializer,
2244 .end = Token.Id.RBrace,
2245 .ptr = &node.rtoken,
2246 }
2247 });
2248 continue;
22772249 },
22782250
2279 State.AddrOfModifiers => |addr_of_info| {
2280 var token = self.getNextToken();
2281 switch (token.id) {
2282 Token.Id.Keyword_align => {
2283 stack.append(state) catch unreachable;
2284 if (addr_of_info.align_expr != null) {
2285 try self.parseError(&stack, token, "multiple align qualifiers");
2286 continue;
2287 }
2288 try stack.append(State { .ExpectToken = Token.Id.RParen });
2289 try stack.append(State { .Expression = DestPtr{.NullableField = &addr_of_info.align_expr} });
2290 try stack.append(State { .ExpectToken = Token.Id.LParen });
2291 continue;
2292 },
2293 Token.Id.Keyword_const => {
2294 stack.append(state) catch unreachable;
2295 if (addr_of_info.const_token != null) {
2296 try self.parseError(&stack, token, "duplicate qualifier: const");
2297 continue;
2298 }
2299 addr_of_info.const_token = token;
2300 continue;
2301 },
2302 Token.Id.Keyword_volatile => {
2303 stack.append(state) catch unreachable;
2304 if (addr_of_info.volatile_token != null) {
2305 try self.parseError(&stack, token, "duplicate qualifier: volatile");
2306 continue;
2307 }
2308 addr_of_info.volatile_token = token;
2309 continue;
2310 },
2311 else => {
2312 self.putBackToken(token);
2313 continue;
2314 },
2315 }
2251 State.TypeExprBegin => |opt_ctx| {
2252 stack.append(State { .TypeExprEnd = opt_ctx }) catch unreachable;
2253 try stack.append(State { .PrefixOpExpression = opt_ctx });
2254 continue;
23162255 },
23172256
2318 State.FnProto => |fn_proto| {
2319 stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable;
2320 try stack.append(State { .ParamDecl = fn_proto });
2321 try stack.append(State { .ExpectToken = Token.Id.LParen });
2257 State.TypeExprEnd => |opt_ctx| {
2258 const lhs = opt_ctx.get() ?? continue;
23222259
2323 const next_token = self.getNextToken();
2324 if (next_token.id == Token.Id.Identifier) {
2325 fn_proto.name_token = next_token;
2260 if (self.eatToken(Token.Id.Bang)) |bang| {
2261 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2262 ast.Node.InfixOp {
2263 .base = undefined,
2264 .lhs = lhs,
2265 .op_token = bang,
2266 .op = ast.Node.InfixOp.Op.ErrorUnion,
2267 .rhs = undefined,
2268 }
2269 );
2270 stack.append(State { .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable;
2271 try stack.append(State { .PrefixOpExpression = OptionalCtx { .Required = &node.rhs } });
23262272 continue;
23272273 }
2328 self.putBackToken(next_token);
2329 continue;
2330 },
2331
2332 State.FnProtoAlign => |fn_proto| {
2333 if (self.eatToken(Token.Id.Keyword_align)) |align_token| {
2334 @panic("TODO fn proto align");
2335 }
2336 stack.append(State {
2337 .FnProtoReturnType = fn_proto,
2338 }) catch unreachable;
2339 continue;
23402274 },
23412275
2342 State.FnProtoReturnType => |fn_proto| {
2276 State.PrefixOpExpression => |opt_ctx| {
23432277 const token = self.getNextToken();
2344 switch (token.id) {
2345 Token.Id.Bang => {
2346 fn_proto.return_type = ast.NodeFnProto.ReturnType { .InferErrorSet = undefined };
2347 stack.append(State {
2348 .TypeExprBegin = DestPtr {.Field = &fn_proto.return_type.InferErrorSet},
2349 }) catch unreachable;
2350 continue;
2351 },
2352 Token.Id.Keyword_align => {
2353 @panic("TODO fn proto align");
2354 continue;
2355 },
2356 else => {
2357 // TODO: this is a special case. Remove this when #760 is fixed
2358 if (token.id == Token.Id.Keyword_error) {
2359 if (self.isPeekToken(Token.Id.LBrace)) {
2360 fn_proto.return_type = ast.NodeFnProto.ReturnType {
2361 .Explicit = &(try self.createLiteral(arena, ast.NodeErrorType, token)).base
2362 };
2363 continue;
2364 }
2278 if (tokenIdToPrefixOp(token.id)) |prefix_id| {
2279 var node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
2280 ast.Node.PrefixOp {
2281 .base = undefined,
2282 .op_token = token,
2283 .op = prefix_id,
2284 .rhs = undefined,
23652285 }
2286 );
23662287
2367 self.putBackToken(token);
2368 fn_proto.return_type = ast.NodeFnProto.ReturnType { .Explicit = undefined };
2369 stack.append(State {
2370 .TypeExprBegin = DestPtr {.Field = &fn_proto.return_type.Explicit},
2371 }) catch unreachable;
2372 continue;
2373 },
2374 }
2375 },
2288 // Treat '**' token as two derefs
2289 if (token.id == Token.Id.AsteriskAsterisk) {
2290 const child = try self.createNode(arena, ast.Node.PrefixOp,
2291 ast.Node.PrefixOp {
2292 .base = undefined,
2293 .op_token = token,
2294 .op = prefix_id,
2295 .rhs = undefined,
2296 }
2297 );
2298 node.rhs = &child.base;
2299 node = child;
2300 }
23762301
2377 State.ParamDecl => |fn_proto| {
2378 if (self.eatToken(Token.Id.RParen)) |_| {
2379 continue;
2380 }
2381 const param_decl = try self.createAttachNode(arena, &fn_proto.params, ast.NodeParamDecl,
2382 ast.NodeParamDecl {
2383 .base = undefined,
2384 .comptime_token = null,
2385 .noalias_token = null,
2386 .name_token = null,
2387 .type_node = undefined,
2388 .var_args_token = null,
2389 },
2390 );
2391 if (self.eatToken(Token.Id.Keyword_comptime)) |comptime_token| {
2392 param_decl.comptime_token = comptime_token;
2393 } else if (self.eatToken(Token.Id.Keyword_noalias)) |noalias_token| {
2394 param_decl.noalias_token = noalias_token;
2395 }
2396 if (self.eatToken(Token.Id.Identifier)) |identifier| {
2397 if (self.eatToken(Token.Id.Colon)) |_| {
2398 param_decl.name_token = identifier;
2399 } else {
2400 self.putBackToken(identifier);
2302 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
2303 if (node.op == ast.Node.PrefixOp.Op.AddrOf) {
2304 try stack.append(State { .AddrOfModifiers = &node.op.AddrOf });
24012305 }
2306 continue;
2307 } else {
2308 self.putBackToken(token);
2309 stack.append(State { .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;
2310 continue;
24022311 }
2403 if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
2404 param_decl.var_args_token = ellipsis3;
2405 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
2312 },
2313
2314 State.SuffixOpExpressionBegin => |opt_ctx| {
2315 if (self.eatToken(Token.Id.Keyword_async)) |async_token| {
2316 const async_node = try self.createNode(arena, ast.Node.AsyncAttribute,
2317 ast.Node.AsyncAttribute {
2318 .base = undefined,
2319 .async_token = async_token,
2320 .allocator_type = null,
2321 .rangle_bracket = null,
2322 }
2323 );
2324 stack.append(State {
2325 .AsyncEnd = AsyncEndCtx {
2326 .ctx = opt_ctx,
2327 .attribute = async_node,
2328 }
2329 }) catch unreachable;
2330 try stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() });
2331 try stack.append(State { .PrimaryExpression = opt_ctx.toRequired() });
2332 try stack.append(State { .AsyncAllocator = async_node });
24062333 continue;
24072334 }
24082335
2409 stack.append(State { .ParamDecl = fn_proto }) catch unreachable;
2410 try stack.append(State.ParamDeclComma);
2411 try stack.append(State {
2412 .TypeExprBegin = DestPtr {.Field = &param_decl.type_node}
2413 });
2336 stack.append(State { .SuffixOpExpressionEnd = opt_ctx }) catch unreachable;
2337 try stack.append(State { .PrimaryExpression = opt_ctx });
24142338 continue;
24152339 },
24162340
2417 State.ParamDeclComma => {
2341 State.SuffixOpExpressionEnd => |opt_ctx| {
2342 const lhs = opt_ctx.get() ?? continue;
2343
24182344 const token = self.getNextToken();
24192345 switch (token.id) {
2420 Token.Id.RParen => {
2421 _ = stack.pop(); // pop off the ParamDecl
2346 Token.Id.LParen => {
2347 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2348 ast.Node.SuffixOp {
2349 .base = undefined,
2350 .lhs = lhs,
2351 .op = ast.Node.SuffixOp.Op {
2352 .Call = ast.Node.SuffixOp.CallInfo {
2353 .params = ArrayList(&ast.Node).init(arena),
2354 .async_attr = null,
2355 }
2356 },
2357 .rtoken = undefined,
2358 }
2359 );
2360 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2361 try stack.append(State {
2362 .ExprListItemOrEnd = ExprListCtx {
2363 .list = &node.op.Call.params,
2364 .end = Token.Id.RParen,
2365 .ptr = &node.rtoken,
2366 }
2367 });
24222368 continue;
24232369 },
2424 Token.Id.Comma => continue,
2425 else => {
2426 try self.parseError(&stack, token, "expected ',' or ')', found {}", @tagName(token.id));
2370 Token.Id.LBracket => {
2371 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp,
2372 ast.Node.SuffixOp {
2373 .base = undefined,
2374 .lhs = lhs,
2375 .op = ast.Node.SuffixOp.Op {
2376 .ArrayAccess = undefined,
2377 },
2378 .rtoken = undefined
2379 }
2380 );
2381 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2382 try stack.append(State { .SliceOrArrayAccess = node });
2383 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayAccess }});
24272384 continue;
24282385 },
2429 }
2430 },
2431
2432 State.FnDef => |fn_proto| {
2433 const token = self.getNextToken();
2434 switch(token.id) {
2435 Token.Id.LBrace => {
2436 const block = try self.createNode(arena, ast.NodeBlock,
2437 ast.NodeBlock {
2386 Token.Id.Period => {
2387 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.InfixOp,
2388 ast.Node.InfixOp {
24382389 .base = undefined,
2439 .label = null,
2440 .lbrace = token,
2441 .statements = ArrayList(&ast.Node).init(arena),
2442 .rbrace = undefined,
2390 .lhs = lhs,
2391 .op_token = token,
2392 .op = ast.Node.InfixOp.Op.Period,
2393 .rhs = undefined,
24432394 }
24442395 );
2445 fn_proto.body_node = &block.base;
2446 stack.append(State { .Block = block }) catch unreachable;
2396 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2397 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.rhs } });
24472398 continue;
24482399 },
2449 Token.Id.Semicolon => continue,
24502400 else => {
2451 try self.parseError(&stack, token, "expected ';' or '{{', found {}", @tagName(token.id));
2401 self.putBackToken(token);
24522402 continue;
24532403 },
24542404 }
24552405 },
24562406
2457 State.LabeledExpression => |ctx| {
2407 State.PrimaryExpression => |opt_ctx| {
24582408 const token = self.getNextToken();
24592409 switch (token.id) {
2460 Token.Id.LBrace => {
2461 const block = try self.createToDestNode(arena, ctx.dest_ptr, ast.NodeBlock,
2462 ast.NodeBlock {
2410 Token.Id.IntegerLiteral => {
2411 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.StringLiteral, token);
2412 continue;
2413 },
2414 Token.Id.FloatLiteral => {
2415 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.FloatLiteral, token);
2416 continue;
2417 },
2418 Token.Id.CharLiteral => {
2419 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.CharLiteral, token);
2420 continue;
2421 },
2422 Token.Id.Keyword_undefined => {
2423 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.UndefinedLiteral, token);
2424 continue;
2425 },
2426 Token.Id.Keyword_true, Token.Id.Keyword_false => {
2427 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.BoolLiteral, token);
2428 continue;
2429 },
2430 Token.Id.Keyword_null => {
2431 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.NullLiteral, token);
2432 continue;
2433 },
2434 Token.Id.Keyword_this => {
2435 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.ThisLiteral, token);
2436 continue;
2437 },
2438 Token.Id.Keyword_var => {
2439 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.VarType, token);
2440 continue;
2441 },
2442 Token.Id.Keyword_unreachable => {
2443 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.Unreachable, token);
2444 continue;
2445 },
2446 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
2447 opt_ctx.store((try self.parseStringLiteral(arena, token)) ?? unreachable);
2448 continue;
2449 },
2450 Token.Id.LParen => {
2451 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.GroupedExpression,
2452 ast.Node.GroupedExpression {
24632453 .base = undefined,
2464 .label = ctx.label,
2465 .lbrace = token,
2466 .statements = ArrayList(&ast.Node).init(arena),
2467 .rbrace = undefined,
2454 .lparen = token,
2455 .expr = undefined,
2456 .rparen = undefined,
24682457 }
24692458 );
2470 stack.append(State { .Block = block }) catch unreachable;
2459 stack.append(State {
2460 .ExpectTokenSave = ExpectTokenSave {
2461 .id = Token.Id.RParen,
2462 .ptr = &node.rparen,
2463 }
2464 }) catch unreachable;
2465 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
24712466 continue;
24722467 },
2473 Token.Id.Keyword_while => {
2468 Token.Id.Builtin => {
2469 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.BuiltinCall,
2470 ast.Node.BuiltinCall {
2471 .base = undefined,
2472 .builtin_token = token,
2473 .params = ArrayList(&ast.Node).init(arena),
2474 .rparen_token = undefined,
2475 }
2476 );
24742477 stack.append(State {
2475 .While = LoopCtx {
2476 .label = ctx.label,
2477 .inline_token = null,
2478 .loop_token = token,
2479 .dest_ptr = ctx.dest_ptr,
2478 .ExprListItemOrEnd = ExprListCtx {
2479 .list = &node.params,
2480 .end = Token.Id.RParen,
2481 .ptr = &node.rparen_token,
24802482 }
24812483 }) catch unreachable;
2484 try stack.append(State { .ExpectToken = Token.Id.LParen, });
24822485 continue;
24832486 },
2484 Token.Id.Keyword_for => {
2487 Token.Id.LBracket => {
2488 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp,
2489 ast.Node.PrefixOp {
2490 .base = undefined,
2491 .op_token = token,
2492 .op = undefined,
2493 .rhs = undefined,
2494 }
2495 );
2496 stack.append(State { .SliceOrArrayType = node }) catch unreachable;
2497 continue;
2498 },
2499 Token.Id.Keyword_error => {
24852500 stack.append(State {
2486 .For = LoopCtx {
2487 .label = ctx.label,
2488 .inline_token = null,
2489 .loop_token = token,
2490 .dest_ptr = ctx.dest_ptr,
2501 .ErrorTypeOrSetDecl = ErrorTypeOrSetDeclCtx {
2502 .error_token = token,
2503 .opt_ctx = opt_ctx
24912504 }
24922505 }) catch unreachable;
24932506 continue;
24942507 },
2495 Token.Id.Keyword_inline => {
2508 Token.Id.Keyword_packed => {
24962509 stack.append(State {
2497 .Inline = InlineCtx {
2498 .label = ctx.label,
2499 .inline_token = token,
2500 .dest_ptr = ctx.dest_ptr,
2510 .ContainerKind = ContainerKindCtx {
2511 .opt_ctx = opt_ctx,
2512 .ltoken = token,
2513 .layout = ast.Node.ContainerDecl.Layout.Packed,
2514 },
2515 }) catch unreachable;
2516 continue;
2517 },
2518 Token.Id.Keyword_extern => {
2519 stack.append(State {
2520 .ExternType = ExternTypeCtx {
2521 .opt_ctx = opt_ctx,
2522 .extern_token = token,
2523 .comments = null,
2524 },
2525 }) catch unreachable;
2526 continue;
2527 },
2528 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
2529 self.putBackToken(token);
2530 stack.append(State {
2531 .ContainerKind = ContainerKindCtx {
2532 .opt_ctx = opt_ctx,
2533 .ltoken = token,
2534 .layout = ast.Node.ContainerDecl.Layout.Auto,
2535 },
2536 }) catch unreachable;
2537 continue;
2538 },
2539 Token.Id.Identifier => {
2540 stack.append(State {
2541 .MaybeLabeledExpression = MaybeLabeledExpressionCtx {
2542 .label = token,
2543 .opt_ctx = opt_ctx
25012544 }
25022545 }) catch unreachable;
25032546 continue;
25042547 },
2505 else => {
2506 try self.parseError(&stack, token, "expected 'while', 'for', 'inline' or '{{', found {}", @tagName(token.id));
2548 Token.Id.Keyword_fn => {
2549 const fn_proto = try self.createToCtxNode(arena, opt_ctx, ast.Node.FnProto,
2550 ast.Node.FnProto {
2551 .base = undefined,
2552 .comments = null,
2553 .visib_token = null,
2554 .name_token = null,
2555 .fn_token = token,
2556 .params = ArrayList(&ast.Node).init(arena),
2557 .return_type = undefined,
2558 .var_args_token = null,
2559 .extern_export_inline_token = null,
2560 .cc_token = null,
2561 .async_attr = null,
2562 .body_node = null,
2563 .lib_name = null,
2564 .align_expr = null,
2565 }
2566 );
2567 stack.append(State { .FnProto = fn_proto }) catch unreachable;
25072568 continue;
25082569 },
2509 }
2510 },
2511
2512 State.Inline => |ctx| {
2513 const token = self.getNextToken();
2514 switch (token.id) {
2515 Token.Id.Keyword_while => {
2570 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
2571 const fn_proto = try self.createToCtxNode(arena, opt_ctx, ast.Node.FnProto,
2572 ast.Node.FnProto {
2573 .base = undefined,
2574 .comments = null,
2575 .visib_token = null,
2576 .name_token = null,
2577 .fn_token = undefined,
2578 .params = ArrayList(&ast.Node).init(arena),
2579 .return_type = undefined,
2580 .var_args_token = null,
2581 .extern_export_inline_token = null,
2582 .cc_token = token,
2583 .async_attr = null,
2584 .body_node = null,
2585 .lib_name = null,
2586 .align_expr = null,
2587 }
2588 );
2589 stack.append(State { .FnProto = fn_proto }) catch unreachable;
2590 try stack.append(State {
2591 .ExpectTokenSave = ExpectTokenSave {
2592 .id = Token.Id.Keyword_fn,
2593 .ptr = &fn_proto.fn_token
2594 }
2595 });
2596 continue;
2597 },
2598 Token.Id.Keyword_asm => {
2599 const node = try self.createToCtxNode(arena, opt_ctx, ast.Node.Asm,
2600 ast.Node.Asm {
2601 .base = undefined,
2602 .asm_token = token,
2603 .volatile_token = null,
2604 .template = undefined,
2605 //.tokens = ArrayList(ast.Node.Asm.AsmToken).init(arena),
2606 .outputs = ArrayList(&ast.Node.AsmOutput).init(arena),
2607 .inputs = ArrayList(&ast.Node.AsmInput).init(arena),
2608 .cloppers = ArrayList(&ast.Node).init(arena),
2609 .rparen = undefined,
2610 }
2611 );
25162612 stack.append(State {
2517 .While = LoopCtx {
2518 .inline_token = ctx.inline_token,
2519 .label = ctx.label,
2520 .loop_token = token,
2521 .dest_ptr = ctx.dest_ptr,
2613 .ExpectTokenSave = ExpectTokenSave {
2614 .id = Token.Id.RParen,
2615 .ptr = &node.rparen,
2616 }
2617 }) catch unreachable;
2618 try stack.append(State { .AsmClopperItems = &node.cloppers });
2619 try stack.append(State { .IfToken = Token.Id.Colon });
2620 try stack.append(State { .AsmInputItems = &node.inputs });
2621 try stack.append(State { .IfToken = Token.Id.Colon });
2622 try stack.append(State { .AsmOutputItems = &node.outputs });
2623 try stack.append(State { .IfToken = Token.Id.Colon });
2624 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.template } });
2625 try stack.append(State { .ExpectToken = Token.Id.LParen });
2626 try stack.append(State {
2627 .OptionalTokenSave = OptionalTokenSave {
2628 .id = Token.Id.Keyword_volatile,
2629 .ptr = &node.volatile_token,
25222630 }
2523 }) catch unreachable;
2524 continue;
2631 });
25252632 },
2526 Token.Id.Keyword_for => {
2633 Token.Id.Keyword_inline => {
25272634 stack.append(State {
2528 .For = LoopCtx {
2529 .inline_token = ctx.inline_token,
2530 .label = ctx.label,
2531 .loop_token = token,
2532 .dest_ptr = ctx.dest_ptr,
2635 .Inline = InlineCtx {
2636 .label = null,
2637 .inline_token = token,
2638 .opt_ctx = opt_ctx,
25332639 }
25342640 }) catch unreachable;
25352641 continue;
25362642 },
25372643 else => {
2538 try self.parseError(&stack, token, "expected 'while' or 'for', found {}", @tagName(token.id));
2644 if (!try self.parseBlockExpr(&stack, arena, opt_ctx, token)) {
2645 self.putBackToken(token);
2646 if (opt_ctx != OptionalCtx.Optional) {
2647 return self.parseError(token, "expected primary expression, found {}", @tagName(token.id));
2648 }
2649 }
25392650 continue;
2540 },
2651 }
25412652 }
25422653 },
25432654
2544 State.While => |ctx| {
2545 const node = try self.createToDestNode(arena, ctx.dest_ptr, ast.NodeWhile,
2546 ast.NodeWhile {
2655
2656 State.ErrorTypeOrSetDecl => |ctx| {
2657 if (self.eatToken(Token.Id.LBrace) == null) {
2658 _ = try self.createToCtxLiteral(arena, ctx.opt_ctx, ast.Node.ErrorType, ctx.error_token);
2659 continue;
2660 }
2661
2662 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.Node.ErrorSetDecl,
2663 ast.Node.ErrorSetDecl {
25472664 .base = undefined,
2548 .label = ctx.label,
2549 .inline_token = ctx.inline_token,
2550 .while_token = ctx.loop_token,
2551 .condition = undefined,
2552 .payload = null,
2553 .continue_expr = null,
2554 .body = undefined,
2555 .@"else" = null,
2665 .error_token = ctx.error_token,
2666 .decls = ArrayList(&ast.Node).init(arena),
2667 .rbrace_token = undefined,
25562668 }
25572669 );
2558 stack.append(State { .Else = &node.@"else" }) catch unreachable;
2559 try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
2560 try stack.append(State { .WhileContinueExpr = &node.continue_expr });
2561 try stack.append(State { .PointerPayload = &node.payload });
2562 try stack.append(State { .ExpectToken = Token.Id.RParen });
2563 try stack.append(State { .Expression = DestPtr { .Field = &node.condition } });
2564 try stack.append(State { .ExpectToken = Token.Id.LParen });
2565 },
25662670
2567 State.For => |ctx| {
2568 const node = try self.createToDestNode(arena, ctx.dest_ptr, ast.NodeFor,
2569 ast.NodeFor {
2570 .base = undefined,
2571 .label = ctx.label,
2572 .inline_token = ctx.inline_token,
2573 .for_token = ctx.loop_token,
2574 .array_expr = undefined,
2575 .payload = null,
2576 .body = undefined,
2577 .@"else" = null,
2671 stack.append(State {
2672 .IdentifierListItemOrEnd = ListSave(&ast.Node) {
2673 .list = &node.decls,
2674 .ptr = &node.rbrace_token,
25782675 }
2579 );
2580 stack.append(State { .Else = &node.@"else" }) catch unreachable;
2581 try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
2582 try stack.append(State { .PointerIndexPayload = &node.payload });
2583 try stack.append(State { .ExpectToken = Token.Id.RParen });
2584 try stack.append(State { .Expression = DestPtr { .Field = &node.array_expr } });
2585 try stack.append(State { .ExpectToken = Token.Id.LParen });
2676 }) catch unreachable;
2677 continue;
25862678 },
2587
2588 State.Block => |block| {
2679 State.StringLiteral => |opt_ctx| {
25892680 const token = self.getNextToken();
2590 switch (token.id) {
2591 Token.Id.RBrace => {
2592 block.rbrace = token;
2593 continue;
2594 },
2595 else => {
2681 opt_ctx.store(
2682 (try self.parseStringLiteral(arena, token)) ?? {
25962683 self.putBackToken(token);
2597 stack.append(State { .Block = block }) catch unreachable;
2598 try stack.append(State { .Statement = block });
2684 if (opt_ctx != OptionalCtx.Optional) {
2685 return self.parseError(token, "expected primary expression, found {}", @tagName(token.id));
2686 }
2687
25992688 continue;
2600 },
2689 }
2690 );
2691 },
2692 State.Identifier => |opt_ctx| {
2693 if (self.eatToken(Token.Id.Identifier)) |ident_token| {
2694 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.Node.Identifier, ident_token);
2695 continue;
2696 }
2697
2698 if (opt_ctx != OptionalCtx.Optional) {
2699 const token = self.getNextToken();
2700 return self.parseError(token, "expected identifier, found {}", @tagName(token.id));
26012701 }
26022702 },
26032703
2604 State.Statement => |block| {
2605 const next = self.getNextToken();
2606 switch (next.id) {
2607 Token.Id.Keyword_comptime => {
2608 const mut_token = self.getNextToken();
2609 if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) {
2610 const var_decl = try self.createAttachNode(arena, &block.statements, ast.NodeVarDecl,
2611 ast.NodeVarDecl {
2612 .base = undefined,
2613 .visib_token = null,
2614 .mut_token = mut_token,
2615 .comptime_token = next,
2616 .extern_export_token = null,
2617 .type_node = null,
2618 .align_node = null,
2619 .init_node = null,
2620 .lib_name = null,
2621 // initialized later
2622 .name_token = undefined,
2623 .eq_token = undefined,
2624 .semicolon_token = undefined,
2625 }
2626 );
2627 stack.append(State { .VarDecl = var_decl }) catch unreachable;
2628 continue;
2629 } else {
2630 self.putBackToken(mut_token);
2631 self.putBackToken(next);
2632 const statememt = try block.statements.addOne();
2633 stack.append(State { .Semicolon = statememt }) catch unreachable;
2634 try stack.append(State { .Expression = DestPtr{.Field = statememt } });
2635 }
2636 },
2637 Token.Id.Keyword_var, Token.Id.Keyword_const => {
2638 const var_decl = try self.createAttachNode(arena, &block.statements, ast.NodeVarDecl,
2639 ast.NodeVarDecl {
2640 .base = undefined,
2641 .visib_token = null,
2642 .mut_token = next,
2643 .comptime_token = null,
2644 .extern_export_token = null,
2645 .type_node = null,
2646 .align_node = null,
2647 .init_node = null,
2648 .lib_name = null,
2649 // initialized later
2650 .name_token = undefined,
2651 .eq_token = undefined,
2652 .semicolon_token = undefined,
2653 }
2654 );
2655 stack.append(State { .VarDecl = var_decl }) catch unreachable;
2656 continue;
2657 },
2658 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
2659 const node = try self.createAttachNode(arena, &block.statements, ast.NodeDefer,
2660 ast.NodeDefer {
2661 .base = undefined,
2662 .defer_token = next,
2663 .kind = switch (next.id) {
2664 Token.Id.Keyword_defer => ast.NodeDefer.Kind.Unconditional,
2665 Token.Id.Keyword_errdefer => ast.NodeDefer.Kind.Error,
2666 else => unreachable,
2667 },
2668 .expr = undefined,
2669 }
2670 );
2671 stack.append(State { .Semicolon = &node.base }) catch unreachable;
2672 try stack.append(State { .AssignmentExpressionBegin = DestPtr{.Field = &node.expr } });
2673 continue;
2674 },
2675 Token.Id.LBrace => {
2676 const inner_block = try self.createAttachNode(arena, &block.statements, ast.NodeBlock,
2677 ast.NodeBlock {
2678 .base = undefined,
2679 .label = null,
2680 .lbrace = next,
2681 .statements = ArrayList(&ast.Node).init(arena),
2682 .rbrace = undefined,
2683 }
2684 );
2685 stack.append(State { .Block = inner_block }) catch unreachable;
2686 continue;
2687 },
2688 else => {
2689 self.putBackToken(next);
2690 const statememt = try block.statements.addOne();
2691 stack.append(State { .Semicolon = statememt }) catch unreachable;
2692 try stack.append(State { .AssignmentExpressionBegin = DestPtr{.Field = statememt } });
2693 continue;
2694 }
2704
2705 State.ExpectToken => |token_id| {
2706 _ = try self.expectToken(token_id);
2707 continue;
2708 },
2709 State.ExpectTokenSave => |expect_token_save| {
2710 *expect_token_save.ptr = try self.expectToken(expect_token_save.id);
2711 continue;
2712 },
2713 State.IfToken => |token_id| {
2714 if (self.eatToken(token_id)) |_| {
2715 continue;
26952716 }
26962717
2718 _ = stack.pop();
2719 continue;
26972720 },
2721 State.IfTokenSave => |if_token_save| {
2722 if (self.eatToken(if_token_save.id)) |token| {
2723 *if_token_save.ptr = token;
2724 continue;
2725 }
26982726
2699 State.Semicolon => |node_ptr| {
2700 const node = *node_ptr;
2701 if (requireSemiColon(node)) {
2702 _ = (try self.expectToken(&stack, Token.Id.Semicolon)) ?? continue;
2727 _ = stack.pop();
2728 continue;
2729 },
2730 State.OptionalTokenSave => |optional_token_save| {
2731 if (self.eatToken(optional_token_save.id)) |token| {
2732 *optional_token_save.ptr = token;
2733 continue;
27032734 }
2704 }
2735
2736 continue;
2737 },
2738 }
2739 }
2740 }
2741
2742 fn eatComments(self: &Parser, arena: &mem.Allocator) !?&ast.Node.LineComment {
2743 var result: ?&ast.Node.LineComment = null;
2744 while (true) {
2745 if (self.eatToken(Token.Id.LineComment)) |line_comment| {
2746 const node = blk: {
2747 if (result) |comment_node| {
2748 break :blk comment_node;
2749 } else {
2750 const comment_node = try arena.create(ast.Node.LineComment);
2751 *comment_node = ast.Node.LineComment {
2752 .base = ast.Node {
2753 .id = ast.Node.Id.LineComment,
2754 },
2755 .lines = ArrayList(Token).init(arena),
2756 };
2757 result = comment_node;
2758 break :blk comment_node;
2759 }
2760 };
2761 try node.lines.append(line_comment);
2762 continue;
27052763 }
2764 break;
27062765 }
2766 return result;
27072767 }
27082768
27092769 fn requireSemiColon(node: &const ast.Node) bool {
......@@ -2726,7 +2786,7 @@ pub const Parser = struct {
27262786 ast.Node.Id.LineComment,
27272787 ast.Node.Id.TestDecl => return false,
27282788 ast.Node.Id.While => {
2729 const while_node = @fieldParentPtr(ast.NodeWhile, "base", n);
2789 const while_node = @fieldParentPtr(ast.Node.While, "base", n);
27302790 if (while_node.@"else") |@"else"| {
27312791 n = @"else".base;
27322792 continue;
......@@ -2735,7 +2795,7 @@ pub const Parser = struct {
27352795 return while_node.body.id != ast.Node.Id.Block;
27362796 },
27372797 ast.Node.Id.For => {
2738 const for_node = @fieldParentPtr(ast.NodeFor, "base", n);
2798 const for_node = @fieldParentPtr(ast.Node.For, "base", n);
27392799 if (for_node.@"else") |@"else"| {
27402800 n = @"else".base;
27412801 continue;
......@@ -2744,7 +2804,7 @@ pub const Parser = struct {
27442804 return for_node.body.id != ast.Node.Id.Block;
27452805 },
27462806 ast.Node.Id.If => {
2747 const if_node = @fieldParentPtr(ast.NodeIf, "base", n);
2807 const if_node = @fieldParentPtr(ast.Node.If, "base", n);
27482808 if (if_node.@"else") |@"else"| {
27492809 n = @"else".base;
27502810 continue;
......@@ -2753,20 +2813,20 @@ pub const Parser = struct {
27532813 return if_node.body.id != ast.Node.Id.Block;
27542814 },
27552815 ast.Node.Id.Else => {
2756 const else_node = @fieldParentPtr(ast.NodeElse, "base", n);
2816 const else_node = @fieldParentPtr(ast.Node.Else, "base", n);
27572817 n = else_node.body;
27582818 continue;
27592819 },
27602820 ast.Node.Id.Defer => {
2761 const defer_node = @fieldParentPtr(ast.NodeDefer, "base", n);
2821 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", n);
27622822 return defer_node.expr.id != ast.Node.Id.Block;
27632823 },
27642824 ast.Node.Id.Comptime => {
2765 const comptime_node = @fieldParentPtr(ast.NodeComptime, "base", n);
2825 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", n);
27662826 return comptime_node.expr.id != ast.Node.Id.Block;
27672827 },
27682828 ast.Node.Id.Suspend => {
2769 const suspend_node = @fieldParentPtr(ast.NodeSuspend, "base", n);
2829 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", n);
27702830 if (suspend_node.body) |body| {
27712831 return body.id != ast.Node.Id.Block;
27722832 }
......@@ -2781,11 +2841,11 @@ pub const Parser = struct {
27812841 fn parseStringLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !?&ast.Node {
27822842 switch (token.id) {
27832843 Token.Id.StringLiteral => {
2784 return &(try self.createLiteral(arena, ast.NodeStringLiteral, token)).base;
2844 return &(try self.createLiteral(arena, ast.Node.StringLiteral, token)).base;
27852845 },
27862846 Token.Id.MultilineStringLiteralLine => {
2787 const node = try self.createNode(arena, ast.NodeMultilineStringLiteral,
2788 ast.NodeMultilineStringLiteral {
2847 const node = try self.createNode(arena, ast.Node.MultilineStringLiteral,
2848 ast.Node.MultilineStringLiteral {
27892849 .base = undefined,
27902850 .tokens = ArrayList(Token).init(arena),
27912851 }
......@@ -2809,11 +2869,11 @@ pub const Parser = struct {
28092869 }
28102870 }
28112871
2812 fn parseBlockExpr(self: &Parser, stack: &ArrayList(State), arena: &mem.Allocator, dest_ptr: &const DestPtr, token: &const Token) !bool {
2872 fn parseBlockExpr(self: &Parser, stack: &ArrayList(State), arena: &mem.Allocator, ctx: &const OptionalCtx, token: &const Token) !bool {
28132873 switch (token.id) {
28142874 Token.Id.Keyword_suspend => {
2815 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSuspend,
2816 ast.NodeSuspend {
2875 const node = try self.createToCtxNode(arena, ctx, ast.Node.Suspend,
2876 ast.Node.Suspend {
28172877 .base = undefined,
28182878 .suspend_token = *token,
28192879 .payload = null,
......@@ -2822,12 +2882,12 @@ pub const Parser = struct {
28222882 );
28232883
28242884 stack.append(State { .SuspendBody = node }) catch unreachable;
2825 try stack.append(State { .Payload = &node.payload });
2885 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
28262886 return true;
28272887 },
28282888 Token.Id.Keyword_if => {
2829 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeIf,
2830 ast.NodeIf {
2889 const node = try self.createToCtxNode(arena, ctx, ast.Node.If,
2890 ast.Node.If {
28312891 .base = undefined,
28322892 .if_token = *token,
28332893 .condition = undefined,
......@@ -2838,10 +2898,10 @@ pub const Parser = struct {
28382898 );
28392899
28402900 stack.append(State { .Else = &node.@"else" }) catch unreachable;
2841 try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
2842 try stack.append(State { .PointerPayload = &node.payload });
2901 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
2902 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
28432903 try stack.append(State { .ExpectToken = Token.Id.RParen });
2844 try stack.append(State { .Expression = DestPtr { .Field = &node.condition } });
2904 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
28452905 try stack.append(State { .ExpectToken = Token.Id.LParen });
28462906 return true;
28472907 },
......@@ -2851,7 +2911,7 @@ pub const Parser = struct {
28512911 .label = null,
28522912 .inline_token = null,
28532913 .loop_token = *token,
2854 .dest_ptr = *dest_ptr,
2914 .opt_ctx = *ctx,
28552915 }
28562916 }) catch unreachable;
28572917 return true;
......@@ -2862,48 +2922,48 @@ pub const Parser = struct {
28622922 .label = null,
28632923 .inline_token = null,
28642924 .loop_token = *token,
2865 .dest_ptr = *dest_ptr,
2925 .opt_ctx = *ctx,
28662926 }
28672927 }) catch unreachable;
28682928 return true;
28692929 },
28702930 Token.Id.Keyword_switch => {
2871 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSwitch,
2872 ast.NodeSwitch {
2931 const node = try self.createToCtxNode(arena, ctx, ast.Node.Switch,
2932 ast.Node.Switch {
28732933 .base = undefined,
28742934 .switch_token = *token,
28752935 .expr = undefined,
2876 .cases = ArrayList(&ast.NodeSwitchCase).init(arena),
2936 .cases = ArrayList(&ast.Node.SwitchCase).init(arena),
28772937 .rbrace = undefined,
28782938 }
28792939 );
28802940
28812941 stack.append(State {
2882 .SwitchCaseOrEnd = ListSave(&ast.NodeSwitchCase) {
2942 .SwitchCaseOrEnd = ListSave(&ast.Node.SwitchCase) {
28832943 .list = &node.cases,
28842944 .ptr = &node.rbrace,
28852945 },
28862946 }) catch unreachable;
28872947 try stack.append(State { .ExpectToken = Token.Id.LBrace });
28882948 try stack.append(State { .ExpectToken = Token.Id.RParen });
2889 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
2949 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
28902950 try stack.append(State { .ExpectToken = Token.Id.LParen });
28912951 return true;
28922952 },
28932953 Token.Id.Keyword_comptime => {
2894 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeComptime,
2895 ast.NodeComptime {
2954 const node = try self.createToCtxNode(arena, ctx, ast.Node.Comptime,
2955 ast.Node.Comptime {
28962956 .base = undefined,
28972957 .comptime_token = *token,
28982958 .expr = undefined,
28992959 }
29002960 );
2901 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
2961 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
29022962 return true;
29032963 },
29042964 Token.Id.LBrace => {
2905 const block = try self.createToDestNode(arena, dest_ptr, ast.NodeBlock,
2906 ast.NodeBlock {
2965 const block = try self.createToCtxNode(arena, ctx, ast.Node.Block,
2966 ast.Node.Block {
29072967 .base = undefined,
29082968 .label = null,
29092969 .lbrace = *token,
......@@ -2920,100 +2980,102 @@ pub const Parser = struct {
29202980 }
29212981 }
29222982
2923 fn commaOrEnd(self: &Parser, stack: &ArrayList(State), end: &const Token.Id, maybe_ptr: ?&Token, state_after_comma: &const State) !void {
2983 fn expectCommaOrEnd(self: &Parser, end: @TagType(Token.Id)) !?Token {
29242984 var token = self.getNextToken();
29252985 switch (token.id) {
2926 Token.Id.Comma => {
2927 stack.append(state_after_comma) catch unreachable;
2928 },
2986 Token.Id.Comma => return null,
29292987 else => {
2930 const IdTag = @TagType(Token.Id);
2931 if (IdTag(*end) == token.id) {
2932 if (maybe_ptr) |ptr| {
2933 *ptr = token;
2934 }
2935 return;
2988 if (end == token.id) {
2989 return token;
29362990 }
29372991
2938 try self.parseError(stack, token, "expected ',' or {}, found {}", @tagName(*end), @tagName(token.id));
2992 return self.parseError(token, "expected ',' or {}, found {}", @tagName(end), @tagName(token.id));
29392993 },
29402994 }
29412995 }
29422996
2943 fn tokenIdToAssignment(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
2997 fn tokenIdToAssignment(id: &const Token.Id) ?ast.Node.InfixOp.Op {
29442998 // TODO: We have to cast all cases because of this:
29452999 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
29463000 return switch (*id) {
2947 Token.Id.AmpersandEqual => ast.NodeInfixOp.InfixOp { .AssignBitAnd = void{} },
2948 Token.Id.AngleBracketAngleBracketLeftEqual => ast.NodeInfixOp.InfixOp { .AssignBitShiftLeft = void{} },
2949 Token.Id.AngleBracketAngleBracketRightEqual => ast.NodeInfixOp.InfixOp { .AssignBitShiftRight = void{} },
2950 Token.Id.AsteriskEqual => ast.NodeInfixOp.InfixOp { .AssignTimes = void{} },
2951 Token.Id.AsteriskPercentEqual => ast.NodeInfixOp.InfixOp { .AssignTimesWarp = void{} },
2952 Token.Id.CaretEqual => ast.NodeInfixOp.InfixOp { .AssignBitXor = void{} },
2953 Token.Id.Equal => ast.NodeInfixOp.InfixOp { .Assign = void{} },
2954 Token.Id.MinusEqual => ast.NodeInfixOp.InfixOp { .AssignMinus = void{} },
2955 Token.Id.MinusPercentEqual => ast.NodeInfixOp.InfixOp { .AssignMinusWrap = void{} },
2956 Token.Id.PercentEqual => ast.NodeInfixOp.InfixOp { .AssignMod = void{} },
2957 Token.Id.PipeEqual => ast.NodeInfixOp.InfixOp { .AssignBitOr = void{} },
2958 Token.Id.PlusEqual => ast.NodeInfixOp.InfixOp { .AssignPlus = void{} },
2959 Token.Id.PlusPercentEqual => ast.NodeInfixOp.InfixOp { .AssignPlusWrap = void{} },
2960 Token.Id.SlashEqual => ast.NodeInfixOp.InfixOp { .AssignDiv = void{} },
3001 Token.Id.AmpersandEqual => ast.Node.InfixOp.Op { .AssignBitAnd = void{} },
3002 Token.Id.AngleBracketAngleBracketLeftEqual => ast.Node.InfixOp.Op { .AssignBitShiftLeft = void{} },
3003 Token.Id.AngleBracketAngleBracketRightEqual => ast.Node.InfixOp.Op { .AssignBitShiftRight = void{} },
3004 Token.Id.AsteriskEqual => ast.Node.InfixOp.Op { .AssignTimes = void{} },
3005 Token.Id.AsteriskPercentEqual => ast.Node.InfixOp.Op { .AssignTimesWarp = void{} },
3006 Token.Id.CaretEqual => ast.Node.InfixOp.Op { .AssignBitXor = void{} },
3007 Token.Id.Equal => ast.Node.InfixOp.Op { .Assign = void{} },
3008 Token.Id.MinusEqual => ast.Node.InfixOp.Op { .AssignMinus = void{} },
3009 Token.Id.MinusPercentEqual => ast.Node.InfixOp.Op { .AssignMinusWrap = void{} },
3010 Token.Id.PercentEqual => ast.Node.InfixOp.Op { .AssignMod = void{} },
3011 Token.Id.PipeEqual => ast.Node.InfixOp.Op { .AssignBitOr = void{} },
3012 Token.Id.PlusEqual => ast.Node.InfixOp.Op { .AssignPlus = void{} },
3013 Token.Id.PlusPercentEqual => ast.Node.InfixOp.Op { .AssignPlusWrap = void{} },
3014 Token.Id.SlashEqual => ast.Node.InfixOp.Op { .AssignDiv = void{} },
29613015 else => null,
29623016 };
29633017 }
29643018
2965 fn tokenIdToComparison(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
2966 return switch (*id) {
2967 Token.Id.BangEqual => ast.NodeInfixOp.InfixOp { .BangEqual = void{} },
2968 Token.Id.EqualEqual => ast.NodeInfixOp.InfixOp { .EqualEqual = void{} },
2969 Token.Id.AngleBracketLeft => ast.NodeInfixOp.InfixOp { .LessThan = void{} },
2970 Token.Id.AngleBracketLeftEqual => ast.NodeInfixOp.InfixOp { .LessOrEqual = void{} },
2971 Token.Id.AngleBracketRight => ast.NodeInfixOp.InfixOp { .GreaterThan = void{} },
2972 Token.Id.AngleBracketRightEqual => ast.NodeInfixOp.InfixOp { .GreaterOrEqual = void{} },
3019 fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3020 return switch (id) {
3021 Token.Id.Keyword_catch => ast.Node.InfixOp.Op { .Catch = null },
3022 Token.Id.QuestionMarkQuestionMark => ast.Node.InfixOp.Op { .UnwrapMaybe = void{} },
29733023 else => null,
29743024 };
29753025 }
29763026
2977 fn tokenIdToBitShift(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
2978 return switch (*id) {
2979 Token.Id.AngleBracketAngleBracketLeft => ast.NodeInfixOp.InfixOp { .BitShiftLeft = void{} },
2980 Token.Id.AngleBracketAngleBracketRight => ast.NodeInfixOp.InfixOp { .BitShiftRight = void{} },
3027 fn tokenIdToComparison(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3028 return switch (id) {
3029 Token.Id.BangEqual => ast.Node.InfixOp.Op { .BangEqual = void{} },
3030 Token.Id.EqualEqual => ast.Node.InfixOp.Op { .EqualEqual = void{} },
3031 Token.Id.AngleBracketLeft => ast.Node.InfixOp.Op { .LessThan = void{} },
3032 Token.Id.AngleBracketLeftEqual => ast.Node.InfixOp.Op { .LessOrEqual = void{} },
3033 Token.Id.AngleBracketRight => ast.Node.InfixOp.Op { .GreaterThan = void{} },
3034 Token.Id.AngleBracketRightEqual => ast.Node.InfixOp.Op { .GreaterOrEqual = void{} },
29813035 else => null,
29823036 };
29833037 }
29843038
2985 fn tokenIdToAddition(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
2986 return switch (*id) {
2987 Token.Id.Minus => ast.NodeInfixOp.InfixOp { .Sub = void{} },
2988 Token.Id.MinusPercent => ast.NodeInfixOp.InfixOp { .SubWrap = void{} },
2989 Token.Id.Plus => ast.NodeInfixOp.InfixOp { .Add = void{} },
2990 Token.Id.PlusPercent => ast.NodeInfixOp.InfixOp { .AddWrap = void{} },
2991 Token.Id.PlusPlus => ast.NodeInfixOp.InfixOp { .ArrayCat = void{} },
3039 fn tokenIdToBitShift(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3040 return switch (id) {
3041 Token.Id.AngleBracketAngleBracketLeft => ast.Node.InfixOp.Op { .BitShiftLeft = void{} },
3042 Token.Id.AngleBracketAngleBracketRight => ast.Node.InfixOp.Op { .BitShiftRight = void{} },
29923043 else => null,
29933044 };
29943045 }
29953046
2996 fn tokenIdToMultiply(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
2997 return switch (*id) {
2998 Token.Id.Slash => ast.NodeInfixOp.InfixOp { .Div = void{} },
2999 Token.Id.Asterisk => ast.NodeInfixOp.InfixOp { .Mult = void{} },
3000 Token.Id.AsteriskAsterisk => ast.NodeInfixOp.InfixOp { .ArrayMult = void{} },
3001 Token.Id.AsteriskPercent => ast.NodeInfixOp.InfixOp { .MultWrap = void{} },
3002 Token.Id.Percent => ast.NodeInfixOp.InfixOp { .Mod = void{} },
3003 Token.Id.PipePipe => ast.NodeInfixOp.InfixOp { .MergeErrorSets = void{} },
3047 fn tokenIdToAddition(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3048 return switch (id) {
3049 Token.Id.Minus => ast.Node.InfixOp.Op { .Sub = void{} },
3050 Token.Id.MinusPercent => ast.Node.InfixOp.Op { .SubWrap = void{} },
3051 Token.Id.Plus => ast.Node.InfixOp.Op { .Add = void{} },
3052 Token.Id.PlusPercent => ast.Node.InfixOp.Op { .AddWrap = void{} },
3053 Token.Id.PlusPlus => ast.Node.InfixOp.Op { .ArrayCat = void{} },
30043054 else => null,
30053055 };
30063056 }
30073057
3008 fn tokenIdToPrefixOp(id: &const Token.Id) ?ast.NodePrefixOp.PrefixOp {
3009 return switch (*id) {
3010 Token.Id.Bang => ast.NodePrefixOp.PrefixOp { .BoolNot = void{} },
3011 Token.Id.Tilde => ast.NodePrefixOp.PrefixOp { .BitNot = void{} },
3012 Token.Id.Minus => ast.NodePrefixOp.PrefixOp { .Negation = void{} },
3013 Token.Id.MinusPercent => ast.NodePrefixOp.PrefixOp { .NegationWrap = void{} },
3014 Token.Id.Asterisk, Token.Id.AsteriskAsterisk => ast.NodePrefixOp.PrefixOp { .Deref = void{} },
3015 Token.Id.Ampersand => ast.NodePrefixOp.PrefixOp {
3016 .AddrOf = ast.NodePrefixOp.AddrOfInfo {
3058 fn tokenIdToMultiply(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op {
3059 return switch (id) {
3060 Token.Id.Slash => ast.Node.InfixOp.Op { .Div = void{} },
3061 Token.Id.Asterisk => ast.Node.InfixOp.Op { .Mult = void{} },
3062 Token.Id.AsteriskAsterisk => ast.Node.InfixOp.Op { .ArrayMult = void{} },
3063 Token.Id.AsteriskPercent => ast.Node.InfixOp.Op { .MultWrap = void{} },
3064 Token.Id.Percent => ast.Node.InfixOp.Op { .Mod = void{} },
3065 Token.Id.PipePipe => ast.Node.InfixOp.Op { .MergeErrorSets = void{} },
3066 else => null,
3067 };
3068 }
3069
3070 fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op {
3071 return switch (id) {
3072 Token.Id.Bang => ast.Node.PrefixOp.Op { .BoolNot = void{} },
3073 Token.Id.Tilde => ast.Node.PrefixOp.Op { .BitNot = void{} },
3074 Token.Id.Minus => ast.Node.PrefixOp.Op { .Negation = void{} },
3075 Token.Id.MinusPercent => ast.Node.PrefixOp.Op { .NegationWrap = void{} },
3076 Token.Id.Asterisk, Token.Id.AsteriskAsterisk => ast.Node.PrefixOp.Op { .Deref = void{} },
3077 Token.Id.Ampersand => ast.Node.PrefixOp.Op {
3078 .AddrOf = ast.Node.PrefixOp.AddrOfInfo {
30173079 .align_expr = null,
30183080 .bit_offset_start_token = null,
30193081 .bit_offset_end_token = null,
......@@ -3021,10 +3083,10 @@ pub const Parser = struct {
30213083 .volatile_token = null,
30223084 },
30233085 },
3024 Token.Id.QuestionMark => ast.NodePrefixOp.PrefixOp { .MaybeType = void{} },
3025 Token.Id.QuestionMarkQuestionMark => ast.NodePrefixOp.PrefixOp { .UnwrapMaybe = void{} },
3026 Token.Id.Keyword_await => ast.NodePrefixOp.PrefixOp { .Await = void{} },
3027 Token.Id.Keyword_try => ast.NodePrefixOp.PrefixOp { .Try = void{ } },
3086 Token.Id.QuestionMark => ast.Node.PrefixOp.Op { .MaybeType = void{} },
3087 Token.Id.QuestionMarkQuestionMark => ast.Node.PrefixOp.Op { .UnwrapMaybe = void{} },
3088 Token.Id.Keyword_await => ast.Node.PrefixOp.Op { .Await = void{} },
3089 Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{ } },
30283090 else => null,
30293091 };
30303092 }
......@@ -3034,11 +3096,7 @@ pub const Parser = struct {
30343096 *node = *init_to;
30353097 node.base = blk: {
30363098 const id = ast.Node.typeToId(T);
3037 if (self.pending_line_comment_node) |comment_node| {
3038 self.pending_line_comment_node = null;
3039 break :blk ast.Node {.id = id, .comment = comment_node};
3040 }
3041 break :blk ast.Node {.id = id, .comment = null };
3099 break :blk ast.Node {.id = id};
30423100 };
30433101
30443102 return node;
......@@ -3051,9 +3109,9 @@ pub const Parser = struct {
30513109 return node;
30523110 }
30533111
3054 fn createToDestNode(self: &Parser, arena: &mem.Allocator, dest_ptr: &const DestPtr, comptime T: type, init_to: &const T) !&T {
3112 fn createToCtxNode(self: &Parser, arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, init_to: &const T) !&T {
30553113 const node = try self.createNode(arena, T, init_to);
3056 dest_ptr.store(&node.base);
3114 opt_ctx.store(&node.base);
30573115
30583116 return node;
30593117 }
......@@ -3067,51 +3125,38 @@ pub const Parser = struct {
30673125 );
30683126 }
30693127
3070 fn parseError(self: &Parser, stack: &ArrayList(State), token: &const Token, comptime fmt: []const u8, args: ...) !void {
3071 // Before reporting an error. We pop the stack to see if our state was optional
3072 self.revertIfOptional(stack) catch {
3073 const loc = self.tokenizer.getTokenLocation(0, token);
3074 warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args);
3075 warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]);
3076 {
3077 var i: usize = 0;
3078 while (i < loc.column) : (i += 1) {
3079 warn(" ");
3080 }
3081 }
3082 {
3083 const caret_count = token.end - token.start;
3084 var i: usize = 0;
3085 while (i < caret_count) : (i += 1) {
3086 warn("~");
3087 }
3088 }
3089 warn("\n");
3090 return error.ParseError;
3091 };
3128 fn createToCtxLiteral(self: &Parser, arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, token: &const Token) !&T {
3129 const node = try self.createLiteral(arena, T, token);
3130 opt_ctx.store(&node.base);
3131
3132 return node;
30923133 }
30933134
3094 fn revertIfOptional(self: &Parser, stack: &ArrayList(State)) !void {
3095 while (stack.popOrNull()) |state| {
3096 switch (state) {
3097 State.Optional => |revert| {
3098 *self = revert.parser;
3099 *self.tokenizer = revert.tokenizer;
3100 *revert.ptr = null;
3101 return;
3102 },
3103 else => { }
3135 fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) (error{ParseError}) {
3136 const loc = self.tokenizer.getTokenLocation(0, token);
3137 warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args);
3138 warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]);
3139 {
3140 var i: usize = 0;
3141 while (i < loc.column) : (i += 1) {
3142 warn(" ");
31043143 }
31053144 }
3106
3107 return error.NoOptionalStateFound;
3145 {
3146 const caret_count = token.end - token.start;
3147 var i: usize = 0;
3148 while (i < caret_count) : (i += 1) {
3149 warn("~");
3150 }
3151 }
3152 warn("\n");
3153 return error.ParseError;
31083154 }
31093155
3110 fn expectToken(self: &Parser, stack: &ArrayList(State), id: @TagType(Token.Id)) !?Token {
3156 fn expectToken(self: &Parser, id: @TagType(Token.Id)) !Token {
31113157 const token = self.getNextToken();
31123158 if (token.id != id) {
3113 try self.parseError(stack, token, "expected {}, found {}", @tagName(id), @tagName(token.id));
3114 return null;
3159 return self.parseError(token, "expected {}, found {}", @tagName(id), @tagName(token.id));
31153160 }
31163161 return token;
31173162 }
......@@ -3150,7 +3195,7 @@ pub const Parser = struct {
31503195 indent: usize,
31513196 };
31523197
3153 pub fn renderAst(self: &Parser, stream: var, root_node: &ast.NodeRoot) !void {
3198 pub fn renderAst(self: &Parser, stream: var, root_node: &ast.Node.Root) !void {
31543199 var stack = self.initUtilityArrayList(RenderAstFrame);
31553200 defer self.deinitUtilityArrayList(stack);
31563201
......@@ -3179,18 +3224,17 @@ pub const Parser = struct {
31793224
31803225 const RenderState = union(enum) {
31813226 TopLevelDecl: &ast.Node,
3182 FnProtoRParen: &ast.NodeFnProto,
31833227 ParamDecl: &ast.Node,
31843228 Text: []const u8,
31853229 Expression: &ast.Node,
3186 VarDecl: &ast.NodeVarDecl,
3230 VarDecl: &ast.Node.VarDecl,
31873231 Statement: &ast.Node,
3188 FieldInitializer: &ast.NodeFieldInitializer,
3232 FieldInitializer: &ast.Node.FieldInitializer,
31893233 PrintIndent,
31903234 Indent: usize,
31913235 };
31923236
3193 pub fn renderSource(self: &Parser, stream: var, root_node: &ast.NodeRoot) !void {
3237 pub fn renderSource(self: &Parser, stream: var, root_node: &ast.Node.Root) !void {
31943238 var stack = self.initUtilityArrayList(RenderState);
31953239 defer self.deinitUtilityArrayList(stack);
31963240
......@@ -3224,7 +3268,8 @@ pub const Parser = struct {
32243268 RenderState.TopLevelDecl => |decl| {
32253269 switch (decl.id) {
32263270 ast.Node.Id.FnProto => {
3227 const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", decl);
3271 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
3272 try self.renderComments(stream, fn_proto, indent);
32283273
32293274 if (fn_proto.body_node) |body_node| {
32303275 stack.append(RenderState { .Expression = body_node}) catch unreachable;
......@@ -3236,7 +3281,7 @@ pub const Parser = struct {
32363281 try stack.append(RenderState { .Expression = decl });
32373282 },
32383283 ast.Node.Id.Use => {
3239 const use_decl = @fieldParentPtr(ast.NodeUse, "base", decl);
3284 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
32403285 if (use_decl.visib_token) |visib_token| {
32413286 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
32423287 }
......@@ -3245,18 +3290,19 @@ pub const Parser = struct {
32453290 try stack.append(RenderState { .Expression = use_decl.expr });
32463291 },
32473292 ast.Node.Id.VarDecl => {
3248 const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", decl);
3293 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
32493294 try stack.append(RenderState { .VarDecl = var_decl});
32503295 },
32513296 ast.Node.Id.TestDecl => {
3252 const test_decl = @fieldParentPtr(ast.NodeTestDecl, "base", decl);
3297 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
3298 try self.renderComments(stream, test_decl, indent);
32533299 try stream.print("test ");
32543300 try stack.append(RenderState { .Expression = test_decl.body_node });
32553301 try stack.append(RenderState { .Text = " " });
32563302 try stack.append(RenderState { .Expression = test_decl.name });
32573303 },
32583304 ast.Node.Id.StructField => {
3259 const field = @fieldParentPtr(ast.NodeStructField, "base", decl);
3305 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
32603306 if (field.visib_token) |visib_token| {
32613307 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
32623308 }
......@@ -3264,7 +3310,7 @@ pub const Parser = struct {
32643310 try stack.append(RenderState { .Expression = field.type_expr});
32653311 },
32663312 ast.Node.Id.UnionTag => {
3267 const tag = @fieldParentPtr(ast.NodeUnionTag, "base", decl);
3313 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
32683314 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
32693315
32703316 if (tag.type_expr) |type_expr| {
......@@ -3273,7 +3319,7 @@ pub const Parser = struct {
32733319 }
32743320 },
32753321 ast.Node.Id.EnumTag => {
3276 const tag = @fieldParentPtr(ast.NodeEnumTag, "base", decl);
3322 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
32773323 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
32783324
32793325 if (tag.value) |value| {
......@@ -3292,6 +3338,7 @@ pub const Parser = struct {
32923338 },
32933339
32943340 RenderState.FieldInitializer => |field_init| {
3341 //TODO try self.renderComments(stream, field_init, indent);
32953342 try stream.print(".{}", self.tokenizer.getTokenSlice(field_init.name_token));
32963343 try stream.print(" = ");
32973344 try stack.append(RenderState { .Expression = field_init.expr });
......@@ -3337,7 +3384,8 @@ pub const Parser = struct {
33373384 },
33383385
33393386 RenderState.ParamDecl => |base| {
3340 const param_decl = @fieldParentPtr(ast.NodeParamDecl, "base", base);
3387 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
3388 // TODO try self.renderComments(stream, param_decl, indent);
33413389 if (param_decl.comptime_token) |comptime_token| {
33423390 try stream.print("{} ", self.tokenizer.getTokenSlice(comptime_token));
33433391 }
......@@ -3358,11 +3406,11 @@ pub const Parser = struct {
33583406 },
33593407 RenderState.Expression => |base| switch (base.id) {
33603408 ast.Node.Id.Identifier => {
3361 const identifier = @fieldParentPtr(ast.NodeIdentifier, "base", base);
3409 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
33623410 try stream.print("{}", self.tokenizer.getTokenSlice(identifier.token));
33633411 },
33643412 ast.Node.Id.Block => {
3365 const block = @fieldParentPtr(ast.NodeBlock, "base", base);
3413 const block = @fieldParentPtr(ast.Node.Block, "base", base);
33663414 if (block.label) |label| {
33673415 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
33683416 }
......@@ -3398,17 +3446,17 @@ pub const Parser = struct {
33983446 }
33993447 },
34003448 ast.Node.Id.Defer => {
3401 const defer_node = @fieldParentPtr(ast.NodeDefer, "base", base);
3449 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
34023450 try stream.print("{} ", self.tokenizer.getTokenSlice(defer_node.defer_token));
34033451 try stack.append(RenderState { .Expression = defer_node.expr });
34043452 },
34053453 ast.Node.Id.Comptime => {
3406 const comptime_node = @fieldParentPtr(ast.NodeComptime, "base", base);
3454 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
34073455 try stream.print("{} ", self.tokenizer.getTokenSlice(comptime_node.comptime_token));
34083456 try stack.append(RenderState { .Expression = comptime_node.expr });
34093457 },
34103458 ast.Node.Id.AsyncAttribute => {
3411 const async_attr = @fieldParentPtr(ast.NodeAsyncAttribute, "base", base);
3459 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);
34123460 try stream.print("{}", self.tokenizer.getTokenSlice(async_attr.async_token));
34133461
34143462 if (async_attr.allocator_type) |allocator_type| {
......@@ -3418,7 +3466,7 @@ pub const Parser = struct {
34183466 }
34193467 },
34203468 ast.Node.Id.Suspend => {
3421 const suspend_node = @fieldParentPtr(ast.NodeSuspend, "base", base);
3469 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
34223470 try stream.print("{}", self.tokenizer.getTokenSlice(suspend_node.suspend_token));
34233471
34243472 if (suspend_node.body) |body| {
......@@ -3427,65 +3475,65 @@ pub const Parser = struct {
34273475 }
34283476
34293477 if (suspend_node.payload) |payload| {
3430 try stack.append(RenderState { .Expression = &payload.base });
3478 try stack.append(RenderState { .Expression = payload });
34313479 try stack.append(RenderState { .Text = " " });
34323480 }
34333481 },
34343482 ast.Node.Id.InfixOp => {
3435 const prefix_op_node = @fieldParentPtr(ast.NodeInfixOp, "base", base);
3483 const prefix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
34363484 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
34373485
3438 if (prefix_op_node.op == ast.NodeInfixOp.InfixOp.Catch) {
3486 if (prefix_op_node.op == ast.Node.InfixOp.Op.Catch) {
34393487 if (prefix_op_node.op.Catch) |payload| {
34403488 try stack.append(RenderState { .Text = " " });
3441 try stack.append(RenderState { .Expression = &payload.base });
3489 try stack.append(RenderState { .Expression = payload });
34423490 }
34433491 try stack.append(RenderState { .Text = " catch " });
34443492 } else {
34453493 const text = switch (prefix_op_node.op) {
3446 ast.NodeInfixOp.InfixOp.Add => " + ",
3447 ast.NodeInfixOp.InfixOp.AddWrap => " +% ",
3448 ast.NodeInfixOp.InfixOp.ArrayCat => " ++ ",
3449 ast.NodeInfixOp.InfixOp.ArrayMult => " ** ",
3450 ast.NodeInfixOp.InfixOp.Assign => " = ",
3451 ast.NodeInfixOp.InfixOp.AssignBitAnd => " &= ",
3452 ast.NodeInfixOp.InfixOp.AssignBitOr => " |= ",
3453 ast.NodeInfixOp.InfixOp.AssignBitShiftLeft => " <<= ",
3454 ast.NodeInfixOp.InfixOp.AssignBitShiftRight => " >>= ",
3455 ast.NodeInfixOp.InfixOp.AssignBitXor => " ^= ",
3456 ast.NodeInfixOp.InfixOp.AssignDiv => " /= ",
3457 ast.NodeInfixOp.InfixOp.AssignMinus => " -= ",
3458 ast.NodeInfixOp.InfixOp.AssignMinusWrap => " -%= ",
3459 ast.NodeInfixOp.InfixOp.AssignMod => " %= ",
3460 ast.NodeInfixOp.InfixOp.AssignPlus => " += ",
3461 ast.NodeInfixOp.InfixOp.AssignPlusWrap => " +%= ",
3462 ast.NodeInfixOp.InfixOp.AssignTimes => " *= ",
3463 ast.NodeInfixOp.InfixOp.AssignTimesWarp => " *%= ",
3464 ast.NodeInfixOp.InfixOp.BangEqual => " != ",
3465 ast.NodeInfixOp.InfixOp.BitAnd => " & ",
3466 ast.NodeInfixOp.InfixOp.BitOr => " | ",
3467 ast.NodeInfixOp.InfixOp.BitShiftLeft => " << ",
3468 ast.NodeInfixOp.InfixOp.BitShiftRight => " >> ",
3469 ast.NodeInfixOp.InfixOp.BitXor => " ^ ",
3470 ast.NodeInfixOp.InfixOp.BoolAnd => " and ",
3471 ast.NodeInfixOp.InfixOp.BoolOr => " or ",
3472 ast.NodeInfixOp.InfixOp.Div => " / ",
3473 ast.NodeInfixOp.InfixOp.EqualEqual => " == ",
3474 ast.NodeInfixOp.InfixOp.ErrorUnion => "!",
3475 ast.NodeInfixOp.InfixOp.GreaterOrEqual => " >= ",
3476 ast.NodeInfixOp.InfixOp.GreaterThan => " > ",
3477 ast.NodeInfixOp.InfixOp.LessOrEqual => " <= ",
3478 ast.NodeInfixOp.InfixOp.LessThan => " < ",
3479 ast.NodeInfixOp.InfixOp.MergeErrorSets => " || ",
3480 ast.NodeInfixOp.InfixOp.Mod => " % ",
3481 ast.NodeInfixOp.InfixOp.Mult => " * ",
3482 ast.NodeInfixOp.InfixOp.MultWrap => " *% ",
3483 ast.NodeInfixOp.InfixOp.Period => ".",
3484 ast.NodeInfixOp.InfixOp.Sub => " - ",
3485 ast.NodeInfixOp.InfixOp.SubWrap => " -% ",
3486 ast.NodeInfixOp.InfixOp.UnwrapMaybe => " ?? ",
3487 ast.NodeInfixOp.InfixOp.Range => " ... ",
3488 ast.NodeInfixOp.InfixOp.Catch => unreachable,
3494 ast.Node.InfixOp.Op.Add => " + ",
3495 ast.Node.InfixOp.Op.AddWrap => " +% ",
3496 ast.Node.InfixOp.Op.ArrayCat => " ++ ",
3497 ast.Node.InfixOp.Op.ArrayMult => " ** ",
3498 ast.Node.InfixOp.Op.Assign => " = ",
3499 ast.Node.InfixOp.Op.AssignBitAnd => " &= ",
3500 ast.Node.InfixOp.Op.AssignBitOr => " |= ",
3501 ast.Node.InfixOp.Op.AssignBitShiftLeft => " <<= ",
3502 ast.Node.InfixOp.Op.AssignBitShiftRight => " >>= ",
3503 ast.Node.InfixOp.Op.AssignBitXor => " ^= ",
3504 ast.Node.InfixOp.Op.AssignDiv => " /= ",
3505 ast.Node.InfixOp.Op.AssignMinus => " -= ",
3506 ast.Node.InfixOp.Op.AssignMinusWrap => " -%= ",
3507 ast.Node.InfixOp.Op.AssignMod => " %= ",
3508 ast.Node.InfixOp.Op.AssignPlus => " += ",
3509 ast.Node.InfixOp.Op.AssignPlusWrap => " +%= ",
3510 ast.Node.InfixOp.Op.AssignTimes => " *= ",
3511 ast.Node.InfixOp.Op.AssignTimesWarp => " *%= ",
3512 ast.Node.InfixOp.Op.BangEqual => " != ",
3513 ast.Node.InfixOp.Op.BitAnd => " & ",
3514 ast.Node.InfixOp.Op.BitOr => " | ",
3515 ast.Node.InfixOp.Op.BitShiftLeft => " << ",
3516 ast.Node.InfixOp.Op.BitShiftRight => " >> ",
3517 ast.Node.InfixOp.Op.BitXor => " ^ ",
3518 ast.Node.InfixOp.Op.BoolAnd => " and ",
3519 ast.Node.InfixOp.Op.BoolOr => " or ",
3520 ast.Node.InfixOp.Op.Div => " / ",
3521 ast.Node.InfixOp.Op.EqualEqual => " == ",
3522 ast.Node.InfixOp.Op.ErrorUnion => "!",
3523 ast.Node.InfixOp.Op.GreaterOrEqual => " >= ",
3524 ast.Node.InfixOp.Op.GreaterThan => " > ",
3525 ast.Node.InfixOp.Op.LessOrEqual => " <= ",
3526 ast.Node.InfixOp.Op.LessThan => " < ",
3527 ast.Node.InfixOp.Op.MergeErrorSets => " || ",
3528 ast.Node.InfixOp.Op.Mod => " % ",
3529 ast.Node.InfixOp.Op.Mult => " * ",
3530 ast.Node.InfixOp.Op.MultWrap => " *% ",
3531 ast.Node.InfixOp.Op.Period => ".",
3532 ast.Node.InfixOp.Op.Sub => " - ",
3533 ast.Node.InfixOp.Op.SubWrap => " -% ",
3534 ast.Node.InfixOp.Op.UnwrapMaybe => " ?? ",
3535 ast.Node.InfixOp.Op.Range => " ... ",
3536 ast.Node.InfixOp.Op.Catch => unreachable,
34893537 };
34903538
34913539 try stack.append(RenderState { .Text = text });
......@@ -3493,10 +3541,10 @@ pub const Parser = struct {
34933541 try stack.append(RenderState { .Expression = prefix_op_node.lhs });
34943542 },
34953543 ast.Node.Id.PrefixOp => {
3496 const prefix_op_node = @fieldParentPtr(ast.NodePrefixOp, "base", base);
3544 const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
34973545 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
34983546 switch (prefix_op_node.op) {
3499 ast.NodePrefixOp.PrefixOp.AddrOf => |addr_of_info| {
3547 ast.Node.PrefixOp.Op.AddrOf => |addr_of_info| {
35003548 try stream.write("&");
35013549 if (addr_of_info.volatile_token != null) {
35023550 try stack.append(RenderState { .Text = "volatile "});
......@@ -3510,7 +3558,7 @@ pub const Parser = struct {
35103558 try stack.append(RenderState { .Expression = align_expr});
35113559 }
35123560 },
3513 ast.NodePrefixOp.PrefixOp.SliceType => |addr_of_info| {
3561 ast.Node.PrefixOp.Op.SliceType => |addr_of_info| {
35143562 try stream.write("[]");
35153563 if (addr_of_info.volatile_token != null) {
35163564 try stack.append(RenderState { .Text = "volatile "});
......@@ -3524,29 +3572,29 @@ pub const Parser = struct {
35243572 try stack.append(RenderState { .Expression = align_expr});
35253573 }
35263574 },
3527 ast.NodePrefixOp.PrefixOp.ArrayType => |array_index| {
3575 ast.Node.PrefixOp.Op.ArrayType => |array_index| {
35283576 try stack.append(RenderState { .Text = "]"});
35293577 try stack.append(RenderState { .Expression = array_index});
35303578 try stack.append(RenderState { .Text = "["});
35313579 },
3532 ast.NodePrefixOp.PrefixOp.BitNot => try stream.write("~"),
3533 ast.NodePrefixOp.PrefixOp.BoolNot => try stream.write("!"),
3534 ast.NodePrefixOp.PrefixOp.Deref => try stream.write("*"),
3535 ast.NodePrefixOp.PrefixOp.Negation => try stream.write("-"),
3536 ast.NodePrefixOp.PrefixOp.NegationWrap => try stream.write("-%"),
3537 ast.NodePrefixOp.PrefixOp.Try => try stream.write("try "),
3538 ast.NodePrefixOp.PrefixOp.UnwrapMaybe => try stream.write("??"),
3539 ast.NodePrefixOp.PrefixOp.MaybeType => try stream.write("?"),
3540 ast.NodePrefixOp.PrefixOp.Await => try stream.write("await "),
3541 ast.NodePrefixOp.PrefixOp.Cancel => try stream.write("cancel "),
3542 ast.NodePrefixOp.PrefixOp.Resume => try stream.write("resume "),
3580 ast.Node.PrefixOp.Op.BitNot => try stream.write("~"),
3581 ast.Node.PrefixOp.Op.BoolNot => try stream.write("!"),
3582 ast.Node.PrefixOp.Op.Deref => try stream.write("*"),
3583 ast.Node.PrefixOp.Op.Negation => try stream.write("-"),
3584 ast.Node.PrefixOp.Op.NegationWrap => try stream.write("-%"),
3585 ast.Node.PrefixOp.Op.Try => try stream.write("try "),
3586 ast.Node.PrefixOp.Op.UnwrapMaybe => try stream.write("??"),
3587 ast.Node.PrefixOp.Op.MaybeType => try stream.write("?"),
3588 ast.Node.PrefixOp.Op.Await => try stream.write("await "),
3589 ast.Node.PrefixOp.Op.Cancel => try stream.write("cancel "),
3590 ast.Node.PrefixOp.Op.Resume => try stream.write("resume "),
35433591 }
35443592 },
35453593 ast.Node.Id.SuffixOp => {
3546 const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", base);
3594 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
35473595
35483596 switch (suffix_op.op) {
3549 ast.NodeSuffixOp.SuffixOp.Call => |call_info| {
3597 ast.Node.SuffixOp.Op.Call => |call_info| {
35503598 try stack.append(RenderState { .Text = ")"});
35513599 var i = call_info.params.len;
35523600 while (i != 0) {
......@@ -3565,13 +3613,13 @@ pub const Parser = struct {
35653613 try stack.append(RenderState { .Expression = &async_attr.base });
35663614 }
35673615 },
3568 ast.NodeSuffixOp.SuffixOp.ArrayAccess => |index_expr| {
3616 ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {
35693617 try stack.append(RenderState { .Text = "]"});
35703618 try stack.append(RenderState { .Expression = index_expr});
35713619 try stack.append(RenderState { .Text = "["});
35723620 try stack.append(RenderState { .Expression = suffix_op.lhs });
35733621 },
3574 ast.NodeSuffixOp.SuffixOp.Slice => |range| {
3622 ast.Node.SuffixOp.Op.Slice => |range| {
35753623 try stack.append(RenderState { .Text = "]"});
35763624 if (range.end) |end| {
35773625 try stack.append(RenderState { .Expression = end});
......@@ -3581,162 +3629,177 @@ pub const Parser = struct {
35813629 try stack.append(RenderState { .Text = "["});
35823630 try stack.append(RenderState { .Expression = suffix_op.lhs });
35833631 },
3584 ast.NodeSuffixOp.SuffixOp.StructInitializer => |field_inits| {
3585 try stack.append(RenderState { .Text = " }"});
3632 ast.Node.SuffixOp.Op.StructInitializer => |field_inits| {
3633 if (field_inits.len == 0) {
3634 try stack.append(RenderState { .Text = "{}" });
3635 try stack.append(RenderState { .Expression = suffix_op.lhs });
3636 continue;
3637 }
3638 try stack.append(RenderState { .Text = "}"});
3639 try stack.append(RenderState.PrintIndent);
3640 try stack.append(RenderState { .Indent = indent });
35863641 var i = field_inits.len;
35873642 while (i != 0) {
35883643 i -= 1;
35893644 const field_init = field_inits.at(i);
3645 try stack.append(RenderState { .Text = ",\n" });
35903646 try stack.append(RenderState { .FieldInitializer = field_init });
3591 try stack.append(RenderState { .Text = " " });
3592 if (i != 0) {
3593 try stack.append(RenderState { .Text = "," });
3594 }
3647 try stack.append(RenderState.PrintIndent);
35953648 }
3596 try stack.append(RenderState { .Text = "{"});
3649 try stack.append(RenderState { .Indent = indent + indent_delta });
3650 try stack.append(RenderState { .Text = " {\n"});
35973651 try stack.append(RenderState { .Expression = suffix_op.lhs });
35983652 },
3599 ast.NodeSuffixOp.SuffixOp.ArrayInitializer => |exprs| {
3600 try stack.append(RenderState { .Text = " }"});
3653 ast.Node.SuffixOp.Op.ArrayInitializer => |exprs| {
3654 if (exprs.len == 0) {
3655 try stack.append(RenderState { .Text = "{}" });
3656 try stack.append(RenderState { .Expression = suffix_op.lhs });
3657 continue;
3658 }
3659 try stack.append(RenderState { .Text = "}"});
3660 try stack.append(RenderState.PrintIndent);
3661 try stack.append(RenderState { .Indent = indent });
36013662 var i = exprs.len;
36023663 while (i != 0) {
36033664 i -= 1;
36043665 const expr = exprs.at(i);
3666 try stack.append(RenderState { .Text = ",\n" });
36053667 try stack.append(RenderState { .Expression = expr });
3606 try stack.append(RenderState { .Text = " " });
3607 if (i != 0) {
3608 try stack.append(RenderState { .Text = "," });
3609 }
3668 try stack.append(RenderState.PrintIndent);
36103669 }
3611 try stack.append(RenderState { .Text = "{"});
3670 try stack.append(RenderState { .Indent = indent + indent_delta });
3671 try stack.append(RenderState { .Text = " {\n"});
36123672 try stack.append(RenderState { .Expression = suffix_op.lhs });
36133673 },
36143674 }
36153675 },
36163676 ast.Node.Id.ControlFlowExpression => {
3617 const flow_expr = @fieldParentPtr(ast.NodeControlFlowExpression, "base", base);
3677 const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);
3678
3679 if (flow_expr.rhs) |rhs| {
3680 try stack.append(RenderState { .Expression = rhs });
3681 try stack.append(RenderState { .Text = " " });
3682 }
3683
36183684 switch (flow_expr.kind) {
3619 ast.NodeControlFlowExpression.Kind.Break => |maybe_blk_token| {
3685 ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {
36203686 try stream.print("break");
3621 if (maybe_blk_token) |blk_token| {
3622 try stream.print(" :{}", self.tokenizer.getTokenSlice(blk_token));
3687 if (maybe_label) |label| {
3688 try stream.print(" :");
3689 try stack.append(RenderState { .Expression = label });
36233690 }
36243691 },
3625 ast.NodeControlFlowExpression.Kind.Continue => |maybe_blk_token| {
3692 ast.Node.ControlFlowExpression.Kind.Continue => |maybe_label| {
36263693 try stream.print("continue");
3627 if (maybe_blk_token) |blk_token| {
3628 try stream.print(" :{}", self.tokenizer.getTokenSlice(blk_token));
3694 if (maybe_label) |label| {
3695 try stream.print(" :");
3696 try stack.append(RenderState { .Expression = label });
36293697 }
36303698 },
3631 ast.NodeControlFlowExpression.Kind.Return => {
3699 ast.Node.ControlFlowExpression.Kind.Return => {
36323700 try stream.print("return");
36333701 },
36343702
36353703 }
3636
3637 if (flow_expr.rhs) |rhs| {
3638 try stream.print(" ");
3639 try stack.append(RenderState { .Expression = rhs });
3640 }
36413704 },
36423705 ast.Node.Id.Payload => {
3643 const payload = @fieldParentPtr(ast.NodePayload, "base", base);
3706 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
36443707 try stack.append(RenderState { .Text = "|"});
3645 try stack.append(RenderState { .Expression = &payload.error_symbol.base });
3708 try stack.append(RenderState { .Expression = payload.error_symbol });
36463709 try stack.append(RenderState { .Text = "|"});
36473710 },
36483711 ast.Node.Id.PointerPayload => {
3649 const payload = @fieldParentPtr(ast.NodePointerPayload, "base", base);
3712 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
36503713 try stack.append(RenderState { .Text = "|"});
3651 try stack.append(RenderState { .Expression = &payload.value_symbol.base });
3714 try stack.append(RenderState { .Expression = payload.value_symbol });
36523715
3653 if (payload.is_ptr) {
3654 try stack.append(RenderState { .Text = "*"});
3716 if (payload.ptr_token) |ptr_token| {
3717 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(ptr_token) });
36553718 }
36563719
36573720 try stack.append(RenderState { .Text = "|"});
36583721 },
36593722 ast.Node.Id.PointerIndexPayload => {
3660 const payload = @fieldParentPtr(ast.NodePointerIndexPayload, "base", base);
3723 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
36613724 try stack.append(RenderState { .Text = "|"});
36623725
36633726 if (payload.index_symbol) |index_symbol| {
3664 try stack.append(RenderState { .Expression = &index_symbol.base });
3727 try stack.append(RenderState { .Expression = index_symbol });
36653728 try stack.append(RenderState { .Text = ", "});
36663729 }
36673730
3668 try stack.append(RenderState { .Expression = &payload.value_symbol.base });
3731 try stack.append(RenderState { .Expression = payload.value_symbol });
36693732
3670 if (payload.is_ptr) {
3671 try stack.append(RenderState { .Text = "*"});
3733 if (payload.ptr_token) |ptr_token| {
3734 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(ptr_token) });
36723735 }
36733736
36743737 try stack.append(RenderState { .Text = "|"});
36753738 },
36763739 ast.Node.Id.GroupedExpression => {
3677 const grouped_expr = @fieldParentPtr(ast.NodeGroupedExpression, "base", base);
3740 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
36783741 try stack.append(RenderState { .Text = ")"});
36793742 try stack.append(RenderState { .Expression = grouped_expr.expr });
36803743 try stack.append(RenderState { .Text = "("});
36813744 },
36823745 ast.Node.Id.FieldInitializer => {
3683 const field_init = @fieldParentPtr(ast.NodeFieldInitializer, "base", base);
3746 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
36843747 try stream.print(".{} = ", self.tokenizer.getTokenSlice(field_init.name_token));
36853748 try stack.append(RenderState { .Expression = field_init.expr });
36863749 },
36873750 ast.Node.Id.IntegerLiteral => {
3688 const integer_literal = @fieldParentPtr(ast.NodeIntegerLiteral, "base", base);
3751 const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);
36893752 try stream.print("{}", self.tokenizer.getTokenSlice(integer_literal.token));
36903753 },
36913754 ast.Node.Id.FloatLiteral => {
3692 const float_literal = @fieldParentPtr(ast.NodeFloatLiteral, "base", base);
3755 const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);
36933756 try stream.print("{}", self.tokenizer.getTokenSlice(float_literal.token));
36943757 },
36953758 ast.Node.Id.StringLiteral => {
3696 const string_literal = @fieldParentPtr(ast.NodeStringLiteral, "base", base);
3759 const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);
36973760 try stream.print("{}", self.tokenizer.getTokenSlice(string_literal.token));
36983761 },
36993762 ast.Node.Id.CharLiteral => {
3700 const char_literal = @fieldParentPtr(ast.NodeCharLiteral, "base", base);
3763 const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
37013764 try stream.print("{}", self.tokenizer.getTokenSlice(char_literal.token));
37023765 },
37033766 ast.Node.Id.BoolLiteral => {
3704 const bool_literal = @fieldParentPtr(ast.NodeCharLiteral, "base", base);
3767 const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
37053768 try stream.print("{}", self.tokenizer.getTokenSlice(bool_literal.token));
37063769 },
37073770 ast.Node.Id.NullLiteral => {
3708 const null_literal = @fieldParentPtr(ast.NodeNullLiteral, "base", base);
3771 const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);
37093772 try stream.print("{}", self.tokenizer.getTokenSlice(null_literal.token));
37103773 },
37113774 ast.Node.Id.ThisLiteral => {
3712 const this_literal = @fieldParentPtr(ast.NodeThisLiteral, "base", base);
3775 const this_literal = @fieldParentPtr(ast.Node.ThisLiteral, "base", base);
37133776 try stream.print("{}", self.tokenizer.getTokenSlice(this_literal.token));
37143777 },
37153778 ast.Node.Id.Unreachable => {
3716 const unreachable_node = @fieldParentPtr(ast.NodeUnreachable, "base", base);
3779 const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);
37173780 try stream.print("{}", self.tokenizer.getTokenSlice(unreachable_node.token));
37183781 },
37193782 ast.Node.Id.ErrorType => {
3720 const error_type = @fieldParentPtr(ast.NodeErrorType, "base", base);
3783 const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);
37213784 try stream.print("{}", self.tokenizer.getTokenSlice(error_type.token));
37223785 },
37233786 ast.Node.Id.VarType => {
3724 const var_type = @fieldParentPtr(ast.NodeVarType, "base", base);
3787 const var_type = @fieldParentPtr(ast.Node.VarType, "base", base);
37253788 try stream.print("{}", self.tokenizer.getTokenSlice(var_type.token));
37263789 },
37273790 ast.Node.Id.ContainerDecl => {
3728 const container_decl = @fieldParentPtr(ast.NodeContainerDecl, "base", base);
3791 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
37293792
37303793 switch (container_decl.layout) {
3731 ast.NodeContainerDecl.Layout.Packed => try stream.print("packed "),
3732 ast.NodeContainerDecl.Layout.Extern => try stream.print("extern "),
3733 ast.NodeContainerDecl.Layout.Auto => { },
3794 ast.Node.ContainerDecl.Layout.Packed => try stream.print("packed "),
3795 ast.Node.ContainerDecl.Layout.Extern => try stream.print("extern "),
3796 ast.Node.ContainerDecl.Layout.Auto => { },
37343797 }
37353798
37363799 switch (container_decl.kind) {
3737 ast.NodeContainerDecl.Kind.Struct => try stream.print("struct"),
3738 ast.NodeContainerDecl.Kind.Enum => try stream.print("enum"),
3739 ast.NodeContainerDecl.Kind.Union => try stream.print("union"),
3800 ast.Node.ContainerDecl.Kind.Struct => try stream.print("struct"),
3801 ast.Node.ContainerDecl.Kind.Enum => try stream.print("enum"),
3802 ast.Node.ContainerDecl.Kind.Union => try stream.print("union"),
37403803 }
37413804
37423805 try stack.append(RenderState { .Text = "}"});
......@@ -3749,6 +3812,14 @@ pub const Parser = struct {
37493812 while (i != 0) {
37503813 i -= 1;
37513814 const node = fields_and_decls[i];
3815 switch (node.id) {
3816 ast.Node.Id.StructField,
3817 ast.Node.Id.UnionTag,
3818 ast.Node.Id.EnumTag => {
3819 try stack.append(RenderState { .Text = "," });
3820 },
3821 else => { }
3822 }
37523823 try stack.append(RenderState { .TopLevelDecl = node});
37533824 try stack.append(RenderState.PrintIndent);
37543825 try stack.append(RenderState {
......@@ -3763,26 +3834,14 @@ pub const Parser = struct {
37633834 break :blk "\n";
37643835 },
37653836 });
3766
3767 if (i != 0) {
3768 const prev_node = fields_and_decls[i - 1];
3769 switch (prev_node.id) {
3770 ast.Node.Id.StructField,
3771 ast.Node.Id.UnionTag,
3772 ast.Node.Id.EnumTag => {
3773 try stack.append(RenderState { .Text = "," });
3774 },
3775 else => { }
3776 }
3777 }
37783837 }
37793838 try stack.append(RenderState { .Indent = indent + indent_delta});
37803839 try stack.append(RenderState { .Text = "{"});
37813840
37823841 switch (container_decl.init_arg_expr) {
3783 ast.NodeContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),
3784 ast.NodeContainerDecl.InitArg.Enum => try stack.append(RenderState { .Text = "(enum) "}),
3785 ast.NodeContainerDecl.InitArg.Type => |type_expr| {
3842 ast.Node.ContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),
3843 ast.Node.ContainerDecl.InitArg.Enum => try stack.append(RenderState { .Text = "(enum) "}),
3844 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
37863845 try stack.append(RenderState { .Text = ") "});
37873846 try stack.append(RenderState { .Expression = type_expr});
37883847 try stack.append(RenderState { .Text = "("});
......@@ -3790,7 +3849,7 @@ pub const Parser = struct {
37903849 }
37913850 },
37923851 ast.Node.Id.ErrorSetDecl => {
3793 const err_set_decl = @fieldParentPtr(ast.NodeErrorSetDecl, "base", base);
3852 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
37943853 try stream.print("error ");
37953854
37963855 try stack.append(RenderState { .Text = "}"});
......@@ -3803,7 +3862,8 @@ pub const Parser = struct {
38033862 while (i != 0) {
38043863 i -= 1;
38053864 const node = decls[i];
3806 try stack.append(RenderState { .Expression = &node.base});
3865 try stack.append(RenderState { .Text = "," });
3866 try stack.append(RenderState { .Expression = node });
38073867 try stack.append(RenderState.PrintIndent);
38083868 try stack.append(RenderState {
38093869 .Text = blk: {
......@@ -3817,16 +3877,12 @@ pub const Parser = struct {
38173877 break :blk "\n";
38183878 },
38193879 });
3820
3821 if (i != 0) {
3822 try stack.append(RenderState { .Text = "," });
3823 }
38243880 }
38253881 try stack.append(RenderState { .Indent = indent + indent_delta});
38263882 try stack.append(RenderState { .Text = "{"});
38273883 },
38283884 ast.Node.Id.MultilineStringLiteral => {
3829 const multiline_str_literal = @fieldParentPtr(ast.NodeMultilineStringLiteral, "base", base);
3885 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
38303886 try stream.print("\n");
38313887
38323888 var i : usize = 0;
......@@ -3838,11 +3894,11 @@ pub const Parser = struct {
38383894 try stream.writeByteNTimes(' ', indent + indent_delta);
38393895 },
38403896 ast.Node.Id.UndefinedLiteral => {
3841 const undefined_literal = @fieldParentPtr(ast.NodeUndefinedLiteral, "base", base);
3897 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);
38423898 try stream.print("{}", self.tokenizer.getTokenSlice(undefined_literal.token));
38433899 },
38443900 ast.Node.Id.BuiltinCall => {
3845 const builtin_call = @fieldParentPtr(ast.NodeBuiltinCall, "base", base);
3901 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
38463902 try stream.print("{}(", self.tokenizer.getTokenSlice(builtin_call.builtin_token));
38473903 try stack.append(RenderState { .Text = ")"});
38483904 var i = builtin_call.params.len;
......@@ -3856,20 +3912,22 @@ pub const Parser = struct {
38563912 }
38573913 },
38583914 ast.Node.Id.FnProto => {
3859 const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", base);
3915 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
38603916
38613917 switch (fn_proto.return_type) {
3862 ast.NodeFnProto.ReturnType.Explicit => |node| {
3918 ast.Node.FnProto.ReturnType.Explicit => |node| {
38633919 try stack.append(RenderState { .Expression = node});
38643920 },
3865 ast.NodeFnProto.ReturnType.InferErrorSet => |node| {
3921 ast.Node.FnProto.ReturnType.InferErrorSet => |node| {
38663922 try stack.append(RenderState { .Expression = node});
38673923 try stack.append(RenderState { .Text = "!"});
38683924 },
38693925 }
38703926
3871 if (fn_proto.align_expr != null) {
3872 @panic("TODO");
3927 if (fn_proto.align_expr) |align_expr| {
3928 try stack.append(RenderState { .Text = ") " });
3929 try stack.append(RenderState { .Expression = align_expr});
3930 try stack.append(RenderState { .Text = "align(" });
38733931 }
38743932
38753933 try stack.append(RenderState { .Text = ") " });
......@@ -3918,7 +3976,7 @@ pub const Parser = struct {
39183976 },
39193977 ast.Node.Id.LineComment => @panic("TODO render line comment in an expression"),
39203978 ast.Node.Id.Switch => {
3921 const switch_node = @fieldParentPtr(ast.NodeSwitch, "base", base);
3979 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
39223980 try stream.print("{} (", self.tokenizer.getTokenSlice(switch_node.switch_token));
39233981
39243982 try stack.append(RenderState { .Text = "}"});
......@@ -3931,6 +3989,7 @@ pub const Parser = struct {
39313989 while (i != 0) {
39323990 i -= 1;
39333991 const node = cases[i];
3992 try stack.append(RenderState { .Text = ","});
39343993 try stack.append(RenderState { .Expression = &node.base});
39353994 try stack.append(RenderState.PrintIndent);
39363995 try stack.append(RenderState {
......@@ -3945,22 +4004,18 @@ pub const Parser = struct {
39454004 break :blk "\n";
39464005 },
39474006 });
3948
3949 if (i != 0) {
3950 try stack.append(RenderState { .Text = "," });
3951 }
39524007 }
39534008 try stack.append(RenderState { .Indent = indent + indent_delta});
39544009 try stack.append(RenderState { .Text = ") {"});
39554010 try stack.append(RenderState { .Expression = switch_node.expr });
39564011 },
39574012 ast.Node.Id.SwitchCase => {
3958 const switch_case = @fieldParentPtr(ast.NodeSwitchCase, "base", base);
4013 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
39594014
39604015 try stack.append(RenderState { .Expression = switch_case.expr });
39614016 if (switch_case.payload) |payload| {
39624017 try stack.append(RenderState { .Text = " " });
3963 try stack.append(RenderState { .Expression = &payload.base });
4018 try stack.append(RenderState { .Expression = payload });
39644019 }
39654020 try stack.append(RenderState { .Text = " => "});
39664021
......@@ -3971,16 +4026,17 @@ pub const Parser = struct {
39714026 try stack.append(RenderState { .Expression = items[i] });
39724027
39734028 if (i != 0) {
3974 try stack.append(RenderState { .Text = ", " });
4029 try stack.append(RenderState.PrintIndent);
4030 try stack.append(RenderState { .Text = ",\n" });
39754031 }
39764032 }
39774033 },
39784034 ast.Node.Id.SwitchElse => {
3979 const switch_else = @fieldParentPtr(ast.NodeSwitchElse, "base", base);
4035 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
39804036 try stream.print("{}", self.tokenizer.getTokenSlice(switch_else.token));
39814037 },
39824038 ast.Node.Id.Else => {
3983 const else_node = @fieldParentPtr(ast.NodeElse, "base", base);
4039 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
39844040 try stream.print("{}", self.tokenizer.getTokenSlice(else_node.else_token));
39854041
39864042 switch (else_node.body.id) {
......@@ -4001,11 +4057,11 @@ pub const Parser = struct {
40014057
40024058 if (else_node.payload) |payload| {
40034059 try stack.append(RenderState { .Text = " " });
4004 try stack.append(RenderState { .Expression = &payload.base });
4060 try stack.append(RenderState { .Expression = payload });
40054061 }
40064062 },
40074063 ast.Node.Id.While => {
4008 const while_node = @fieldParentPtr(ast.NodeWhile, "base", base);
4064 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
40094065 if (while_node.label) |label| {
40104066 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
40114067 }
......@@ -4046,7 +4102,7 @@ pub const Parser = struct {
40464102 }
40474103
40484104 if (while_node.payload) |payload| {
4049 try stack.append(RenderState { .Expression = &payload.base });
4105 try stack.append(RenderState { .Expression = payload });
40504106 try stack.append(RenderState { .Text = " " });
40514107 }
40524108
......@@ -4055,7 +4111,7 @@ pub const Parser = struct {
40554111 try stack.append(RenderState { .Text = "(" });
40564112 },
40574113 ast.Node.Id.For => {
4058 const for_node = @fieldParentPtr(ast.NodeFor, "base", base);
4114 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
40594115 if (for_node.label) |label| {
40604116 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
40614117 }
......@@ -4089,7 +4145,7 @@ pub const Parser = struct {
40894145 }
40904146
40914147 if (for_node.payload) |payload| {
4092 try stack.append(RenderState { .Expression = &payload.base });
4148 try stack.append(RenderState { .Expression = payload });
40934149 try stack.append(RenderState { .Text = " " });
40944150 }
40954151
......@@ -4098,7 +4154,7 @@ pub const Parser = struct {
40984154 try stack.append(RenderState { .Text = "(" });
40994155 },
41004156 ast.Node.Id.If => {
4101 const if_node = @fieldParentPtr(ast.NodeIf, "base", base);
4157 const if_node = @fieldParentPtr(ast.Node.If, "base", base);
41024158 try stream.print("{} ", self.tokenizer.getTokenSlice(if_node.if_token));
41034159
41044160 switch (if_node.body.id) {
......@@ -4122,7 +4178,7 @@ pub const Parser = struct {
41224178
41234179 if (@"else".payload) |payload| {
41244180 try stack.append(RenderState { .Text = " " });
4125 try stack.append(RenderState { .Expression = &payload.base });
4181 try stack.append(RenderState { .Expression = payload });
41264182 }
41274183
41284184 try stack.append(RenderState { .Text = " " });
......@@ -4136,7 +4192,7 @@ pub const Parser = struct {
41364192 try stack.append(RenderState { .Text = " " });
41374193
41384194 if (if_node.payload) |payload| {
4139 try stack.append(RenderState { .Expression = &payload.base });
4195 try stack.append(RenderState { .Expression = payload });
41404196 try stack.append(RenderState { .Text = " " });
41414197 }
41424198
......@@ -4145,11 +4201,11 @@ pub const Parser = struct {
41454201 try stack.append(RenderState { .Text = "(" });
41464202 },
41474203 ast.Node.Id.Asm => {
4148 const asm_node = @fieldParentPtr(ast.NodeAsm, "base", base);
4204 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
41494205 try stream.print("{} ", self.tokenizer.getTokenSlice(asm_node.asm_token));
41504206
4151 if (asm_node.is_volatile) {
4152 try stream.write("volatile ");
4207 if (asm_node.volatile_token) |volatile_token| {
4208 try stream.print("{} ", self.tokenizer.getTokenSlice(volatile_token));
41534209 }
41544210
41554211 try stack.append(RenderState { .Indent = indent });
......@@ -4232,25 +4288,25 @@ pub const Parser = struct {
42324288 try stack.append(RenderState { .Text = "(" });
42334289 },
42344290 ast.Node.Id.AsmInput => {
4235 const asm_input = @fieldParentPtr(ast.NodeAsmInput, "base", base);
4291 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
42364292
42374293 try stack.append(RenderState { .Text = ")"});
42384294 try stack.append(RenderState { .Expression = asm_input.expr});
42394295 try stack.append(RenderState { .Text = " ("});
42404296 try stack.append(RenderState { .Expression = asm_input.constraint });
42414297 try stack.append(RenderState { .Text = "] "});
4242 try stack.append(RenderState { .Expression = &asm_input.symbolic_name.base});
4298 try stack.append(RenderState { .Expression = asm_input.symbolic_name });
42434299 try stack.append(RenderState { .Text = "["});
42444300 },
42454301 ast.Node.Id.AsmOutput => {
4246 const asm_output = @fieldParentPtr(ast.NodeAsmOutput, "base", base);
4302 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
42474303
42484304 try stack.append(RenderState { .Text = ")"});
42494305 switch (asm_output.kind) {
4250 ast.NodeAsmOutput.Kind.Variable => |variable_name| {
4306 ast.Node.AsmOutput.Kind.Variable => |variable_name| {
42514307 try stack.append(RenderState { .Expression = &variable_name.base});
42524308 },
4253 ast.NodeAsmOutput.Kind.Return => |return_type| {
4309 ast.Node.AsmOutput.Kind.Return => |return_type| {
42544310 try stack.append(RenderState { .Expression = return_type});
42554311 try stack.append(RenderState { .Text = "-> "});
42564312 },
......@@ -4258,7 +4314,7 @@ pub const Parser = struct {
42584314 try stack.append(RenderState { .Text = " ("});
42594315 try stack.append(RenderState { .Expression = asm_output.constraint });
42604316 try stack.append(RenderState { .Text = "] "});
4261 try stack.append(RenderState { .Expression = &asm_output.symbolic_name.base});
4317 try stack.append(RenderState { .Expression = asm_output.symbolic_name });
42624318 try stack.append(RenderState { .Text = "["});
42634319 },
42644320
......@@ -4271,36 +4327,11 @@ pub const Parser = struct {
42714327 ast.Node.Id.TestDecl,
42724328 ast.Node.Id.ParamDecl => unreachable,
42734329 },
4274 RenderState.FnProtoRParen => |fn_proto| {
4275 try stream.print(")");
4276 if (fn_proto.align_expr != null) {
4277 @panic("TODO");
4278 }
4279 try stream.print(" ");
4280 if (fn_proto.body_node) |body_node| {
4281 try stack.append(RenderState { .Expression = body_node});
4282 try stack.append(RenderState { .Text = " "});
4283 }
4284 switch (fn_proto.return_type) {
4285 ast.NodeFnProto.ReturnType.Explicit => |node| {
4286 try stack.append(RenderState { .Expression = node});
4287 },
4288 ast.NodeFnProto.ReturnType.InferErrorSet => |node| {
4289 try stream.print("!");
4290 try stack.append(RenderState { .Expression = node});
4291 },
4292 }
4293 },
42944330 RenderState.Statement => |base| {
4295 if (base.comment) |comment| {
4296 for (comment.lines.toSliceConst()) |line_token| {
4297 try stream.print("{}\n", self.tokenizer.getTokenSlice(line_token));
4298 try stream.writeByteNTimes(' ', indent);
4299 }
4300 }
43014331 switch (base.id) {
43024332 ast.Node.Id.VarDecl => {
4303 const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", base);
4333 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
4334 try self.renderComments(stream, var_decl, indent);
43044335 try stack.append(RenderState { .VarDecl = var_decl});
43054336 },
43064337 else => {
......@@ -4317,6 +4348,14 @@ pub const Parser = struct {
43174348 }
43184349 }
43194350
4351 fn renderComments(self: &Parser, stream: var, node: var, indent: usize) !void {
4352 const comment = node.comments ?? return;
4353 for (comment.lines.toSliceConst()) |line_token| {
4354 try stream.print("{}\n", self.tokenizer.getTokenSlice(line_token));
4355 try stream.writeByteNTimes(' ', indent);
4356 }
4357 }
4358
43204359 fn initUtilityArrayList(self: &Parser, comptime T: type) ArrayList(T) {
43214360 const new_byte_count = self.utility_bytes.len - self.utility_bytes.len % @sizeOf(T);
43224361 self.utility_bytes = self.util_allocator.alignedShrink(u8, utility_bytes_align, self.utility_bytes, new_byte_count);
......@@ -4391,6 +4430,14 @@ fn testCanonical(source: []const u8) !void {
43914430 }
43924431}
43934432
4433test "zig fmt: preserve top level comments" {
4434 try testCanonical(
4435 \\// top level comment
4436 \\test "hi" {}
4437 \\
4438 );
4439}
4440
43944441test "zig fmt: get stdout or fail" {
43954442 try testCanonical(
43964443 \\const std = @import("std");
......@@ -4583,10 +4630,10 @@ test "zig fmt: precedence" {
45834630 \\ (a!b)();
45844631 \\ !a!b;
45854632 \\ !(a!b);
4586 \\ !a{ };
4587 \\ !(a{ });
4588 \\ a + b{ };
4589 \\ (a + b){ };
4633 \\ !a{};
4634 \\ !(a{});
4635 \\ a + b{};
4636 \\ (a + b){};
45904637 \\ a << b + c;
45914638 \\ (a << b) + c;
45924639 \\ a & b << c;
......@@ -4644,12 +4691,20 @@ test "zig fmt: var type" {
46444691 );
46454692}
46464693
4647test "zig fmt: extern function" {
4694test "zig fmt: functions" {
46484695 try testCanonical(
46494696 \\extern fn puts(s: &const u8) c_int;
46504697 \\extern "c" fn puts(s: &const u8) c_int;
46514698 \\export fn puts(s: &const u8) c_int;
46524699 \\inline fn puts(s: &const u8) c_int;
4700 \\pub extern fn puts(s: &const u8) c_int;
4701 \\pub extern "c" fn puts(s: &const u8) c_int;
4702 \\pub export fn puts(s: &const u8) c_int;
4703 \\pub inline fn puts(s: &const u8) c_int;
4704 \\pub extern fn puts(s: &const u8) align(2 + 2) c_int;
4705 \\pub extern "c" fn puts(s: &const u8) align(2 + 2) c_int;
4706 \\pub export fn puts(s: &const u8) align(2 + 2) c_int;
4707 \\pub inline fn puts(s: &const u8) align(2 + 2) c_int;
46534708 \\
46544709 );
46554710}
......@@ -4715,21 +4770,21 @@ test "zig fmt: struct declaration" {
47154770 \\ return *self;
47164771 \\ }
47174772 \\
4718 \\ f2: u8
4773 \\ f2: u8,
47194774 \\};
47204775 \\
47214776 \\const Ps = packed struct {
47224777 \\ a: u8,
47234778 \\ pub b: u8,
47244779 \\
4725 \\ c: u8
4780 \\ c: u8,
47264781 \\};
47274782 \\
47284783 \\const Es = extern struct {
47294784 \\ a: u8,
47304785 \\ pub b: u8,
47314786 \\
4732 \\ c: u8
4787 \\ c: u8,
47334788 \\};
47344789 \\
47354790 );
......@@ -4739,25 +4794,25 @@ test "zig fmt: enum declaration" {
47394794 try testCanonical(
47404795 \\const E = enum {
47414796 \\ Ok,
4742 \\ SomethingElse = 0
4797 \\ SomethingElse = 0,
47434798 \\};
47444799 \\
47454800 \\const E2 = enum(u8) {
47464801 \\ Ok,
47474802 \\ SomethingElse = 255,
4748 \\ SomethingThird
4803 \\ SomethingThird,
47494804 \\};
47504805 \\
47514806 \\const Ee = extern enum {
47524807 \\ Ok,
47534808 \\ SomethingElse,
4754 \\ SomethingThird
4809 \\ SomethingThird,
47554810 \\};
47564811 \\
47574812 \\const Ep = packed enum {
47584813 \\ Ok,
47594814 \\ SomethingElse,
4760 \\ SomethingThird
4815 \\ SomethingThird,
47614816 \\};
47624817 \\
47634818 );
......@@ -4769,35 +4824,35 @@ test "zig fmt: union declaration" {
47694824 \\ Int: u8,
47704825 \\ Float: f32,
47714826 \\ None,
4772 \\ Bool: bool
4827 \\ Bool: bool,
47734828 \\};
47744829 \\
47754830 \\const Ue = union(enum) {
47764831 \\ Int: u8,
47774832 \\ Float: f32,
47784833 \\ None,
4779 \\ Bool: bool
4834 \\ Bool: bool,
47804835 \\};
47814836 \\
47824837 \\const E = enum {
47834838 \\ Int,
47844839 \\ Float,
47854840 \\ None,
4786 \\ Bool
4841 \\ Bool,
47874842 \\};
47884843 \\
47894844 \\const Ue2 = union(E) {
47904845 \\ Int: u8,
47914846 \\ Float: f32,
47924847 \\ None,
4793 \\ Bool: bool
4848 \\ Bool: bool,
47944849 \\};
47954850 \\
47964851 \\const Eu = extern union {
47974852 \\ Int: u8,
47984853 \\ Float: f32,
47994854 \\ None,
4800 \\ Bool: bool
4855 \\ Bool: bool,
48014856 \\};
48024857 \\
48034858 );
......@@ -4809,7 +4864,7 @@ test "zig fmt: error set declaration" {
48094864 \\ A,
48104865 \\ B,
48114866 \\
4812 \\ C
4867 \\ C,
48134868 \\};
48144869 \\
48154870 );
......@@ -4818,9 +4873,15 @@ test "zig fmt: error set declaration" {
48184873test "zig fmt: arrays" {
48194874 try testCanonical(
48204875 \\test "test array" {
4821 \\ const a: [2]u8 = [2]u8{ 1, 2 };
4822 \\ const a: [2]u8 = []u8{ 1, 2 };
4823 \\ const a: [0]u8 = []u8{ };
4876 \\ const a: [2]u8 = [2]u8 {
4877 \\ 1,
4878 \\ 2,
4879 \\ };
4880 \\ const a: [2]u8 = []u8 {
4881 \\ 1,
4882 \\ 2,
4883 \\ };
4884 \\ const a: [0]u8 = []u8{};
48244885 \\}
48254886 \\
48264887 );
......@@ -4828,10 +4889,18 @@ test "zig fmt: arrays" {
48284889
48294890test "zig fmt: container initializers" {
48304891 try testCanonical(
4831 \\const a1 = []u8{ };
4832 \\const a2 = []u8{ 1, 2, 3, 4 };
4833 \\const s1 = S{ };
4834 \\const s2 = S{ .a = 1, .b = 2 };
4892 \\const a1 = []u8{};
4893 \\const a2 = []u8 {
4894 \\ 1,
4895 \\ 2,
4896 \\ 3,
4897 \\ 4,
4898 \\};
4899 \\const s1 = S{};
4900 \\const s2 = S {
4901 \\ .a = 1,
4902 \\ .b = 2,
4903 \\};
48354904 \\
48364905 );
48374906}
......@@ -4875,31 +4944,34 @@ test "zig fmt: switch" {
48754944 \\ switch (0) {
48764945 \\ 0 => {},
48774946 \\ 1 => unreachable,
4878 \\ 2, 3 => {},
4947 \\ 2,
4948 \\ 3 => {},
48794949 \\ 4 ... 7 => {},
48804950 \\ 1 + 4 * 3 + 22 => {},
48814951 \\ else => {
48824952 \\ const a = 1;
48834953 \\ const b = a;
4884 \\ }
4954 \\ },
48854955 \\ }
48864956 \\
48874957 \\ const res = switch (0) {
48884958 \\ 0 => 0,
48894959 \\ 1 => 2,
48904960 \\ 1 => a = 4,
4891 \\ else => 4
4961 \\ else => 4,
48924962 \\ };
48934963 \\
48944964 \\ const Union = union(enum) {
48954965 \\ Int: i64,
4896 \\ Float: f64
4966 \\ Float: f64,
48974967 \\ };
48984968 \\
4899 \\ const u = Union{ .Int = 0 };
4969 \\ const u = Union {
4970 \\ .Int = 0,
4971 \\ };
49004972 \\ switch (u) {
49014973 \\ Union.Int => |int| {},
4902 \\ Union.Float => |*float| unreachable
4974 \\ Union.Float => |*float| unreachable,
49034975 \\ }
49044976 \\}
49054977 \\
......@@ -4975,7 +5047,11 @@ test "zig fmt: while" {
49755047test "zig fmt: for" {
49765048 try testCanonical(
49775049 \\test "for" {
4978 \\ const a = []u8{ 1, 2, 3 };
5050 \\ const a = []u8 {
5051 \\ 1,
5052 \\ 2,
5053 \\ 3,
5054 \\ };
49795055 \\ for (a) |v| {
49805056 \\ continue;
49815057 \\ }
......@@ -5205,3 +5281,12 @@ test "zig fmt: error return" {
52055281 \\
52065282 );
52075283}
5284
5285test "zig fmt: struct literals with fields on each line" {
5286 try testCanonical(
5287 \\var self = BufSet {
5288 \\ .hash_map = BufSetHashMap.init(a),
5289 \\};
5290 \\
5291 );
5292}
test/behavior.zig+1
......@@ -12,6 +12,7 @@ comptime {
1212 _ = @import("cases/bugs/655.zig");
1313 _ = @import("cases/bugs/656.zig");
1414 _ = @import("cases/bugs/828.zig");
15 _ = @import("cases/bugs/920.zig");
1516 _ = @import("cases/cast.zig");
1617 _ = @import("cases/const_slice_child.zig");
1718 _ = @import("cases/coroutines.zig");
test/cases/atomics.zig+47-3
......@@ -1,12 +1,24 @@
1const assert = @import("std").debug.assert;
1const std = @import("std");
2const assert = std.debug.assert;
23const builtin = @import("builtin");
34const AtomicRmwOp = builtin.AtomicRmwOp;
45const AtomicOrder = builtin.AtomicOrder;
56
67test "cmpxchg" {
78 var x: i32 = 1234;
8 while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {}
9 if (@cmpxchgWeak(i32, &x, 99, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
10 assert(x1 == 1234);
11 } else {
12 @panic("cmpxchg should have failed");
13 }
14
15 while (@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
16 assert(x1 == 1234);
17 }
918 assert(x == 5678);
19
20 assert(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
21 assert(x == 42);
1022}
1123
1224test "fence" {
......@@ -15,13 +27,45 @@ test "fence" {
1527 x = 5678;
1628}
1729
18test "atomicrmw" {
30test "atomicrmw and atomicload" {
1931 var data: u8 = 200;
2032 testAtomicRmw(&data);
2133 assert(data == 42);
34 testAtomicLoad(&data);
2235}
2336
2437fn testAtomicRmw(ptr: &u8) void {
2538 const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst);
2639 assert(prev_value == 200);
40 comptime {
41 var x: i32 = 1234;
42 const y: i32 = 12345;
43 assert(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234);
44 assert(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345);
45 }
46}
47
48fn testAtomicLoad(ptr: &u8) void {
49 const x = @atomicLoad(u8, ptr, AtomicOrder.SeqCst);
50 assert(x == 42);
51}
52
53test "cmpxchg with ptr" {
54 var data1: i32 = 1234;
55 var data2: i32 = 5678;
56 var data3: i32 = 9101;
57 var x: &i32 = &data1;
58 if (@cmpxchgWeak(&i32, &x, &data2, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
59 assert(x1 == &data1);
60 } else {
61 @panic("cmpxchg should have failed");
62 }
63
64 while (@cmpxchgWeak(&i32, &x, &data1, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
65 assert(x1 == &data1);
66 }
67 assert(x == &data3);
68
69 assert(@cmpxchgStrong(&i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
70 assert(x == &data2);
2771}
test/cases/bugs/920.zig created+60
......@@ -0,0 +1,60 @@
1const std = @import("std");
2const math = std.math;
3const Random = std.rand.Random;
4
5const ZigTable = struct {
6 r: f64,
7 x: [257]f64,
8 f: [257]f64,
9
10 pdf: fn(f64) f64,
11 is_symmetric: bool,
12 zero_case: fn(&Random, f64) f64,
13};
14
15fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, comptime f: fn(f64) f64,
16 comptime f_inv: fn(f64) f64, comptime zero_case: fn(&Random, f64) f64) ZigTable {
17 var tables: ZigTable = undefined;
18
19 tables.is_symmetric = is_symmetric;
20 tables.r = r;
21 tables.pdf = f;
22 tables.zero_case = zero_case;
23
24 tables.x[0] = v / f(r);
25 tables.x[1] = r;
26
27 for (tables.x[2..256]) |*entry, i| {
28 const last = tables.x[2 + i - 1];
29 *entry = f_inv(v / last + f(last));
30 }
31 tables.x[256] = 0;
32
33 for (tables.f[0..]) |*entry, i| {
34 *entry = f(tables.x[i]);
35 }
36
37 return tables;
38}
39
40const norm_r = 3.6541528853610088;
41const norm_v = 0.00492867323399;
42
43fn norm_f(x: f64) f64 { return math.exp(-x * x / 2.0); }
44fn norm_f_inv(y: f64) f64 { return math.sqrt(-2.0 * math.ln(y)); }
45fn norm_zero_case(random: &Random, u: f64) f64 { return 0.0; }
46
47const NormalDist = blk: {
48 @setEvalBranchQuota(30000);
49 break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case);
50};
51
52test "bug 920 fixed" {
53 const NormalDist1 = blk: {
54 break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case);
55 };
56
57 for (NormalDist1.f) |_, i| {
58 std.debug.assert(NormalDist1.f[i] == NormalDist.f[i]);
59 }
60}
test/cases/coroutines.zig+18
......@@ -224,3 +224,21 @@ async fn printTrace(p: promise->error!void) void {
224224 }
225225 };
226226}
227
228test "break from suspend" {
229 var buf: [500]u8 = undefined;
230 var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
231 var my_result: i32 = 1;
232 const p = try async<a> testBreakFromSuspend(&my_result);
233 cancel p;
234 std.debug.assert(my_result == 2);
235}
236
237async fn testBreakFromSuspend(my_result: &i32) void {
238 s: suspend |p| {
239 break :s;
240 }
241 *my_result += 1;
242 suspend;
243 *my_result += 1;
244}
test/cases/defer.zig+11
......@@ -41,3 +41,14 @@ fn testBreakContInDefer(x: usize) void {
4141 assert(i == 5);
4242 }
4343}
44
45test "defer and labeled break" {
46 var i = usize(0);
47
48 blk: {
49 defer i += 1;
50 break :blk;
51 }
52
53 assert(i == 1);
54}
test/cases/eval.zig+16
......@@ -513,3 +513,19 @@ test "array concat of slices gives slice" {
513513 assert(std.mem.eql(u8, c, "aoeuasdf"));
514514 }
515515}
516
517test "comptime shlWithOverflow" {
518 const ct_shifted: u64 = comptime amt: {
519 var amt = u64(0);
520 _ = @shlWithOverflow(u64, ~u64(0), 16, &amt);
521 break :amt amt;
522 };
523
524 const rt_shifted: u64 = amt: {
525 var amt = u64(0);
526 _ = @shlWithOverflow(u64, ~u64(0), 16, &amt);
527 break :amt amt;
528 };
529
530 assert(ct_shifted == rt_shifted);
531}
test/cases/fn.zig+7
......@@ -104,3 +104,10 @@ test "number literal as an argument" {
104104fn numberLiteralArg(a: var) void {
105105 assert(a == 3);
106106}
107
108test "assign inline fn to const variable" {
109 const a = inlineFn;
110 a();
111}
112
113inline fn inlineFn() void { }
test/cases/math.zig+16
......@@ -402,3 +402,19 @@ test "comptime float rem int" {
402402 assert(x == 1.0);
403403 }
404404}
405
406test "@sqrt" {
407 testSqrt(f64, 12.0);
408 comptime testSqrt(f64, 12.0);
409 testSqrt(f32, 13.0);
410 comptime testSqrt(f32, 13.0);
411
412 const x = 14.0;
413 const y = x * x;
414 const z = @sqrt(@typeOf(y), y);
415 comptime assert(z == x);
416}
417
418fn testSqrt(comptime T: type, x: T) void {
419 assert(@sqrt(T, x * x) == x);
420}
test/cases/reflection.zig+24
......@@ -1,5 +1,6 @@
11const assert = @import("std").debug.assert;
22const mem = @import("std").mem;
3const reflection = this;
34
45test "reflection: array, pointer, nullable, error union type child" {
56 comptime {
......@@ -56,7 +57,30 @@ test "reflection: enum member types and names" {
5657
5758}
5859
60test "reflection: @field" {
61 var f = Foo {
62 .one = 42,
63 .two = true,
64 .three = void{},
65 };
66
67 assert(f.one == f.one);
68 assert(@field(f, "o" ++ "ne") == f.one);
69 assert(@field(f, "t" ++ "wo") == f.two);
70 assert(@field(f, "th" ++ "ree") == f.three);
71 assert(@field(Foo, "const" ++ "ant") == Foo.constant);
72 assert(@field(Bar, "O" ++ "ne") == Bar.One);
73 assert(@field(Bar, "T" ++ "wo") == Bar.Two);
74 assert(@field(Bar, "Th" ++ "ree") == Bar.Three);
75 assert(@field(Bar, "F" ++ "our") == Bar.Four);
76 assert(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2));
77 @field(f, "o" ++ "ne") = 4;
78 assert(f.one == 4);
79}
80
5981const Foo = struct {
82 const constant = 52;
83
6084 one: i32,
6185 two: bool,
6286 three: void,
test/compile_errors.zig+57-8
......@@ -1,6 +1,55 @@
11const tests = @import("tests.zig");
22
33pub fn addCases(cases: &tests.CompileErrorContext) void {
4 cases.add("invalid deref on switch target",
5 \\comptime {
6 \\ var tile = Tile.Empty;
7 \\ switch (*tile) {
8 \\ Tile.Empty => {},
9 \\ Tile.Filled => {},
10 \\ }
11 \\}
12 \\const Tile = enum {
13 \\ Empty,
14 \\ Filled,
15 \\};
16 ,
17 ".tmp_source.zig:3:13: error: invalid deref on switch target");
18
19 cases.add("invalid field access in comptime",
20 \\comptime { var x = doesnt_exist.whatever; }
21 ,
22 ".tmp_source.zig:1:20: error: use of undeclared identifier 'doesnt_exist'");
23
24 cases.add("suspend inside suspend block",
25 \\const std = @import("std");
26 \\
27 \\export fn entry() void {
28 \\ var buf: [500]u8 = undefined;
29 \\ var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
30 \\ const p = (async<a> foo()) catch unreachable;
31 \\ cancel p;
32 \\}
33 \\
34 \\async fn foo() void {
35 \\ suspend |p| {
36 \\ suspend |p1| {
37 \\ }
38 \\ }
39 \\}
40 ,
41 ".tmp_source.zig:12:9: error: cannot suspend inside suspend block",
42 ".tmp_source.zig:11:5: note: other suspend block here");
43
44 cases.add("assign inline fn to non-comptime var",
45 \\export fn entry() void {
46 \\ var a = b;
47 \\}
48 \\inline fn b() void { }
49 ,
50 ".tmp_source.zig:2:5: error: functions marked inline must be stored in const or comptime var",
51 ".tmp_source.zig:4:8: note: declared here");
52
453 cases.add("wrong type passed to @panic",
554 \\export fn entry() void {
655 \\ var e = error.Foo;
......@@ -1385,17 +1434,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
13851434 \\const AtomicOrder = @import("builtin").AtomicOrder;
13861435 \\export fn f() void {
13871436 \\ var x: i32 = 1234;
1388 \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {}
1437 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {}
13891438 \\}
1390 , ".tmp_source.zig:4:72: error: failure atomic ordering must be no stricter than success");
1439 , ".tmp_source.zig:4:81: error: failure atomic ordering must be no stricter than success");
13911440
13921441 cases.add("atomic orderings of cmpxchg - success Monotonic or stricter",
13931442 \\const AtomicOrder = @import("builtin").AtomicOrder;
13941443 \\export fn f() void {
13951444 \\ var x: i32 = 1234;
1396 \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {}
1445 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {}
13971446 \\}
1398 , ".tmp_source.zig:4:49: error: success atomic ordering must be Monotonic or stricter");
1447 , ".tmp_source.zig:4:58: error: success atomic ordering must be Monotonic or stricter");
13991448
14001449 cases.add("negation overflow in function evaluation",
14011450 \\const y = neg(-128);
......@@ -2451,11 +2500,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
24512500 \\const AtomicOrder = @import("builtin").AtomicOrder;
24522501 \\export fn entry() bool {
24532502 \\ var x: i32 align(1) = 1234;
2454 \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {}
2503 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {}
24552504 \\ return x == 5678;
24562505 \\}
24572506 ,
2458 ".tmp_source.zig:4:23: error: expected pointer alignment of at least 4, found 1");
2507 ".tmp_source.zig:4:32: error: expected type '&i32', found '&align(1) i32'");
24592508
24602509 cases.add("wrong size to an array literal",
24612510 \\comptime {
......@@ -2525,10 +2574,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
25252574 cases.add("wrong types given to atomic order args in cmpxchg",
25262575 \\export fn entry() void {
25272576 \\ var x: i32 = 1234;
2528 \\ while (!@cmpxchg(&x, 1234, 5678, u32(1234), u32(1234))) {}
2577 \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, u32(1234), u32(1234))) {}
25292578 \\}
25302579 ,
2531 ".tmp_source.zig:3:41: error: expected type 'AtomicOrder', found 'u32'");
2580 ".tmp_source.zig:3:50: error: expected type 'AtomicOrder', found 'u32'");
25322581
25332582 cases.add("wrong types given to @export",
25342583 \\extern fn entry() void { }
test/tests.zig+1
......@@ -583,6 +583,7 @@ pub const CompileErrorContext = struct {
583583 Mode.Debug => {},
584584 Mode.ReleaseSafe => zig_args.append("--release-safe") catch unreachable,
585585 Mode.ReleaseFast => zig_args.append("--release-fast") catch unreachable,
586 Mode.ReleaseSmall => zig_args.append("--release-small") catch unreachable,
586587 }
587588
588589 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);