authorgravatar for andrea@orru.ioAndrea Orru <andrea@orru.io> 2018-04-13 11:11:21-07:00
committergravatar for andrea@orru.ioAndrea Orru <andrea@orru.io> 2018-04-13 11:11:21-07:00
log06614b3fa09954464c2e2f32756cacedc178a282
tree37cd43b61b1c8be543551ef7e9f6605bce847947
parentd2c672ab0cc969f97e30cf6a12e4bffcac7cee18
parentfa05cab01a755827209b6ede299402f515681a81

Merge branch 'master' into zen_stdlib


19 files changed, 4071 insertions(+), 3217 deletions(-)

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)
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/codegen.cpp+1-1
......@@ -467,7 +467,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
467467 fn_table_entry->llvm_value, buf_ptr(&fn_export->name));
468468 }
469469 }
470 fn_table_entry->llvm_name = LLVMGetValueName(fn_table_entry->llvm_value);
470 fn_table_entry->llvm_name = strdup(LLVMGetValueName(fn_table_entry->llvm_value));
471471
472472 switch (fn_table_entry->fn_inline) {
473473 case FnInlineAlways:
src/ir.cpp+21-2
......@@ -11395,7 +11395,19 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
1139511395 }
1139611396 break;
1139711397 case VarClassRequiredAny:
11398 // OK
11398 if (casted_init_value->value.special == ConstValSpecialStatic &&
11399 casted_init_value->value.type->id == TypeTableEntryIdFn &&
11400 casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways)
11401 {
11402 var_class_requires_const = true;
11403 if (!var->src_is_const && !is_comptime_var) {
11404 ErrorMsg *msg = ir_add_error_node(ira, source_node,
11405 buf_sprintf("functions marked inline must be stored in const or comptime var"));
11406 AstNode *proto_node = casted_init_value->value.data.x_ptr.data.fn.fn_entry->proto_node;
11407 add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here"));
11408 result_type = ira->codegen->builtin_types.entry_invalid;
11409 }
11410 }
1139911411 break;
1140011412 }
1140111413 }
......@@ -11804,7 +11816,8 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
1180411816 }
1180511817 }
1180611818
11807 bool comptime_arg = param_decl_node->data.param_decl.is_inline;
11819 bool comptime_arg = param_decl_node->data.param_decl.is_inline ||
11820 casted_arg->value.type->id == TypeTableEntryIdNumLitInt || casted_arg->value.type->id == TypeTableEntryIdNumLitFloat;
1180811821
1180911822 ConstExprValue *arg_val;
1181011823
......@@ -11829,6 +11842,12 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
1182911842 var->shadowable = !comptime_arg;
1183011843
1183111844 *next_proto_i += 1;
11845 } else if (casted_arg->value.type->id == TypeTableEntryIdNumLitInt ||
11846 casted_arg->value.type->id == TypeTableEntryIdNumLitFloat)
11847 {
11848 ir_add_error(ira, casted_arg,
11849 buf_sprintf("compiler bug: integer and float literals in var args function must be casted. https://github.com/zig-lang/zig/issues/557"));
11850 return false;
1183211851 }
1183311852
1183411853 if (!comptime_arg) {
src/main.cpp+8-25
......@@ -54,7 +54,6 @@ static int usage(const char *arg0) {
5454 " --verbose-ir turn on compiler debug output for Zig IR\n"
5555 " --verbose-llvm-ir turn on compiler debug output for LLVM IR\n"
5656 " --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"
5857 " -dirafter [dir] same as -isystem but do it last\n"
5958 " -isystem [dir] add additional search path for other .h files\n"
6059 " -mllvm [arg] additional arguments to forward to LLVM's option processing\n"
......@@ -177,6 +176,7 @@ static int find_zig_lib_dir(Buf *out_path) {
177176 int err;
178177
179178 Buf self_exe_path = BUF_INIT;
179 buf_resize(&self_exe_path, 0);
180180 if (!(err = os_self_exe_path(&self_exe_path))) {
181181 Buf *cur_path = &self_exe_path;
182182
......@@ -199,23 +199,14 @@ static int find_zig_lib_dir(Buf *out_path) {
199199 return ErrorFileNotFound;
200200}
201201
202static Buf *resolve_zig_lib_dir(const char *zig_install_prefix_arg) {
202static Buf *resolve_zig_lib_dir(void) {
203203 int err;
204204 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;
205 if ((err = find_zig_lib_dir(result))) {
206 fprintf(stderr, "Unable to find zig lib directory\n");
207 exit(EXIT_FAILURE);
215208 }
216
217 fprintf(stderr, "No Zig installation found at prefix: %s\n", zig_install_prefix_arg);
218 exit(EXIT_FAILURE);
209 return result;
219210}
220211
221212enum Cmd {
......@@ -299,7 +290,6 @@ int main(int argc, char **argv) {
299290 const char *libc_include_dir = nullptr;
300291 const char *msvc_lib_dir = nullptr;
301292 const char *kernel32_lib_dir = nullptr;
302 const char *zig_install_prefix = nullptr;
303293 const char *dynamic_linker = nullptr;
304294 ZigList<const char *> clang_argv = {0};
305295 ZigList<const char *> llvm_argv = {0};
......@@ -359,17 +349,12 @@ int main(int argc, char **argv) {
359349 } else if (i + 1 < argc && strcmp(argv[i], "--cache-dir") == 0) {
360350 cache_dir = argv[i + 1];
361351 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);
367352 } else {
368353 args.append(argv[i]);
369354 }
370355 }
371356
372 Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);
357 Buf *zig_lib_dir_buf = resolve_zig_lib_dir();
373358
374359 Buf *zig_std_dir = buf_alloc();
375360 os_path_join(zig_lib_dir_buf, buf_create_from_str("std"), zig_std_dir);
......@@ -590,8 +575,6 @@ int main(int argc, char **argv) {
590575 msvc_lib_dir = argv[i];
591576 } else if (strcmp(arg, "--kernel32-lib-dir") == 0) {
592577 kernel32_lib_dir = argv[i];
593 } else if (strcmp(arg, "--zig-install-prefix") == 0) {
594 zig_install_prefix = argv[i];
595578 } else if (strcmp(arg, "--dynamic-linker") == 0) {
596579 dynamic_linker = argv[i];
597580 } else if (strcmp(arg, "-isystem") == 0) {
......@@ -803,7 +786,7 @@ int main(int argc, char **argv) {
803786 full_cache_dir);
804787 }
805788
806 Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);
789 Buf *zig_lib_dir_buf = resolve_zig_lib_dir();
807790
808791 CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, zig_lib_dir_buf);
809792 codegen_set_out_name(g, buf_out_name);
std/c/index.zig+1
......@@ -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;
std/os/darwin.zig+9
......@@ -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)));
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/linux/index.zig+9
......@@ -38,6 +38,11 @@ pub const MAP_STACK = 0x20000;
3838pub const MAP_HUGETLB = 0x40000;
3939pub const MAP_FILE = 0;
4040
41pub const F_OK = 0;
42pub const X_OK = 1;
43pub const W_OK = 2;
44pub const R_OK = 4;
45
4146pub const WNOHANG = 1;
4247pub const WUNTRACED = 2;
4348pub const WSTOPPED = 2;
......@@ -705,6 +710,10 @@ pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) usize {
705710 return syscall4(SYS_pread, usize(fd), @ptrToInt(buf), count, offset);
706711}
707712
713pub fn access(path: &const u8, mode: u32) usize {
714 return syscall2(SYS_access, @ptrToInt(path), mode);
715}
716
708717pub fn pipe(fd: &[2]i32) usize {
709718 return pipe2(fd, 0);
710719}
std/os/test.zig+17
......@@ -23,3 +23,20 @@ test "makePath, put some files in it, deleteTree" {
2323 assert(err == error.PathNotFound);
2424 }
2525}
26
27test "access file" {
28 if (builtin.os == builtin.Os.windows) {
29 return;
30 }
31
32 try os.makePath(a, "os_test_tmp");
33 if (os.File.access(a, "os_test_tmp/file.txt", os.default_file_mode)) |ok| {
34 unreachable;
35 } else |err| {
36 assert(err == error.NotFound);
37 }
38
39 try io.writeFile(a, "os_test_tmp/file.txt", "");
40 assert((try os.File.access(a, "os_test_tmp/file.txt", os.default_file_mode)) == true);
41 try os.deleteTree(a, "os_test_tmp");
42}
std/os/windows/index.zig+2
......@@ -78,6 +78,8 @@ pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem
7878pub extern "kernel32" stdcallcc fn MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR,
7979 dwFlags: DWORD) BOOL;
8080
81pub extern "kernel32" stdcallcc fn PathFileExists(pszPath: ?LPCTSTR) BOOL;
82
8183pub extern "kernel32" stdcallcc fn ReadFile(in_hFile: HANDLE, out_lpBuffer: &c_void,
8284 in_nNumberOfBytesToRead: DWORD, out_lpNumberOfBytesRead: &DWORD,
8385 in_out_lpOverlapped: ?&OVERLAPPED) BOOL;
std/zig/ast.zig+215-240
......@@ -9,38 +9,34 @@ pub const Node = struct {
99 comment: ?&NodeLineComment,
1010
1111 pub const Id = enum {
12 // Top level
1213 Root,
13 VarDecl,
1414 Use,
15 ErrorSetDecl,
16 ContainerDecl,
17 StructField,
18 UnionTag,
19 EnumTag,
20 Identifier,
21 AsyncAttribute,
22 FnProto,
23 ParamDecl,
24 Block,
15 TestDecl,
16
17 // Statements
18 VarDecl,
2519 Defer,
26 Comptime,
27 Payload,
28 PointerPayload,
29 PointerIndexPayload,
30 Else,
20
21 // Operators
22 InfixOp,
23 PrefixOp,
24 SuffixOp,
25
26 // Control flow
3127 Switch,
32 SwitchCase,
33 SwitchElse,
3428 While,
3529 For,
3630 If,
37 InfixOp,
38 PrefixOp,
39 SuffixOp,
40 GroupedExpression,
4131 ControlFlowExpression,
4232 Suspend,
43 FieldInitializer,
33
34 // Type expressions
35 VarType,
36 ErrorType,
37 FnProto,
38
39 // Primary expressions
4440 IntegerLiteral,
4541 FloatLiteral,
4642 StringLiteral,
......@@ -50,180 +46,143 @@ pub const Node = struct {
5046 NullLiteral,
5147 UndefinedLiteral,
5248 ThisLiteral,
53 Asm,
54 AsmInput,
55 AsmOutput,
5649 Unreachable,
57 ErrorType,
58 VarType,
50 Identifier,
51 GroupedExpression,
5952 BuiltinCall,
53 ErrorSetDecl,
54 ContainerDecl,
55 Asm,
56 Comptime,
57 Block,
58
59 // Misc
6060 LineComment,
61 TestDecl,
61 SwitchCase,
62 SwitchElse,
63 Else,
64 Payload,
65 PointerPayload,
66 PointerIndexPayload,
67 StructField,
68 UnionTag,
69 EnumTag,
70 AsmInput,
71 AsmOutput,
72 AsyncAttribute,
73 ParamDecl,
74 FieldInitializer,
75 };
76
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 },
62141 };
63142
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
64161 pub fn iterate(base: &Node, index: usize) ?&Node {
65 return switch (base.id) {
66 Id.Root => @fieldParentPtr(NodeRoot, "base", base).iterate(index),
67 Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).iterate(index),
68 Id.Use => @fieldParentPtr(NodeUse, "base", base).iterate(index),
69 Id.ErrorSetDecl => @fieldParentPtr(NodeErrorSetDecl, "base", base).iterate(index),
70 Id.ContainerDecl => @fieldParentPtr(NodeContainerDecl, "base", base).iterate(index),
71 Id.StructField => @fieldParentPtr(NodeStructField, "base", base).iterate(index),
72 Id.UnionTag => @fieldParentPtr(NodeUnionTag, "base", base).iterate(index),
73 Id.EnumTag => @fieldParentPtr(NodeEnumTag, "base", base).iterate(index),
74 Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).iterate(index),
75 Id.AsyncAttribute => @fieldParentPtr(NodeAsyncAttribute, "base", base).iterate(index),
76 Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).iterate(index),
77 Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).iterate(index),
78 Id.Block => @fieldParentPtr(NodeBlock, "base", base).iterate(index),
79 Id.Defer => @fieldParentPtr(NodeDefer, "base", base).iterate(index),
80 Id.Comptime => @fieldParentPtr(NodeComptime, "base", base).iterate(index),
81 Id.Payload => @fieldParentPtr(NodePayload, "base", base).iterate(index),
82 Id.PointerPayload => @fieldParentPtr(NodePointerPayload, "base", base).iterate(index),
83 Id.PointerIndexPayload => @fieldParentPtr(NodePointerIndexPayload, "base", base).iterate(index),
84 Id.Else => @fieldParentPtr(NodeSwitch, "base", base).iterate(index),
85 Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).iterate(index),
86 Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).iterate(index),
87 Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).iterate(index),
88 Id.While => @fieldParentPtr(NodeWhile, "base", base).iterate(index),
89 Id.For => @fieldParentPtr(NodeFor, "base", base).iterate(index),
90 Id.If => @fieldParentPtr(NodeIf, "base", base).iterate(index),
91 Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).iterate(index),
92 Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).iterate(index),
93 Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).iterate(index),
94 Id.GroupedExpression => @fieldParentPtr(NodeGroupedExpression, "base", base).iterate(index),
95 Id.ControlFlowExpression => @fieldParentPtr(NodeControlFlowExpression, "base", base).iterate(index),
96 Id.Suspend => @fieldParentPtr(NodeSuspend, "base", base).iterate(index),
97 Id.FieldInitializer => @fieldParentPtr(NodeFieldInitializer, "base", base).iterate(index),
98 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).iterate(index),
99 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).iterate(index),
100 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).iterate(index),
101 Id.MultilineStringLiteral => @fieldParentPtr(NodeMultilineStringLiteral, "base", base).iterate(index),
102 Id.CharLiteral => @fieldParentPtr(NodeCharLiteral, "base", base).iterate(index),
103 Id.BoolLiteral => @fieldParentPtr(NodeBoolLiteral, "base", base).iterate(index),
104 Id.NullLiteral => @fieldParentPtr(NodeNullLiteral, "base", base).iterate(index),
105 Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).iterate(index),
106 Id.ThisLiteral => @fieldParentPtr(NodeThisLiteral, "base", base).iterate(index),
107 Id.Asm => @fieldParentPtr(NodeAsm, "base", base).iterate(index),
108 Id.AsmInput => @fieldParentPtr(NodeAsmInput, "base", base).iterate(index),
109 Id.AsmOutput => @fieldParentPtr(NodeAsmOutput, "base", base).iterate(index),
110 Id.Unreachable => @fieldParentPtr(NodeUnreachable, "base", base).iterate(index),
111 Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).iterate(index),
112 Id.VarType => @fieldParentPtr(NodeVarType, "base", base).iterate(index),
113 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).iterate(index),
114 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).iterate(index),
115 Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).iterate(index),
116 };
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);
165 }
166
167 unreachable;
117168 }
118169
119170 pub fn firstToken(base: &Node) Token {
120 return switch (base.id) {
121 Id.Root => @fieldParentPtr(NodeRoot, "base", base).firstToken(),
122 Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).firstToken(),
123 Id.Use => @fieldParentPtr(NodeUse, "base", base).firstToken(),
124 Id.ErrorSetDecl => @fieldParentPtr(NodeErrorSetDecl, "base", base).firstToken(),
125 Id.ContainerDecl => @fieldParentPtr(NodeContainerDecl, "base", base).firstToken(),
126 Id.StructField => @fieldParentPtr(NodeStructField, "base", base).firstToken(),
127 Id.UnionTag => @fieldParentPtr(NodeUnionTag, "base", base).firstToken(),
128 Id.EnumTag => @fieldParentPtr(NodeEnumTag, "base", base).firstToken(),
129 Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).firstToken(),
130 Id.AsyncAttribute => @fieldParentPtr(NodeAsyncAttribute, "base", base).firstToken(),
131 Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).firstToken(),
132 Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).firstToken(),
133 Id.Block => @fieldParentPtr(NodeBlock, "base", base).firstToken(),
134 Id.Defer => @fieldParentPtr(NodeDefer, "base", base).firstToken(),
135 Id.Comptime => @fieldParentPtr(NodeComptime, "base", base).firstToken(),
136 Id.Payload => @fieldParentPtr(NodePayload, "base", base).firstToken(),
137 Id.PointerPayload => @fieldParentPtr(NodePointerPayload, "base", base).firstToken(),
138 Id.PointerIndexPayload => @fieldParentPtr(NodePointerIndexPayload, "base", base).firstToken(),
139 Id.Else => @fieldParentPtr(NodeSwitch, "base", base).firstToken(),
140 Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).firstToken(),
141 Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).firstToken(),
142 Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).firstToken(),
143 Id.While => @fieldParentPtr(NodeWhile, "base", base).firstToken(),
144 Id.For => @fieldParentPtr(NodeFor, "base", base).firstToken(),
145 Id.If => @fieldParentPtr(NodeIf, "base", base).firstToken(),
146 Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).firstToken(),
147 Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).firstToken(),
148 Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).firstToken(),
149 Id.GroupedExpression => @fieldParentPtr(NodeGroupedExpression, "base", base).firstToken(),
150 Id.ControlFlowExpression => @fieldParentPtr(NodeControlFlowExpression, "base", base).firstToken(),
151 Id.Suspend => @fieldParentPtr(NodeSuspend, "base", base).firstToken(),
152 Id.FieldInitializer => @fieldParentPtr(NodeFieldInitializer, "base", base).firstToken(),
153 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).firstToken(),
154 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).firstToken(),
155 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).firstToken(),
156 Id.MultilineStringLiteral => @fieldParentPtr(NodeMultilineStringLiteral, "base", base).firstToken(),
157 Id.CharLiteral => @fieldParentPtr(NodeCharLiteral, "base", base).firstToken(),
158 Id.BoolLiteral => @fieldParentPtr(NodeBoolLiteral, "base", base).firstToken(),
159 Id.NullLiteral => @fieldParentPtr(NodeNullLiteral, "base", base).firstToken(),
160 Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).firstToken(),
161 Id.Unreachable => @fieldParentPtr(NodeUnreachable, "base", base).firstToken(),
162 Id.ThisLiteral => @fieldParentPtr(NodeThisLiteral, "base", base).firstToken(),
163 Id.Asm => @fieldParentPtr(NodeAsm, "base", base).firstToken(),
164 Id.AsmInput => @fieldParentPtr(NodeAsmInput, "base", base).firstToken(),
165 Id.AsmOutput => @fieldParentPtr(NodeAsmOutput, "base", base).firstToken(),
166 Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).firstToken(),
167 Id.VarType => @fieldParentPtr(NodeVarType, "base", base).firstToken(),
168 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).firstToken(),
169 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).firstToken(),
170 Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).firstToken(),
171 };
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();
174 }
175
176 unreachable;
172177 }
173178
174179 pub fn lastToken(base: &Node) Token {
175 return switch (base.id) {
176 Id.Root => @fieldParentPtr(NodeRoot, "base", base).lastToken(),
177 Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).lastToken(),
178 Id.Use => @fieldParentPtr(NodeUse, "base", base).lastToken(),
179 Id.ErrorSetDecl => @fieldParentPtr(NodeErrorSetDecl, "base", base).lastToken(),
180 Id.ContainerDecl => @fieldParentPtr(NodeContainerDecl, "base", base).lastToken(),
181 Id.StructField => @fieldParentPtr(NodeStructField, "base", base).lastToken(),
182 Id.UnionTag => @fieldParentPtr(NodeUnionTag, "base", base).lastToken(),
183 Id.EnumTag => @fieldParentPtr(NodeEnumTag, "base", base).lastToken(),
184 Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).lastToken(),
185 Id.AsyncAttribute => @fieldParentPtr(NodeAsyncAttribute, "base", base).lastToken(),
186 Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).lastToken(),
187 Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).lastToken(),
188 Id.Block => @fieldParentPtr(NodeBlock, "base", base).lastToken(),
189 Id.Defer => @fieldParentPtr(NodeDefer, "base", base).lastToken(),
190 Id.Comptime => @fieldParentPtr(NodeComptime, "base", base).lastToken(),
191 Id.Payload => @fieldParentPtr(NodePayload, "base", base).lastToken(),
192 Id.PointerPayload => @fieldParentPtr(NodePointerPayload, "base", base).lastToken(),
193 Id.PointerIndexPayload => @fieldParentPtr(NodePointerIndexPayload, "base", base).lastToken(),
194 Id.Else => @fieldParentPtr(NodeElse, "base", base).lastToken(),
195 Id.Switch => @fieldParentPtr(NodeSwitch, "base", base).lastToken(),
196 Id.SwitchCase => @fieldParentPtr(NodeSwitchCase, "base", base).lastToken(),
197 Id.SwitchElse => @fieldParentPtr(NodeSwitchElse, "base", base).lastToken(),
198 Id.While => @fieldParentPtr(NodeWhile, "base", base).lastToken(),
199 Id.For => @fieldParentPtr(NodeFor, "base", base).lastToken(),
200 Id.If => @fieldParentPtr(NodeIf, "base", base).lastToken(),
201 Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).lastToken(),
202 Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).lastToken(),
203 Id.SuffixOp => @fieldParentPtr(NodeSuffixOp, "base", base).lastToken(),
204 Id.GroupedExpression => @fieldParentPtr(NodeGroupedExpression, "base", base).lastToken(),
205 Id.ControlFlowExpression => @fieldParentPtr(NodeControlFlowExpression, "base", base).lastToken(),
206 Id.Suspend => @fieldParentPtr(NodeSuspend, "base", base).lastToken(),
207 Id.FieldInitializer => @fieldParentPtr(NodeFieldInitializer, "base", base).lastToken(),
208 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).lastToken(),
209 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).lastToken(),
210 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).lastToken(),
211 Id.MultilineStringLiteral => @fieldParentPtr(NodeMultilineStringLiteral, "base", base).lastToken(),
212 Id.CharLiteral => @fieldParentPtr(NodeCharLiteral, "base", base).lastToken(),
213 Id.BoolLiteral => @fieldParentPtr(NodeBoolLiteral, "base", base).lastToken(),
214 Id.NullLiteral => @fieldParentPtr(NodeNullLiteral, "base", base).lastToken(),
215 Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).lastToken(),
216 Id.ThisLiteral => @fieldParentPtr(NodeThisLiteral, "base", base).lastToken(),
217 Id.Asm => @fieldParentPtr(NodeAsm, "base", base).lastToken(),
218 Id.AsmInput => @fieldParentPtr(NodeAsmInput, "base", base).lastToken(),
219 Id.AsmOutput => @fieldParentPtr(NodeAsmOutput, "base", base).lastToken(),
220 Id.Unreachable => @fieldParentPtr(NodeUnreachable, "base", base).lastToken(),
221 Id.ErrorType => @fieldParentPtr(NodeErrorType, "base", base).lastToken(),
222 Id.VarType => @fieldParentPtr(NodeVarType, "base", base).lastToken(),
223 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).lastToken(),
224 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).lastToken(),
225 Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).lastToken(),
226 };
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();
183 }
184
185 unreachable;
227186 }
228187};
229188
......@@ -255,7 +214,7 @@ pub const NodeVarDecl = struct {
255214 eq_token: Token,
256215 mut_token: Token,
257216 comptime_token: ?Token,
258 extern_token: ?Token,
217 extern_export_token: ?Token,
259218 lib_name: ?&Node,
260219 type_node: ?&Node,
261220 align_node: ?&Node,
......@@ -286,7 +245,7 @@ pub const NodeVarDecl = struct {
286245 pub fn firstToken(self: &NodeVarDecl) Token {
287246 if (self.visib_token) |visib_token| return visib_token;
288247 if (self.comptime_token) |comptime_token| return comptime_token;
289 if (self.extern_token) |extern_token| return extern_token;
248 if (self.extern_export_token) |extern_export_token| return extern_export_token;
290249 assert(self.lib_name == null);
291250 return self.mut_token;
292251 }
......@@ -324,13 +283,13 @@ pub const NodeUse = struct {
324283pub const NodeErrorSetDecl = struct {
325284 base: Node,
326285 error_token: Token,
327 decls: ArrayList(&NodeIdentifier),
286 decls: ArrayList(&Node),
328287 rbrace_token: Token,
329288
330289 pub fn iterate(self: &NodeErrorSetDecl, index: usize) ?&Node {
331290 var i = index;
332291
333 if (i < self.decls.len) return &self.decls.at(i).base;
292 if (i < self.decls.len) return self.decls.at(i);
334293 i -= self.decls.len;
335294
336295 return null;
......@@ -401,6 +360,7 @@ pub const NodeContainerDecl = struct {
401360
402361pub const NodeStructField = struct {
403362 base: Node,
363 visib_token: ?Token,
404364 name_token: Token,
405365 type_expr: &Node,
406366
......@@ -414,6 +374,7 @@ pub const NodeStructField = struct {
414374 }
415375
416376 pub fn firstToken(self: &NodeStructField) Token {
377 if (self.visib_token) |visib_token| return visib_token;
417378 return self.name_token;
418379 }
419380
......@@ -482,18 +443,18 @@ pub const NodeEnumTag = struct {
482443
483444pub const NodeIdentifier = struct {
484445 base: Node,
485 name_token: Token,
446 token: Token,
486447
487448 pub fn iterate(self: &NodeIdentifier, index: usize) ?&Node {
488449 return null;
489450 }
490451
491452 pub fn firstToken(self: &NodeIdentifier) Token {
492 return self.name_token;
453 return self.token;
493454 }
494455
495456 pub fn lastToken(self: &NodeIdentifier) Token {
496 return self.name_token;
457 return self.token;
497458 }
498459};
499460
......@@ -535,8 +496,7 @@ pub const NodeFnProto = struct {
535496 params: ArrayList(&Node),
536497 return_type: ReturnType,
537498 var_args_token: ?Token,
538 extern_token: ?Token,
539 inline_token: ?Token,
499 extern_export_inline_token: ?Token,
540500 cc_token: ?Token,
541501 async_attr: ?&NodeAsyncAttribute,
542502 body_node: ?&Node,
......@@ -586,9 +546,8 @@ pub const NodeFnProto = struct {
586546
587547 pub fn firstToken(self: &NodeFnProto) Token {
588548 if (self.visib_token) |visib_token| return visib_token;
589 if (self.extern_token) |extern_token| return extern_token;
549 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
590550 assert(self.lib_name == null);
591 if (self.inline_token) |inline_token| return inline_token;
592551 if (self.cc_token) |cc_token| return cc_token;
593552 return self.fn_token;
594553 }
......@@ -717,13 +676,13 @@ pub const NodeComptime = struct {
717676pub const NodePayload = struct {
718677 base: Node,
719678 lpipe: Token,
720 error_symbol: &NodeIdentifier,
679 error_symbol: &Node,
721680 rpipe: Token,
722681
723682 pub fn iterate(self: &NodePayload, index: usize) ?&Node {
724683 var i = index;
725684
726 if (i < 1) return &self.error_symbol.base;
685 if (i < 1) return self.error_symbol;
727686 i -= 1;
728687
729688 return null;
......@@ -741,14 +700,14 @@ pub const NodePayload = struct {
741700pub const NodePointerPayload = struct {
742701 base: Node,
743702 lpipe: Token,
744 is_ptr: bool,
745 value_symbol: &NodeIdentifier,
703 ptr_token: ?Token,
704 value_symbol: &Node,
746705 rpipe: Token,
747706
748707 pub fn iterate(self: &NodePointerPayload, index: usize) ?&Node {
749708 var i = index;
750709
751 if (i < 1) return &self.value_symbol.base;
710 if (i < 1) return self.value_symbol;
752711 i -= 1;
753712
754713 return null;
......@@ -766,19 +725,19 @@ pub const NodePointerPayload = struct {
766725pub const NodePointerIndexPayload = struct {
767726 base: Node,
768727 lpipe: Token,
769 is_ptr: bool,
770 value_symbol: &NodeIdentifier,
771 index_symbol: ?&NodeIdentifier,
728 ptr_token: ?Token,
729 value_symbol: &Node,
730 index_symbol: ?&Node,
772731 rpipe: Token,
773732
774733 pub fn iterate(self: &NodePointerIndexPayload, index: usize) ?&Node {
775734 var i = index;
776735
777 if (i < 1) return &self.value_symbol.base;
736 if (i < 1) return self.value_symbol;
778737 i -= 1;
779738
780739 if (self.index_symbol) |index_symbol| {
781 if (i < 1) return &index_symbol.base;
740 if (i < 1) return index_symbol;
782741 i -= 1;
783742 }
784743
......@@ -797,14 +756,14 @@ pub const NodePointerIndexPayload = struct {
797756pub const NodeElse = struct {
798757 base: Node,
799758 else_token: Token,
800 payload: ?&NodePayload,
759 payload: ?&Node,
801760 body: &Node,
802761
803762 pub fn iterate(self: &NodeElse, index: usize) ?&Node {
804763 var i = index;
805764
806765 if (self.payload) |payload| {
807 if (i < 1) return &payload.base;
766 if (i < 1) return payload;
808767 i -= 1;
809768 }
810769
......@@ -854,7 +813,7 @@ pub const NodeSwitch = struct {
854813pub const NodeSwitchCase = struct {
855814 base: Node,
856815 items: ArrayList(&Node),
857 payload: ?&NodePointerPayload,
816 payload: ?&Node,
858817 expr: &Node,
859818
860819 pub fn iterate(self: &NodeSwitchCase, index: usize) ?&Node {
......@@ -864,7 +823,7 @@ pub const NodeSwitchCase = struct {
864823 i -= self.items.len;
865824
866825 if (self.payload) |payload| {
867 if (i < 1) return &payload.base;
826 if (i < 1) return payload;
868827 i -= 1;
869828 }
870829
......@@ -906,7 +865,7 @@ pub const NodeWhile = struct {
906865 inline_token: ?Token,
907866 while_token: Token,
908867 condition: &Node,
909 payload: ?&NodePointerPayload,
868 payload: ?&Node,
910869 continue_expr: ?&Node,
911870 body: &Node,
912871 @"else": ?&NodeElse,
......@@ -918,7 +877,7 @@ pub const NodeWhile = struct {
918877 i -= 1;
919878
920879 if (self.payload) |payload| {
921 if (i < 1) return &payload.base;
880 if (i < 1) return payload;
922881 i -= 1;
923882 }
924883
......@@ -965,7 +924,7 @@ pub const NodeFor = struct {
965924 inline_token: ?Token,
966925 for_token: Token,
967926 array_expr: &Node,
968 payload: ?&NodePointerIndexPayload,
927 payload: ?&Node,
969928 body: &Node,
970929 @"else": ?&NodeElse,
971930
......@@ -976,7 +935,7 @@ pub const NodeFor = struct {
976935 i -= 1;
977936
978937 if (self.payload) |payload| {
979 if (i < 1) return &payload.base;
938 if (i < 1) return payload;
980939 i -= 1;
981940 }
982941
......@@ -1016,7 +975,7 @@ pub const NodeIf = struct {
1016975 base: Node,
1017976 if_token: Token,
1018977 condition: &Node,
1019 payload: ?&NodePointerPayload,
978 payload: ?&Node,
1020979 body: &Node,
1021980 @"else": ?&NodeElse,
1022981
......@@ -1027,7 +986,7 @@ pub const NodeIf = struct {
1027986 i -= 1;
1028987
1029988 if (self.payload) |payload| {
1030 if (i < 1) return &payload.base;
989 if (i < 1) return payload;
1031990 i -= 1;
1032991 }
1033992
......@@ -1089,7 +1048,7 @@ pub const NodeInfixOp = struct {
10891048 BitXor,
10901049 BoolAnd,
10911050 BoolOr,
1092 Catch: ?&NodePayload,
1051 Catch: ?&Node,
10931052 Div,
10941053 EqualEqual,
10951054 ErrorUnion,
......@@ -1117,7 +1076,7 @@ pub const NodeInfixOp = struct {
11171076 switch (self.op) {
11181077 InfixOp.Catch => |maybe_payload| {
11191078 if (maybe_payload) |payload| {
1120 if (i < 1) return &payload.base;
1079 if (i < 1) return payload;
11211080 i -= 1;
11221081 }
11231082 },
......@@ -1385,14 +1344,30 @@ pub const NodeControlFlowExpression = struct {
13851344 rhs: ?&Node,
13861345
13871346 const Kind = union(enum) {
1388 Break: ?Token,
1389 Continue: ?Token,
1347 Break: ?&Node,
1348 Continue: ?&Node,
13901349 Return,
13911350 };
13921351
13931352 pub fn iterate(self: &NodeControlFlowExpression, index: usize) ?&Node {
13941353 var i = index;
13951354
1355 switch (self.kind) {
1356 Kind.Break => |maybe_label| {
1357 if (maybe_label) |label| {
1358 if (i < 1) return label;
1359 i -= 1;
1360 }
1361 },
1362 Kind.Continue => |maybe_label| {
1363 if (maybe_label) |label| {
1364 if (i < 1) return label;
1365 i -= 1;
1366 }
1367 },
1368 Kind.Return => {},
1369 }
1370
13961371 if (self.rhs) |rhs| {
13971372 if (i < 1) return rhs;
13981373 i -= 1;
......@@ -1411,14 +1386,14 @@ pub const NodeControlFlowExpression = struct {
14111386 }
14121387
14131388 switch (self.kind) {
1414 Kind.Break => |maybe_blk_token| {
1415 if (maybe_blk_token) |blk_token| {
1416 return blk_token;
1389 Kind.Break => |maybe_label| {
1390 if (maybe_label) |label| {
1391 return label.lastToken();
14171392 }
14181393 },
1419 Kind.Continue => |maybe_blk_token| {
1420 if (maybe_blk_token) |blk_token| {
1421 return blk_token;
1394 Kind.Continue => |maybe_label| {
1395 if (maybe_label) |label| {
1396 return label.lastToken();
14221397 }
14231398 },
14241399 Kind.Return => return self.ltoken,
......@@ -1431,14 +1406,14 @@ pub const NodeControlFlowExpression = struct {
14311406pub const NodeSuspend = struct {
14321407 base: Node,
14331408 suspend_token: Token,
1434 payload: ?&NodePayload,
1409 payload: ?&Node,
14351410 body: ?&Node,
14361411
14371412 pub fn iterate(self: &NodeSuspend, index: usize) ?&Node {
14381413 var i = index;
14391414
14401415 if (self.payload) |payload| {
1441 if (i < 1) return &payload.base;
1416 if (i < 1) return payload;
14421417 i -= 1;
14431418 }
14441419
......@@ -1646,8 +1621,8 @@ pub const NodeThisLiteral = struct {
16461621
16471622pub const NodeAsmOutput = struct {
16481623 base: Node,
1649 symbolic_name: &NodeIdentifier,
1650 constraint: &NodeStringLiteral,
1624 symbolic_name: &Node,
1625 constraint: &Node,
16511626 kind: Kind,
16521627
16531628 const Kind = union(enum) {
......@@ -1658,10 +1633,10 @@ pub const NodeAsmOutput = struct {
16581633 pub fn iterate(self: &NodeAsmOutput, index: usize) ?&Node {
16591634 var i = index;
16601635
1661 if (i < 1) return &self.symbolic_name.base;
1636 if (i < 1) return self.symbolic_name;
16621637 i -= 1;
16631638
1664 if (i < 1) return &self.constraint.base;
1639 if (i < 1) return self.constraint;
16651640 i -= 1;
16661641
16671642 switch (self.kind) {
......@@ -1692,17 +1667,17 @@ pub const NodeAsmOutput = struct {
16921667
16931668pub const NodeAsmInput = struct {
16941669 base: Node,
1695 symbolic_name: &NodeIdentifier,
1696 constraint: &NodeStringLiteral,
1670 symbolic_name: &Node,
1671 constraint: &Node,
16971672 expr: &Node,
16981673
16991674 pub fn iterate(self: &NodeAsmInput, index: usize) ?&Node {
17001675 var i = index;
17011676
1702 if (i < 1) return &self.symbolic_name.base;
1677 if (i < 1) return self.symbolic_name;
17031678 i -= 1;
17041679
1705 if (i < 1) return &self.constraint.base;
1680 if (i < 1) return self.constraint;
17061681 i -= 1;
17071682
17081683 if (i < 1) return self.expr;
......@@ -1723,12 +1698,12 @@ pub const NodeAsmInput = struct {
17231698pub const NodeAsm = struct {
17241699 base: Node,
17251700 asm_token: Token,
1726 is_volatile: bool,
1727 template: Token,
1701 volatile_token: ?Token,
1702 template: &Node,
17281703 //tokens: ArrayList(AsmToken),
17291704 outputs: ArrayList(&NodeAsmOutput),
17301705 inputs: ArrayList(&NodeAsmInput),
1731 cloppers: ArrayList(&NodeStringLiteral),
1706 cloppers: ArrayList(&Node),
17321707 rparen: Token,
17331708
17341709 pub fn iterate(self: &NodeAsm, index: usize) ?&Node {
......@@ -1740,7 +1715,7 @@ pub const NodeAsm = struct {
17401715 if (i < self.inputs.len) return &self.inputs.at(index).base;
17411716 i -= self.inputs.len;
17421717
1743 if (i < self.cloppers.len) return &self.cloppers.at(index).base;
1718 if (i < self.cloppers.len) return self.cloppers.at(index);
17441719 i -= self.cloppers.len;
17451720
17461721 return null;
std/zig/parser.zig+2462-2246
......@@ -55,33 +55,33 @@ pub const Parser = struct {
5555 const TopLevelDeclCtx = struct {
5656 decls: &ArrayList(&ast.Node),
5757 visib_token: ?Token,
58 extern_token: ?Token,
58 extern_export_inline_token: ?Token,
5959 lib_name: ?&ast.Node,
6060 };
6161
62 const ContainerExternCtx = struct {
63 dest_ptr: DestPtr,
64 ltoken: Token,
65 layout: ast.NodeContainerDecl.Layout,
62 const VarDeclCtx = struct {
63 mut_token: Token,
64 visib_token: ?Token,
65 comptime_token: ?Token,
66 extern_export_token: ?Token,
67 lib_name: ?&ast.Node,
68 list: &ArrayList(&ast.Node),
6669 };
6770
68 const DestPtr = union(enum) {
69 Field: &&ast.Node,
70 NullableField: &?&ast.Node,
71 const TopLevelExternOrFieldCtx = struct {
72 visib_token: Token,
73 container_decl: &ast.NodeContainerDecl,
74 };
7175
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 }
76 const ExternTypeCtx = struct {
77 opt_ctx: OptionalCtx,
78 extern_token: Token,
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.NodeContainerDecl.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,117 +107,196 @@ 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,
134 ctx: OptionalCtx,
139135 attribute: &ast.NodeAsyncAttribute,
140136 };
141137
138 const ErrorTypeOrSetDeclCtx = struct {
139 opt_ctx: OptionalCtx,
140 error_token: Token,
141 };
142
143 const ParamDeclEndCtx = struct {
144 fn_proto: &ast.NodeFnProto,
145 param_decl: &ast.NodeParamDecl,
146 };
147
148 const ComptimeStatementCtx = struct {
149 comptime_token: Token,
150 block: &ast.NodeBlock,
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 }
183 };
184
142185 const State = union(enum) {
143186 TopLevel,
144187 TopLevelExtern: TopLevelDeclCtx,
188 TopLevelLibname: TopLevelDeclCtx,
145189 TopLevelDecl: TopLevelDeclCtx,
146 ContainerExtern: ContainerExternCtx,
190 TopLevelExternOrField: TopLevelExternOrFieldCtx,
191
192 ContainerKind: ContainerKindCtx,
193 ContainerInitArgStart: &ast.NodeContainerDecl,
194 ContainerInitArg: &ast.NodeContainerDecl,
147195 ContainerDecl: &ast.NodeContainerDecl,
148 SliceOrArrayAccess: &ast.NodeSuffixOp,
149 AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo,
150 VarDecl: &ast.NodeVarDecl,
196
197 VarDecl: VarDeclCtx,
151198 VarDeclAlign: &ast.NodeVarDecl,
152199 VarDeclEq: &ast.NodeVarDecl,
153 IfToken: @TagType(Token.Id),
154 IfTokenSave: ExpectTokenSave,
155 ExpectToken: @TagType(Token.Id),
156 ExpectTokenSave: ExpectTokenSave,
200
201 FnDef: &ast.NodeFnProto,
157202 FnProto: &ast.NodeFnProto,
158203 FnProtoAlign: &ast.NodeFnProto,
159204 FnProtoReturnType: &ast.NodeFnProto,
205
160206 ParamDecl: &ast.NodeFnProto,
161 ParamDeclComma,
162 FnDef: &ast.NodeFnProto,
207 ParamDeclAliasOrComptime: &ast.NodeParamDecl,
208 ParamDeclName: &ast.NodeParamDecl,
209 ParamDeclEnd: ParamDeclEndCtx,
210 ParamDeclComma: &ast.NodeFnProto,
211
212 MaybeLabeledExpression: MaybeLabeledExpressionCtx,
163213 LabeledExpression: LabelCtx,
164214 Inline: InlineCtx,
165215 While: LoopCtx,
216 WhileContinueExpr: &?&ast.Node,
166217 For: LoopCtx,
167 Block: &ast.NodeBlock,
168218 Else: &?&ast.NodeElse,
169 WhileContinueExpr: &?&ast.Node,
219
220 Block: &ast.NodeBlock,
170221 Statement: &ast.NodeBlock,
171 Semicolon: &const &const ast.Node,
222 ComptimeStatement: ComptimeStatementCtx,
223 Semicolon: &&ast.Node,
224
172225 AsmOutputItems: &ArrayList(&ast.NodeAsmOutput),
226 AsmOutputReturnOrType: &ast.NodeAsmOutput,
173227 AsmInputItems: &ArrayList(&ast.NodeAsmInput),
174 AsmClopperItems: &ArrayList(&ast.NodeStringLiteral),
228 AsmClopperItems: &ArrayList(&ast.Node),
229
175230 ExprListItemOrEnd: ExprListCtx,
176231 ExprListCommaOrEnd: ExprListCtx,
177232 FieldInitListItemOrEnd: ListSave(&ast.NodeFieldInitializer),
178233 FieldInitListCommaOrEnd: ListSave(&ast.NodeFieldInitializer),
179234 FieldListCommaOrEnd: &ast.NodeContainerDecl,
235 IdentifierListItemOrEnd: ListSave(&ast.Node),
236 IdentifierListCommaOrEnd: ListSave(&ast.Node),
180237 SwitchCaseOrEnd: ListSave(&ast.NodeSwitchCase),
181 SuspendBody: &ast.NodeSuspend,
182 AsyncEnd: AsyncEndCtx,
183 Payload: &?&ast.NodePayload,
184 PointerPayload: &?&ast.NodePointerPayload,
185 PointerIndexPayload: &?&ast.NodePointerIndexPayload,
186238 SwitchCaseCommaOrEnd: ListSave(&ast.NodeSwitchCase),
239 SwitchCaseFirstItem: &ArrayList(&ast.Node),
187240 SwitchCaseItem: &ArrayList(&ast.Node),
188241 SwitchCaseItemCommaOrEnd: &ArrayList(&ast.Node),
189242
190 /// A state that can be appended before any other State. If an error occures,
191 /// the parser will first try looking for the closest optional state. If an
192 /// optional state is found, the parser will revert to the state it was in
193 /// when the optional was added. This will polute the arena allocator with
194 /// "leaked" nodes. TODO: Figure out if it's nessesary to handle leaked nodes.
195 Optional: RevertState,
196
197 Expression: DestPtr,
198 RangeExpressionBegin: DestPtr,
199 RangeExpressionEnd: DestPtr,
200 AssignmentExpressionBegin: DestPtr,
201 AssignmentExpressionEnd: DestPtr,
202 UnwrapExpressionBegin: DestPtr,
203 UnwrapExpressionEnd: DestPtr,
204 BoolOrExpressionBegin: DestPtr,
205 BoolOrExpressionEnd: DestPtr,
206 BoolAndExpressionBegin: DestPtr,
207 BoolAndExpressionEnd: DestPtr,
208 ComparisonExpressionBegin: DestPtr,
209 ComparisonExpressionEnd: DestPtr,
210 BinaryOrExpressionBegin: DestPtr,
211 BinaryOrExpressionEnd: DestPtr,
212 BinaryXorExpressionBegin: DestPtr,
213 BinaryXorExpressionEnd: DestPtr,
214 BinaryAndExpressionBegin: DestPtr,
215 BinaryAndExpressionEnd: DestPtr,
216 BitShiftExpressionBegin: DestPtr,
217 BitShiftExpressionEnd: DestPtr,
218 AdditionExpressionBegin: DestPtr,
219 AdditionExpressionEnd: DestPtr,
220 MultiplyExpressionBegin: DestPtr,
221 MultiplyExpressionEnd: DestPtr,
222 CurlySuffixExpressionBegin: DestPtr,
223 CurlySuffixExpressionEnd: DestPtr,
224 TypeExprBegin: DestPtr,
225 TypeExprEnd: DestPtr,
226 PrefixOpExpression: DestPtr,
227 SuffixOpExpressionBegin: DestPtr,
228 SuffixOpExpressionEnd: DestPtr,
229 PrimaryExpression: DestPtr,
243 SuspendBody: &ast.NodeSuspend,
244 AsyncAllocator: &ast.NodeAsyncAttribute,
245 AsyncEnd: AsyncEndCtx,
246
247 ExternType: ExternTypeCtx,
248 SliceOrArrayAccess: &ast.NodeSuffixOp,
249 SliceOrArrayType: &ast.NodePrefixOp,
250 AddrOfModifiers: &ast.NodePrefixOp.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,
230300 };
231301
232302 /// Returns an AST tree, allocated with the parser's allocator.
......@@ -240,7 +310,14 @@ pub const Parser = struct {
240310 errdefer arena_allocator.deinit();
241311
242312 const arena = &arena_allocator.allocator;
243 const root_node = try self.createRoot(arena);
313 const root_node = try self.createNode(arena, ast.NodeRoot,
314 ast.NodeRoot {
315 .base = undefined,
316 .decls = ArrayList(&ast.Node).init(arena),
317 // initialized when we get the eof token
318 .eof_token = undefined,
319 }
320 );
244321
245322 try stack.append(State.TopLevel);
246323
......@@ -259,8 +336,7 @@ pub const Parser = struct {
259336
260337 // look for line comments
261338 while (true) {
262 const token = self.getNextToken();
263 if (token.id == Token.Id.LineComment) {
339 if (self.eatToken(Token.Id.LineComment)) |line_comment| {
264340 const node = blk: {
265341 if (self.pending_line_comment_node) |comment_node| {
266342 break :blk comment_node;
......@@ -277,10 +353,9 @@ pub const Parser = struct {
277353 break :blk comment_node;
278354 }
279355 };
280 try node.lines.append(token);
356 try node.lines.append(line_comment);
281357 continue;
282358 }
283 self.putBackToken(token);
284359 break;
285360 }
286361
......@@ -294,41 +369,74 @@ pub const Parser = struct {
294369 Token.Id.Keyword_test => {
295370 stack.append(State.TopLevel) catch unreachable;
296371
297 const name_token = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue;
298 const lbrace = (try self.eatToken(&stack, Token.Id.LBrace)) ?? continue;
299
300 const name = try self.createStringLiteral(arena, name_token);
301 const block = try self.createBlock(arena, (?Token)(null), token);
302 const test_decl = try self.createAttachTestDecl(arena, &root_node.decls, token, &name.base, block);
372 const block = try self.createNode(arena, ast.NodeBlock,
373 ast.NodeBlock {
374 .base = undefined,
375 .label = null,
376 .lbrace = undefined,
377 .statements = ArrayList(&ast.Node).init(arena),
378 .rbrace = undefined,
379 }
380 );
381 const test_node = try self.createAttachNode(arena, &root_node.decls, ast.NodeTestDecl,
382 ast.NodeTestDecl {
383 .base = undefined,
384 .test_token = token,
385 .name = undefined,
386 .body_node = &block.base,
387 }
388 );
303389 stack.append(State { .Block = block }) catch unreachable;
390 try stack.append(State {
391 .ExpectTokenSave = ExpectTokenSave {
392 .id = Token.Id.LBrace,
393 .ptr = &block.rbrace,
394 }
395 });
396 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &test_node.name } });
304397 continue;
305398 },
306399 Token.Id.Eof => {
307400 root_node.eof_token = token;
308401 return Tree {.root_node = root_node, .arena_allocator = arena_allocator};
309402 },
310 Token.Id.Keyword_pub, Token.Id.Keyword_export => {
403 Token.Id.Keyword_pub => {
311404 stack.append(State.TopLevel) catch unreachable;
312405 try stack.append(State {
313406 .TopLevelExtern = TopLevelDeclCtx {
314407 .decls = &root_node.decls,
315408 .visib_token = token,
316 .extern_token = null,
409 .extern_export_inline_token = null,
317410 .lib_name = null,
318411 }
319412 });
320413 continue;
321414 },
322415 Token.Id.Keyword_comptime => {
323 const node = try arena.create(ast.NodeComptime);
324 *node = ast.NodeComptime {
325 .base = self.initNode(ast.Node.Id.Comptime),
326 .comptime_token = token,
327 .expr = undefined,
328 };
329 try root_node.decls.append(&node.base);
416 const block = try self.createNode(arena, ast.NodeBlock,
417 ast.NodeBlock {
418 .base = undefined,
419 .label = null,
420 .lbrace = undefined,
421 .statements = ArrayList(&ast.Node).init(arena),
422 .rbrace = undefined,
423 }
424 );
425 const node = try self.createAttachNode(arena, &root_node.decls, ast.NodeComptime,
426 ast.NodeComptime {
427 .base = undefined,
428 .comptime_token = token,
429 .expr = &block.base,
430 }
431 );
330432 stack.append(State.TopLevel) catch unreachable;
331 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
433 try stack.append(State { .Block = block });
434 try stack.append(State {
435 .ExpectTokenSave = ExpectTokenSave {
436 .id = Token.Id.LBrace,
437 .ptr = &block.rbrace,
438 }
439 });
332440 continue;
333441 },
334442 else => {
......@@ -338,7 +446,7 @@ pub const Parser = struct {
338446 .TopLevelExtern = TopLevelDeclCtx {
339447 .decls = &root_node.decls,
340448 .visib_token = null,
341 .extern_token = null,
449 .extern_export_inline_token = null,
342450 .lib_name = null,
343451 }
344452 });
......@@ -349,43 +457,24 @@ pub const Parser = struct {
349457 State.TopLevelExtern => |ctx| {
350458 const token = self.getNextToken();
351459 switch (token.id) {
352 Token.Id.Keyword_use => {
353 const node = try arena.create(ast.NodeUse);
354 *node = ast.NodeUse {
355 .base = self.initNode(ast.Node.Id.Use),
356 .visib_token = ctx.visib_token,
357 .expr = undefined,
358 .semicolon_token = undefined,
359 };
360 try ctx.decls.append(&node.base);
361
460 Token.Id.Keyword_export, Token.Id.Keyword_inline => {
362461 stack.append(State {
363 .ExpectTokenSave = ExpectTokenSave {
364 .id = Token.Id.Semicolon,
365 .ptr = &node.semicolon_token,
366 }
462 .TopLevelDecl = TopLevelDeclCtx {
463 .decls = ctx.decls,
464 .visib_token = ctx.visib_token,
465 .extern_export_inline_token = token,
466 .lib_name = null,
467 },
367468 }) catch unreachable;
368 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
369469 continue;
370470 },
371471 Token.Id.Keyword_extern => {
372 const lib_name_token = self.getNextToken();
373 const lib_name = blk: {
374 if (lib_name_token.id == Token.Id.StringLiteral) {
375 const res = try self.createStringLiteral(arena, lib_name_token);
376 break :blk &res.base;
377 } else {
378 self.putBackToken(lib_name_token);
379 break :blk null;
380 }
381 };
382
383472 stack.append(State {
384 .TopLevelDecl = TopLevelDeclCtx {
473 .TopLevelLibname = TopLevelDeclCtx {
385474 .decls = ctx.decls,
386475 .visib_token = ctx.visib_token,
387 .extern_token = token,
388 .lib_name = lib_name,
476 .extern_export_inline_token = token,
477 .lib_name = null,
389478 },
390479 }) catch unreachable;
391480 continue;
......@@ -397,258 +486,302 @@ pub const Parser = struct {
397486 }
398487 }
399488 },
489 State.TopLevelLibname => |ctx| {
490 const lib_name = blk: {
491 const lib_name_token = self.getNextToken();
492 break :blk (try self.parseStringLiteral(arena, lib_name_token)) ?? {
493 self.putBackToken(lib_name_token);
494 break :blk null;
495 };
496 };
497
498 stack.append(State {
499 .TopLevelDecl = TopLevelDeclCtx {
500 .decls = ctx.decls,
501 .visib_token = ctx.visib_token,
502 .extern_export_inline_token = ctx.extern_export_inline_token,
503 .lib_name = lib_name,
504 },
505 }) catch unreachable;
506 continue;
507 },
400508 State.TopLevelDecl => |ctx| {
401509 const token = self.getNextToken();
402510 switch (token.id) {
403 Token.Id.Keyword_var, Token.Id.Keyword_const => {
404 // TODO shouldn't need these casts
405 const var_decl_node = try self.createAttachVarDecl(arena, ctx.decls, ctx.visib_token,
406 token, (?Token)(null), ctx.extern_token, ctx.lib_name);
407 stack.append(State { .VarDecl = var_decl_node }) catch unreachable;
408 continue;
409 },
410 Token.Id.Keyword_fn => {
411 // TODO shouldn't need these casts
412 const fn_proto = try self.createAttachFnProto(arena, ctx.decls, token,
413 ctx.extern_token, ctx.lib_name, (?Token)(null), ctx.visib_token, (?Token)(null));
414 stack.append(State { .FnDef = fn_proto }) catch unreachable;
415 try stack.append(State { .FnProto = fn_proto });
416 continue;
417 },
418 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
419 // TODO shouldn't need this cast
420 const fn_proto = try self.createAttachFnProto(arena, ctx.decls, Token(undefined),
421 ctx.extern_token, ctx.lib_name, (?Token)(token), (?Token)(null), (?Token)(null));
422 stack.append(State { .FnDef = fn_proto }) catch unreachable;
423 try stack.append(State { .FnProto = fn_proto });
424 try stack.append(State {
511 Token.Id.Keyword_use => {
512 if (ctx.extern_export_inline_token != null) {
513 return self.parseError(token, "Invalid token {}", @tagName((??ctx.extern_export_inline_token).id));
514 }
515
516 const node = try self.createAttachNode(arena, ctx.decls, ast.NodeUse,
517 ast.NodeUse {
518 .base = undefined,
519 .visib_token = ctx.visib_token,
520 .expr = undefined,
521 .semicolon_token = undefined,
522 }
523 );
524 stack.append(State {
425525 .ExpectTokenSave = ExpectTokenSave {
426 .id = Token.Id.Keyword_fn,
427 .ptr = &fn_proto.fn_token,
526 .id = Token.Id.Semicolon,
527 .ptr = &node.semicolon_token,
428528 }
429 });
529 }) catch unreachable;
530 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
430531 continue;
431532 },
432 Token.Id.Keyword_async => {
433 // TODO shouldn't need this cast
434 const fn_proto = try self.createAttachFnProto(arena, ctx.decls, Token(undefined),
435 ctx.extern_token, ctx.lib_name, (?Token)(null), (?Token)(null), (?Token)(null));
436
437 const async_node = try arena.create(ast.NodeAsyncAttribute);
438 *async_node = ast.NodeAsyncAttribute {
439 .base = self.initNode(ast.Node.Id.AsyncAttribute),
440 .async_token = token,
441 .allocator_type = null,
442 .rangle_bracket = null,
443 };
444
445 fn_proto.async_attr = async_node;
446 stack.append(State { .FnDef = fn_proto }) catch unreachable;
447 try stack.append(State { .FnProto = fn_proto });
448 try stack.append(State {
449 .ExpectTokenSave = ExpectTokenSave {
450 .id = Token.Id.Keyword_fn,
451 .ptr = &fn_proto.fn_token,
533 Token.Id.Keyword_var, Token.Id.Keyword_const => {
534 if (ctx.extern_export_inline_token) |extern_export_inline_token| {
535 if (extern_export_inline_token.id == Token.Id.Keyword_inline) {
536 return self.parseError(token, "Invalid token {}", @tagName(extern_export_inline_token.id));
452537 }
453 });
454
455 const langle_bracket = self.getNextToken();
456 if (langle_bracket.id != Token.Id.AngleBracketLeft) {
457 self.putBackToken(langle_bracket);
458 continue;
459538 }
460539
461 async_node.rangle_bracket = Token(undefined);
462 try stack.append(State {
463 .ExpectTokenSave = ExpectTokenSave {
464 .id = Token.Id.AngleBracketRight,
465 .ptr = &??async_node.rangle_bracket,
540 stack.append(State {
541 .VarDecl = VarDeclCtx {
542 .visib_token = ctx.visib_token,
543 .lib_name = ctx.lib_name,
544 .comptime_token = null,
545 .extern_export_token = ctx.extern_export_inline_token,
546 .mut_token = token,
547 .list = ctx.decls
466548 }
467 });
468 try stack.append(State { .TypeExprBegin = DestPtr { .NullableField = &async_node.allocator_type } });
549 }) catch unreachable;
469550 continue;
470551 },
552 Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc,
553 Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => {
554 const fn_proto = try self.createAttachNode(arena, ctx.decls, ast.NodeFnProto,
555 ast.NodeFnProto {
556 .base = undefined,
557 .visib_token = ctx.visib_token,
558 .name_token = null,
559 .fn_token = undefined,
560 .params = ArrayList(&ast.Node).init(arena),
561 .return_type = undefined,
562 .var_args_token = null,
563 .extern_export_inline_token = ctx.extern_export_inline_token,
564 .cc_token = null,
565 .async_attr = null,
566 .body_node = null,
567 .lib_name = ctx.lib_name,
568 .align_expr = null,
569 }
570 );
571 stack.append(State { .FnDef = fn_proto }) catch unreachable;
572 try stack.append(State { .FnProto = fn_proto });
573
574 switch (token.id) {
575 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
576 fn_proto.cc_token = token;
577 try stack.append(State {
578 .ExpectTokenSave = ExpectTokenSave {
579 .id = Token.Id.Keyword_fn,
580 .ptr = &fn_proto.fn_token,
581 }
582 });
583 continue;
584 },
585 Token.Id.Keyword_async => {
586 const async_node = try self.createNode(arena, ast.NodeAsyncAttribute,
587 ast.NodeAsyncAttribute {
588 .base = undefined,
589 .async_token = token,
590 .allocator_type = null,
591 .rangle_bracket = null,
592 }
593 );
594 fn_proto.async_attr = async_node;
595
596 try stack.append(State {
597 .ExpectTokenSave = ExpectTokenSave {
598 .id = Token.Id.Keyword_fn,
599 .ptr = &fn_proto.fn_token,
600 }
601 });
602 try stack.append(State { .AsyncAllocator = async_node });
603 continue;
604 },
605 Token.Id.Keyword_fn => {
606 fn_proto.fn_token = token;
607 continue;
608 },
609 else => unreachable,
610 }
611 },
471612 else => {
472 try self.parseError(&stack, token, "expected variable declaration or function, found {}", @tagName(token.id));
473 continue;
613 return self.parseError(token, "expected variable declaration or function, found {}", @tagName(token.id));
474614 },
475615 }
476616 },
477 State.VarDecl => |var_decl| {
478 stack.append(State { .VarDeclAlign = var_decl }) catch unreachable;
479 try stack.append(State { .TypeExprBegin = DestPtr {.NullableField = &var_decl.type_node} });
480 try stack.append(State { .IfToken = Token.Id.Colon });
481 try stack.append(State {
482 .ExpectTokenSave = ExpectTokenSave {
483 .id = Token.Id.Identifier,
484 .ptr = &var_decl.name_token,
485 }
486 });
487 continue;
488 },
489 State.VarDeclAlign => |var_decl| {
490 stack.append(State { .VarDeclEq = var_decl }) catch unreachable;
617 State.TopLevelExternOrField => |ctx| {
618 if (self.eatToken(Token.Id.Identifier)) |identifier| {
619 std.debug.assert(ctx.container_decl.kind == ast.NodeContainerDecl.Kind.Struct);
620 const node = try self.createAttachNode(arena, &ctx.container_decl.fields_and_decls, ast.NodeStructField,
621 ast.NodeStructField {
622 .base = undefined,
623 .visib_token = ctx.visib_token,
624 .name_token = identifier,
625 .type_expr = undefined,
626 }
627 );
491628
492 const next_token = self.getNextToken();
493 if (next_token.id == Token.Id.Keyword_align) {
494 try stack.append(State { .ExpectToken = Token.Id.RParen });
495 try stack.append(State { .Expression = DestPtr{.NullableField = &var_decl.align_node} });
496 try stack.append(State { .ExpectToken = Token.Id.LParen });
629 stack.append(State { .FieldListCommaOrEnd = ctx.container_decl }) catch unreachable;
630 try stack.append(State { .Expression = OptionalCtx { .Required = &node.type_expr } });
631 try stack.append(State { .ExpectToken = Token.Id.Colon });
497632 continue;
498633 }
499634
500 self.putBackToken(next_token);
501 continue;
502 },
503 State.VarDeclEq => |var_decl| {
504 const token = self.getNextToken();
505 if (token.id == Token.Id.Equal) {
506 var_decl.eq_token = token;
507 stack.append(State {
508 .ExpectTokenSave = ExpectTokenSave {
509 .id = Token.Id.Semicolon,
510 .ptr = &var_decl.semicolon_token,
511 },
512 }) catch unreachable;
513 try stack.append(State {
514 .Expression = DestPtr {.NullableField = &var_decl.init_node},
515 });
516 continue;
517 }
518 if (token.id == Token.Id.Semicolon) {
519 var_decl.semicolon_token = token;
520 continue;
521 }
522 try self.parseError(&stack, token, "expected '=' or ';', found {}", @tagName(token.id));
635 stack.append(State{ .ContainerDecl = ctx.container_decl }) catch unreachable;
636 try stack.append(State {
637 .TopLevelExtern = TopLevelDeclCtx {
638 .decls = &ctx.container_decl.fields_and_decls,
639 .visib_token = ctx.visib_token,
640 .extern_export_inline_token = null,
641 .lib_name = null,
642 }
643 });
523644 continue;
524645 },
525646
526 State.ContainerExtern => |ctx| {
527 const token = self.getNextToken();
528647
529 const node = try arena.create(ast.NodeContainerDecl);
530 *node = ast.NodeContainerDecl {
531 .base = self.initNode(ast.Node.Id.ContainerDecl),
532 .ltoken = ctx.ltoken,
533 .layout = ctx.layout,
534 .kind = switch (token.id) {
535 Token.Id.Keyword_struct => ast.NodeContainerDecl.Kind.Struct,
536 Token.Id.Keyword_union => ast.NodeContainerDecl.Kind.Union,
537 Token.Id.Keyword_enum => ast.NodeContainerDecl.Kind.Enum,
538 else => {
539 try self.parseError(&stack, token, "expected {}, {} or {}, found {}",
540 @tagName(Token.Id.Keyword_struct),
541 @tagName(Token.Id.Keyword_union),
542 @tagName(Token.Id.Keyword_enum),
543 @tagName(token.id));
544 continue;
648 State.ContainerKind => |ctx| {
649 const token = self.getNextToken();
650 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeContainerDecl,
651 ast.NodeContainerDecl {
652 .base = undefined,
653 .ltoken = ctx.ltoken,
654 .layout = ctx.layout,
655 .kind = switch (token.id) {
656 Token.Id.Keyword_struct => ast.NodeContainerDecl.Kind.Struct,
657 Token.Id.Keyword_union => ast.NodeContainerDecl.Kind.Union,
658 Token.Id.Keyword_enum => ast.NodeContainerDecl.Kind.Enum,
659 else => {
660 return self.parseError(token, "expected {}, {} or {}, found {}",
661 @tagName(Token.Id.Keyword_struct),
662 @tagName(Token.Id.Keyword_union),
663 @tagName(Token.Id.Keyword_enum),
664 @tagName(token.id));
665 },
545666 },
546 },
547 .init_arg_expr = undefined,
548 .fields_and_decls = ArrayList(&ast.Node).init(arena),
549 .rbrace_token = undefined,
550 };
551 ctx.dest_ptr.store(&node.base);
667 .init_arg_expr = ast.NodeContainerDecl.InitArg.None,
668 .fields_and_decls = ArrayList(&ast.Node).init(arena),
669 .rbrace_token = undefined,
670 }
671 );
552672
553673 stack.append(State { .ContainerDecl = node }) catch unreachable;
554674 try stack.append(State { .ExpectToken = Token.Id.LBrace });
675 try stack.append(State { .ContainerInitArgStart = node });
676 continue;
677 },
555678
556 const lparen = self.getNextToken();
557 if (lparen.id != Token.Id.LParen) {
558 self.putBackToken(lparen);
559 node.init_arg_expr = ast.NodeContainerDecl.InitArg.None;
679 State.ContainerInitArgStart => |container_decl| {
680 if (self.eatToken(Token.Id.LParen) == null) {
560681 continue;
561682 }
562683
563 try stack.append(State { .ExpectToken = Token.Id.RParen });
684 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
685 try stack.append(State { .ContainerInitArg = container_decl });
686 continue;
687 },
564688
689 State.ContainerInitArg => |container_decl| {
565690 const init_arg_token = self.getNextToken();
566691 switch (init_arg_token.id) {
567692 Token.Id.Keyword_enum => {
568 node.init_arg_expr = ast.NodeContainerDecl.InitArg.Enum;
693 container_decl.init_arg_expr = ast.NodeContainerDecl.InitArg.Enum;
569694 },
570695 else => {
571696 self.putBackToken(init_arg_token);
572 node.init_arg_expr = ast.NodeContainerDecl.InitArg { .Type = undefined };
573 try stack.append(State {
574 .Expression = DestPtr {
575 .Field = &node.init_arg_expr.Type
576 }
577 });
697 container_decl.init_arg_expr = ast.NodeContainerDecl.InitArg { .Type = undefined };
698 stack.append(State { .Expression = OptionalCtx { .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;
578699 },
579700 }
580701 continue;
581702 },
582
583703 State.ContainerDecl => |container_decl| {
584704 const token = self.getNextToken();
585
586705 switch (token.id) {
587706 Token.Id.Identifier => {
588707 switch (container_decl.kind) {
589708 ast.NodeContainerDecl.Kind.Struct => {
590 const node = try arena.create(ast.NodeStructField);
591 *node = ast.NodeStructField {
592 .base = self.initNode(ast.Node.Id.StructField),
593 .name_token = token,
594 .type_expr = undefined,
595 };
596 try container_decl.fields_and_decls.append(&node.base);
709 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeStructField,
710 ast.NodeStructField {
711 .base = undefined,
712 .visib_token = null,
713 .name_token = token,
714 .type_expr = undefined,
715 }
716 );
597717
598718 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
599 try stack.append(State { .Expression = DestPtr { .Field = &node.type_expr } });
719 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.type_expr } });
600720 try stack.append(State { .ExpectToken = Token.Id.Colon });
601721 continue;
602722 },
603723 ast.NodeContainerDecl.Kind.Union => {
604 const node = try arena.create(ast.NodeUnionTag);
605 *node = ast.NodeUnionTag {
606 .base = self.initNode(ast.Node.Id.UnionTag),
607 .name_token = token,
608 .type_expr = null,
609 };
610 try container_decl.fields_and_decls.append(&node.base);
724 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeUnionTag,
725 ast.NodeUnionTag {
726 .base = undefined,
727 .name_token = token,
728 .type_expr = null,
729 }
730 );
611731
612732 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
613
614 const next = self.getNextToken();
615 if (next.id != Token.Id.Colon) {
616 self.putBackToken(next);
617 continue;
618 }
619
620 try stack.append(State { .Expression = DestPtr { .NullableField = &node.type_expr } });
733 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &node.type_expr } });
734 try stack.append(State { .IfToken = Token.Id.Colon });
621735 continue;
622736 },
623737 ast.NodeContainerDecl.Kind.Enum => {
624 const node = try arena.create(ast.NodeEnumTag);
625 *node = ast.NodeEnumTag {
626 .base = self.initNode(ast.Node.Id.EnumTag),
627 .name_token = token,
628 .value = null,
629 };
630 try container_decl.fields_and_decls.append(&node.base);
738 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeEnumTag,
739 ast.NodeEnumTag {
740 .base = undefined,
741 .name_token = token,
742 .value = null,
743 }
744 );
631745
632746 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
633
634 const next = self.getNextToken();
635 if (next.id != Token.Id.Equal) {
636 self.putBackToken(next);
637 continue;
638 }
639
640 try stack.append(State { .Expression = DestPtr { .NullableField = &node.value } });
747 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &node.value } });
748 try stack.append(State { .IfToken = Token.Id.Equal });
749 continue;
750 },
751 }
752 },
753 Token.Id.Keyword_pub => {
754 switch (container_decl.kind) {
755 ast.NodeContainerDecl.Kind.Struct => {
756 try stack.append(State {
757 .TopLevelExternOrField = TopLevelExternOrFieldCtx {
758 .visib_token = token,
759 .container_decl = container_decl,
760 }
761 });
641762 continue;
642763 },
764 else => {
765 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
766 try stack.append(State {
767 .TopLevelExtern = TopLevelDeclCtx {
768 .decls = &container_decl.fields_and_decls,
769 .visib_token = token,
770 .extern_export_inline_token = null,
771 .lib_name = null,
772 }
773 });
774 continue;
775 }
643776 }
644777 },
645 Token.Id.Keyword_pub, Token.Id.Keyword_export => {
778 Token.Id.Keyword_export => {
646779 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
647780 try stack.append(State {
648781 .TopLevelExtern = TopLevelDeclCtx {
649782 .decls = &container_decl.fields_and_decls,
650783 .visib_token = token,
651 .extern_token = null,
784 .extern_export_inline_token = null,
652785 .lib_name = null,
653786 }
654787 });
......@@ -665,7 +798,7 @@ pub const Parser = struct {
665798 .TopLevelExtern = TopLevelDeclCtx {
666799 .decls = &container_decl.fields_and_decls,
667800 .visib_token = null,
668 .extern_token = null,
801 .extern_export_inline_token = null,
669802 .lib_name = null,
670803 }
671804 });
......@@ -674,161 +807,251 @@ pub const Parser = struct {
674807 }
675808 },
676809
677 State.ExpectToken => |token_id| {
678 _ = (try self.eatToken(&stack, token_id)) ?? continue;
679 continue;
680 },
681810
682 State.ExpectTokenSave => |expect_token_save| {
683 *expect_token_save.ptr = (try self.eatToken(&stack, expect_token_save.id)) ?? continue;
684 continue;
685 },
811 State.VarDecl => |ctx| {
812 const var_decl = try self.createAttachNode(arena, ctx.list, ast.NodeVarDecl,
813 ast.NodeVarDecl {
814 .base = undefined,
815 .visib_token = ctx.visib_token,
816 .mut_token = ctx.mut_token,
817 .comptime_token = ctx.comptime_token,
818 .extern_export_token = ctx.extern_export_token,
819 .type_node = null,
820 .align_node = null,
821 .init_node = null,
822 .lib_name = ctx.lib_name,
823 // initialized later
824 .name_token = undefined,
825 .eq_token = undefined,
826 .semicolon_token = undefined,
827 }
828 );
686829
687 State.IfToken => |token_id| {
688 const token = self.getNextToken();
689 if (@TagType(Token.Id)(token.id) != token_id) {
690 self.putBackToken(token);
691 _ = stack.pop();
692 continue;
693 }
830 stack.append(State { .VarDeclAlign = var_decl }) catch unreachable;
831 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &var_decl.type_node} });
832 try stack.append(State { .IfToken = Token.Id.Colon });
833 try stack.append(State {
834 .ExpectTokenSave = ExpectTokenSave {
835 .id = Token.Id.Identifier,
836 .ptr = &var_decl.name_token,
837 }
838 });
694839 continue;
695840 },
841 State.VarDeclAlign => |var_decl| {
842 stack.append(State { .VarDeclEq = var_decl }) catch unreachable;
696843
697 State.IfTokenSave => |if_token_save| {
698 const token = self.getNextToken();
699 if (@TagType(Token.Id)(token.id) != if_token_save.id) {
700 self.putBackToken(token);
701 _ = stack.pop();
844 const next_token = self.getNextToken();
845 if (next_token.id == Token.Id.Keyword_align) {
846 try stack.append(State { .ExpectToken = Token.Id.RParen });
847 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.align_node} });
848 try stack.append(State { .ExpectToken = Token.Id.LParen });
702849 continue;
703850 }
704851
705 *if_token_save.ptr = token;
852 self.putBackToken(next_token);
706853 continue;
707854 },
708
709 State.Optional => { },
710
711 State.Expression => |dest_ptr| {
855 State.VarDeclEq => |var_decl| {
712856 const token = self.getNextToken();
713857 switch (token.id) {
714 Token.Id.Keyword_try => {
715 const node = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp.Try);
716 dest_ptr.store(&node.base);
717
718 stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }) catch unreachable;
719 continue;
720 },
721 Token.Id.Keyword_return => {
722 const node = try self.createControlFlowExpr(arena, token, ast.NodeControlFlowExpression.Kind.Return);
723 dest_ptr.store(&node.base);
724
858 Token.Id.Equal => {
859 var_decl.eq_token = token;
725860 stack.append(State {
726 .Optional = RevertState {
727 .parser = *self,
728 .tokenizer = *self.tokenizer,
729 .ptr = &node.rhs,
730 }
861 .ExpectTokenSave = ExpectTokenSave {
862 .id = Token.Id.Semicolon,
863 .ptr = &var_decl.semicolon_token,
864 },
731865 }) catch unreachable;
732 try stack.append(State { .Expression = DestPtr { .NullableField = &node.rhs } });
866 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.init_node } });
733867 continue;
734868 },
735 Token.Id.Keyword_break => {
736 const label = blk: {
737 const colon = self.getNextToken();
738 if (colon.id != Token.Id.Colon) {
739 self.putBackToken(colon);
740 break :blk null;
741 }
869 Token.Id.Semicolon => {
870 var_decl.semicolon_token = token;
871 continue;
872 },
873 else => {
874 return self.parseError(token, "expected '=' or ';', found {}", @tagName(token.id));
875 }
876 }
877 },
742878
743 break :blk (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
744 };
745879
746 const node = try self.createControlFlowExpr(arena, token,
747 ast.NodeControlFlowExpression.Kind {
748 .Break = label,
880 State.FnDef => |fn_proto| {
881 const token = self.getNextToken();
882 switch(token.id) {
883 Token.Id.LBrace => {
884 const block = try self.createNode(arena, ast.NodeBlock,
885 ast.NodeBlock {
886 .base = undefined,
887 .label = null,
888 .lbrace = token,
889 .statements = ArrayList(&ast.Node).init(arena),
890 .rbrace = undefined,
749891 }
750892 );
751 dest_ptr.store(&node.base);
893 fn_proto.body_node = &block.base;
894 stack.append(State { .Block = block }) catch unreachable;
895 continue;
896 },
897 Token.Id.Semicolon => continue,
898 else => {
899 return self.parseError(token, "expected ';' or '{{', found {}", @tagName(token.id));
900 },
901 }
902 },
903 State.FnProto => |fn_proto| {
904 stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable;
905 try stack.append(State { .ParamDecl = fn_proto });
906 try stack.append(State { .ExpectToken = Token.Id.LParen });
907
908 if (self.eatToken(Token.Id.Identifier)) |name_token| {
909 fn_proto.name_token = name_token;
910 }
911 continue;
912 },
913 State.FnProtoAlign => |fn_proto| {
914 stack.append(State { .FnProtoReturnType = fn_proto }) catch unreachable;
752915
916 if (self.eatToken(Token.Id.Keyword_align)) |align_token| {
917 try stack.append(State { .ExpectToken = Token.Id.RParen });
918 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &fn_proto.align_expr } });
919 try stack.append(State { .ExpectToken = Token.Id.LParen });
920 }
921 continue;
922 },
923 State.FnProtoReturnType => |fn_proto| {
924 const token = self.getNextToken();
925 switch (token.id) {
926 Token.Id.Bang => {
927 fn_proto.return_type = ast.NodeFnProto.ReturnType { .InferErrorSet = undefined };
753928 stack.append(State {
754 .Optional = RevertState {
755 .parser = *self,
756 .tokenizer = *self.tokenizer,
757 .ptr = &node.rhs,
758 }
929 .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.InferErrorSet },
759930 }) catch unreachable;
760 try stack.append(State { .Expression = DestPtr { .NullableField = &node.rhs } });
761931 continue;
762932 },
763 Token.Id.Keyword_continue => {
764 const label = blk: {
765 const colon = self.getNextToken();
766 if (colon.id != Token.Id.Colon) {
767 self.putBackToken(colon);
768 break :blk null;
933 else => {
934 // TODO: this is a special case. Remove this when #760 is fixed
935 if (token.id == Token.Id.Keyword_error) {
936 if (self.isPeekToken(Token.Id.LBrace)) {
937 fn_proto.return_type = ast.NodeFnProto.ReturnType {
938 .Explicit = &(try self.createLiteral(arena, ast.NodeErrorType, token)).base
939 };
940 continue;
769941 }
942 }
770943
771 break :blk (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
772 };
773
774 const node = try self.createControlFlowExpr(arena, token,
775 ast.NodeControlFlowExpression.Kind {
776 .Continue = label,
777 }
778 );
779 dest_ptr.store(&node.base);
944 self.putBackToken(token);
945 fn_proto.return_type = ast.NodeFnProto.ReturnType { .Explicit = undefined };
946 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.Explicit }, }) catch unreachable;
780947 continue;
781948 },
782 Token.Id.Keyword_cancel => {
783 const cancel_node = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp.Cancel);
784 dest_ptr.store(&cancel_node.base);
785 stack.append(State { .Expression = DestPtr { .Field = &cancel_node.rhs } }) catch unreachable;
786 },
787 Token.Id.Keyword_resume => {
788 const resume_node = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp.Resume);
789 dest_ptr.store(&resume_node.base);
790 stack.append(State { .Expression = DestPtr { .Field = &resume_node.rhs } }) catch unreachable;
791 },
792 Token.Id.Keyword_suspend => {
793 const node = try arena.create(ast.NodeSuspend);
794 *node = ast.NodeSuspend {
795 .base = self.initNode(ast.Node.Id.Suspend),
796 .suspend_token = token,
797 .payload = null,
798 .body = null,
799 };
800 dest_ptr.store(&node.base);
801 stack.append(State { .SuspendBody = node }) catch unreachable;
802 try stack.append(State { .Payload = &node.payload });
803 continue;
949 }
950 },
951
952
953 State.ParamDecl => |fn_proto| {
954 if (self.eatToken(Token.Id.RParen)) |_| {
955 continue;
956 }
957 const param_decl = try self.createAttachNode(arena, &fn_proto.params, ast.NodeParamDecl,
958 ast.NodeParamDecl {
959 .base = undefined,
960 .comptime_token = null,
961 .noalias_token = null,
962 .name_token = null,
963 .type_node = undefined,
964 .var_args_token = null,
804965 },
805 Token.Id.Keyword_if => {
806 const node = try arena.create(ast.NodeIf);
807 *node = ast.NodeIf {
808 .base = self.initNode(ast.Node.Id.If),
809 .if_token = token,
810 .condition = undefined,
811 .payload = null,
812 .body = undefined,
813 .@"else" = null,
814 };
815 dest_ptr.store(&node.base);
966 );
816967
817 stack.append(State { .Else = &node.@"else" }) catch unreachable;
818 try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
819 try stack.append(State { .PointerPayload = &node.payload });
820 try stack.append(State { .ExpectToken = Token.Id.RParen });
821 try stack.append(State { .Expression = DestPtr { .Field = &node.condition } });
822 try stack.append(State { .ExpectToken = Token.Id.LParen });
968 stack.append(State {
969 .ParamDeclEnd = ParamDeclEndCtx {
970 .param_decl = param_decl,
971 .fn_proto = fn_proto,
972 }
973 }) catch unreachable;
974 try stack.append(State { .ParamDeclName = param_decl });
975 try stack.append(State { .ParamDeclAliasOrComptime = param_decl });
976 continue;
977 },
978 State.ParamDeclAliasOrComptime => |param_decl| {
979 if (self.eatToken(Token.Id.Keyword_comptime)) |comptime_token| {
980 param_decl.comptime_token = comptime_token;
981 } else if (self.eatToken(Token.Id.Keyword_noalias)) |noalias_token| {
982 param_decl.noalias_token = noalias_token;
983 }
984 continue;
985 },
986 State.ParamDeclName => |param_decl| {
987 // TODO: Here, we eat two tokens in one state. This means that we can't have
988 // comments between these two tokens.
989 if (self.eatToken(Token.Id.Identifier)) |ident_token| {
990 if (self.eatToken(Token.Id.Colon)) |_| {
991 param_decl.name_token = ident_token;
992 } else {
993 self.putBackToken(ident_token);
994 }
995 }
996 continue;
997 },
998 State.ParamDeclEnd => |ctx| {
999 if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
1000 ctx.param_decl.var_args_token = ellipsis3;
1001 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
1002 continue;
1003 }
1004
1005 try stack.append(State { .ParamDeclComma = ctx.fn_proto });
1006 try stack.append(State {
1007 .TypeExprBegin = OptionalCtx { .Required = &ctx.param_decl.type_node }
1008 });
1009 continue;
1010 },
1011 State.ParamDeclComma => |fn_proto| {
1012 if ((try self.expectCommaOrEnd(Token.Id.RParen)) == null) {
1013 stack.append(State { .ParamDecl = fn_proto }) catch unreachable;
1014 }
1015 continue;
1016 },
1017
1018 State.MaybeLabeledExpression => |ctx| {
1019 if (self.eatToken(Token.Id.Colon)) |_| {
1020 stack.append(State {
1021 .LabeledExpression = LabelCtx {
1022 .label = ctx.label,
1023 .opt_ctx = ctx.opt_ctx,
1024 }
1025 }) catch unreachable;
1026 continue;
1027 }
1028
1029 _ = try self.createToCtxLiteral(arena, ctx.opt_ctx, ast.NodeIdentifier, ctx.label);
1030 continue;
1031 },
1032 State.LabeledExpression => |ctx| {
1033 const token = self.getNextToken();
1034 switch (token.id) {
1035 Token.Id.LBrace => {
1036 const block = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeBlock,
1037 ast.NodeBlock {
1038 .base = undefined,
1039 .label = ctx.label,
1040 .lbrace = token,
1041 .statements = ArrayList(&ast.Node).init(arena),
1042 .rbrace = undefined,
1043 }
1044 );
1045 stack.append(State { .Block = block }) catch unreachable;
8231046 continue;
8241047 },
8251048 Token.Id.Keyword_while => {
8261049 stack.append(State {
8271050 .While = LoopCtx {
828 .label = null,
1051 .label = ctx.label,
8291052 .inline_token = null,
8301053 .loop_token = token,
831 .dest_ptr = dest_ptr,
1054 .opt_ctx = ctx.opt_ctx.toRequired(),
8321055 }
8331056 }) catch unreachable;
8341057 continue;
......@@ -836,1670 +1059,1693 @@ pub const Parser = struct {
8361059 Token.Id.Keyword_for => {
8371060 stack.append(State {
8381061 .For = LoopCtx {
839 .label = null,
1062 .label = ctx.label,
8401063 .inline_token = null,
8411064 .loop_token = token,
842 .dest_ptr = dest_ptr,
1065 .opt_ctx = ctx.opt_ctx.toRequired(),
8431066 }
8441067 }) catch unreachable;
8451068 continue;
8461069 },
847 Token.Id.Keyword_switch => {
848 const node = try arena.create(ast.NodeSwitch);
849 *node = ast.NodeSwitch {
850 .base = self.initNode(ast.Node.Id.Switch),
851 .switch_token = token,
852 .expr = undefined,
853 .cases = ArrayList(&ast.NodeSwitchCase).init(arena),
854 .rbrace = undefined,
855 };
856 dest_ptr.store(&node.base);
857
1070 Token.Id.Keyword_inline => {
8581071 stack.append(State {
859 .SwitchCaseOrEnd = ListSave(&ast.NodeSwitchCase) {
860 .list = &node.cases,
861 .ptr = &node.rbrace,
862 },
1072 .Inline = InlineCtx {
1073 .label = ctx.label,
1074 .inline_token = token,
1075 .opt_ctx = ctx.opt_ctx.toRequired(),
1076 }
8631077 }) catch unreachable;
864 try stack.append(State { .ExpectToken = Token.Id.LBrace });
865 try stack.append(State { .ExpectToken = Token.Id.RParen });
866 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
867 try stack.append(State { .ExpectToken = Token.Id.LParen });
868 },
869 Token.Id.Keyword_comptime => {
870 const node = try arena.create(ast.NodeComptime);
871 *node = ast.NodeComptime {
872 .base = self.initNode(ast.Node.Id.Comptime),
873 .comptime_token = token,
874 .expr = undefined,
875 };
876 dest_ptr.store(&node.base);
877 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
8781078 continue;
8791079 },
880 Token.Id.LBrace => {
881 const block = try self.createBlock(arena, (?Token)(null), token);
882 dest_ptr.store(&block.base);
1080 else => {
1081 if (ctx.opt_ctx != OptionalCtx.Optional) {
1082 return self.parseError(token, "expected 'while', 'for', 'inline' or '{{', found {}", @tagName(token.id));
1083 }
8831084
884 stack.append(State { .Block = block }) catch unreachable;
1085 self.putBackToken(token);
1086 continue;
1087 },
1088 }
1089 },
1090 State.Inline => |ctx| {
1091 const token = self.getNextToken();
1092 switch (token.id) {
1093 Token.Id.Keyword_while => {
1094 stack.append(State {
1095 .While = LoopCtx {
1096 .inline_token = ctx.inline_token,
1097 .label = ctx.label,
1098 .loop_token = token,
1099 .opt_ctx = ctx.opt_ctx.toRequired(),
1100 }
1101 }) catch unreachable;
1102 continue;
1103 },
1104 Token.Id.Keyword_for => {
1105 stack.append(State {
1106 .For = LoopCtx {
1107 .inline_token = ctx.inline_token,
1108 .label = ctx.label,
1109 .loop_token = token,
1110 .opt_ctx = ctx.opt_ctx.toRequired(),
1111 }
1112 }) catch unreachable;
8851113 continue;
8861114 },
8871115 else => {
1116 if (ctx.opt_ctx != OptionalCtx.Optional) {
1117 return self.parseError(token, "expected 'while' or 'for', found {}", @tagName(token.id));
1118 }
1119
8881120 self.putBackToken(token);
889 stack.append(State { .UnwrapExpressionBegin = dest_ptr }) catch unreachable;
8901121 continue;
891 }
1122 },
8921123 }
8931124 },
894
895 State.RangeExpressionBegin => |dest_ptr| {
896 stack.append(State { .RangeExpressionEnd = dest_ptr }) catch unreachable;
897 try stack.append(State { .Expression = dest_ptr });
1125 State.While => |ctx| {
1126 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeWhile,
1127 ast.NodeWhile {
1128 .base = undefined,
1129 .label = ctx.label,
1130 .inline_token = ctx.inline_token,
1131 .while_token = ctx.loop_token,
1132 .condition = undefined,
1133 .payload = null,
1134 .continue_expr = null,
1135 .body = undefined,
1136 .@"else" = null,
1137 }
1138 );
1139 stack.append(State { .Else = &node.@"else" }) catch unreachable;
1140 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
1141 try stack.append(State { .WhileContinueExpr = &node.continue_expr });
1142 try stack.append(State { .IfToken = Token.Id.Colon });
1143 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
1144 try stack.append(State { .ExpectToken = Token.Id.RParen });
1145 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
1146 try stack.append(State { .ExpectToken = Token.Id.LParen });
8981147 continue;
8991148 },
900
901 State.RangeExpressionEnd => |dest_ptr| {
902 const token = self.getNextToken();
903 if (token.id == Token.Id.Ellipsis3) {
904 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.Range);
905 node.lhs = dest_ptr.get();
906 dest_ptr.store(&node.base);
907
908 stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }) catch unreachable;
909 continue;
910 } else {
911 self.putBackToken(token);
912 continue;
913 }
1149 State.WhileContinueExpr => |dest| {
1150 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
1151 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = dest } });
1152 try stack.append(State { .ExpectToken = Token.Id.LParen });
1153 continue;
9141154 },
915
916 State.AssignmentExpressionBegin => |dest_ptr| {
917 stack.append(State { .AssignmentExpressionEnd = dest_ptr }) catch unreachable;
918 try stack.append(State { .Expression = dest_ptr });
1155 State.For => |ctx| {
1156 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeFor,
1157 ast.NodeFor {
1158 .base = undefined,
1159 .label = ctx.label,
1160 .inline_token = ctx.inline_token,
1161 .for_token = ctx.loop_token,
1162 .array_expr = undefined,
1163 .payload = null,
1164 .body = undefined,
1165 .@"else" = null,
1166 }
1167 );
1168 stack.append(State { .Else = &node.@"else" }) catch unreachable;
1169 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
1170 try stack.append(State { .PointerIndexPayload = OptionalCtx { .Optional = &node.payload } });
1171 try stack.append(State { .ExpectToken = Token.Id.RParen });
1172 try stack.append(State { .Expression = OptionalCtx { .Required = &node.array_expr } });
1173 try stack.append(State { .ExpectToken = Token.Id.LParen });
9191174 continue;
9201175 },
1176 State.Else => |dest| {
1177 if (self.eatToken(Token.Id.Keyword_else)) |else_token| {
1178 const node = try self.createNode(arena, ast.NodeElse,
1179 ast.NodeElse {
1180 .base = undefined,
1181 .else_token = else_token,
1182 .payload = null,
1183 .body = undefined,
1184 }
1185 );
1186 *dest = node;
9211187
922 State.AssignmentExpressionEnd => |dest_ptr| {
923 const token = self.getNextToken();
924 if (tokenIdToAssignment(token.id)) |ass_id| {
925 const node = try self.createInfixOp(arena, token, ass_id);
926 node.lhs = dest_ptr.get();
927 dest_ptr.store(&node.base);
928
929 stack.append(State { .AssignmentExpressionEnd = dest_ptr }) catch unreachable;
930 try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } });
1188 stack.append(State { .Expression = OptionalCtx { .Required = &node.body } }) catch unreachable;
1189 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
9311190 continue;
9321191 } else {
933 self.putBackToken(token);
9341192 continue;
9351193 }
9361194 },
9371195
938 State.UnwrapExpressionBegin => |dest_ptr| {
939 stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable;
940 try stack.append(State { .BoolOrExpressionBegin = dest_ptr });
941 continue;
942 },
9431196
944 State.UnwrapExpressionEnd => |dest_ptr| {
1197 State.Block => |block| {
9451198 const token = self.getNextToken();
9461199 switch (token.id) {
947 Token.Id.Keyword_catch => {
948 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp { .Catch = null });
949 node.lhs = dest_ptr.get();
950 dest_ptr.store(&node.base);
951
952 stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable;
953 try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } });
954 try stack.append(State { .Payload = &node.op.Catch });
955 continue;
956 },
957 Token.Id.QuestionMarkQuestionMark => {
958 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.UnwrapMaybe);
959 node.lhs = dest_ptr.get();
960 dest_ptr.store(&node.base);
961
962 stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable;
963 try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } });
1200 Token.Id.RBrace => {
1201 block.rbrace = token;
9641202 continue;
9651203 },
9661204 else => {
9671205 self.putBackToken(token);
1206 stack.append(State { .Block = block }) catch unreachable;
1207 try stack.append(State { .Statement = block });
9681208 continue;
9691209 },
9701210 }
9711211 },
972
973 State.BoolOrExpressionBegin => |dest_ptr| {
974 stack.append(State { .BoolOrExpressionEnd = dest_ptr }) catch unreachable;
975 try stack.append(State { .BoolAndExpressionBegin = dest_ptr });
976 continue;
977 },
978
979 State.BoolOrExpressionEnd => |dest_ptr| {
1212 State.Statement => |block| {
9801213 const token = self.getNextToken();
9811214 switch (token.id) {
982 Token.Id.Keyword_or => {
983 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BoolOr);
984 node.lhs = dest_ptr.get();
985 dest_ptr.store(&node.base);
986
987 stack.append(State { .BoolOrExpressionEnd = dest_ptr }) catch unreachable;
988 try stack.append(State { .BoolAndExpressionBegin = DestPtr { .Field = &node.rhs } });
1215 Token.Id.Keyword_comptime => {
1216 stack.append(State {
1217 .ComptimeStatement = ComptimeStatementCtx {
1218 .comptime_token = token,
1219 .block = block,
1220 }
1221 }) catch unreachable;
1222 continue;
1223 },
1224 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1225 stack.append(State {
1226 .VarDecl = VarDeclCtx {
1227 .visib_token = null,
1228 .comptime_token = null,
1229 .extern_export_token = null,
1230 .lib_name = null,
1231 .mut_token = token,
1232 .list = &block.statements,
1233 }
1234 }) catch unreachable;
1235 continue;
1236 },
1237 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
1238 const node = try self.createAttachNode(arena, &block.statements, ast.NodeDefer,
1239 ast.NodeDefer {
1240 .base = undefined,
1241 .defer_token = token,
1242 .kind = switch (token.id) {
1243 Token.Id.Keyword_defer => ast.NodeDefer.Kind.Unconditional,
1244 Token.Id.Keyword_errdefer => ast.NodeDefer.Kind.Error,
1245 else => unreachable,
1246 },
1247 .expr = undefined,
1248 }
1249 );
1250 stack.append(State { .Semicolon = &&node.base }) catch unreachable;
1251 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
1252 continue;
1253 },
1254 Token.Id.LBrace => {
1255 const inner_block = try self.createAttachNode(arena, &block.statements, ast.NodeBlock,
1256 ast.NodeBlock {
1257 .base = undefined,
1258 .label = null,
1259 .lbrace = token,
1260 .statements = ArrayList(&ast.Node).init(arena),
1261 .rbrace = undefined,
1262 }
1263 );
1264 stack.append(State { .Block = inner_block }) catch unreachable;
9891265 continue;
9901266 },
9911267 else => {
9921268 self.putBackToken(token);
1269 const statememt = try block.statements.addOne();
1270 stack.append(State { .Semicolon = statememt }) catch unreachable;
1271 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx{ .Required = statememt } });
9931272 continue;
994 },
1273 }
9951274 }
9961275 },
997
998 State.BoolAndExpressionBegin => |dest_ptr| {
999 stack.append(State { .BoolAndExpressionEnd = dest_ptr }) catch unreachable;
1000 try stack.append(State { .ComparisonExpressionBegin = dest_ptr });
1001 continue;
1002 },
1003
1004 State.BoolAndExpressionEnd => |dest_ptr| {
1276 State.ComptimeStatement => |ctx| {
10051277 const token = self.getNextToken();
10061278 switch (token.id) {
1007 Token.Id.Keyword_and => {
1008 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BoolAnd);
1009 node.lhs = dest_ptr.get();
1010 dest_ptr.store(&node.base);
1011
1012 stack.append(State { .BoolAndExpressionEnd = dest_ptr }) catch unreachable;
1013 try stack.append(State { .ComparisonExpressionBegin = DestPtr { .Field = &node.rhs } });
1279 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1280 stack.append(State {
1281 .VarDecl = VarDeclCtx {
1282 .visib_token = null,
1283 .comptime_token = ctx.comptime_token,
1284 .extern_export_token = null,
1285 .lib_name = null,
1286 .mut_token = token,
1287 .list = &ctx.block.statements,
1288 }
1289 }) catch unreachable;
10141290 continue;
10151291 },
10161292 else => {
10171293 self.putBackToken(token);
1294 self.putBackToken(ctx.comptime_token);
1295 const statememt = try ctx.block.statements.addOne();
1296 stack.append(State { .Semicolon = statememt }) catch unreachable;
1297 try stack.append(State { .Expression = OptionalCtx { .Required = statememt } });
10181298 continue;
1019 },
1299 }
10201300 }
10211301 },
1022
1023 State.ComparisonExpressionBegin => |dest_ptr| {
1024 stack.append(State { .ComparisonExpressionEnd = dest_ptr }) catch unreachable;
1025 try stack.append(State { .BinaryOrExpressionBegin = dest_ptr });
1302 State.Semicolon => |node_ptr| {
1303 const node = *node_ptr;
1304 if (requireSemiColon(node)) {
1305 stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable;
1306 continue;
1307 }
10261308 continue;
10271309 },
10281310
1029 State.ComparisonExpressionEnd => |dest_ptr| {
1030 const token = self.getNextToken();
1031 if (tokenIdToComparison(token.id)) |comp_id| {
1032 const node = try self.createInfixOp(arena, token, comp_id);
1033 node.lhs = dest_ptr.get();
1034 dest_ptr.store(&node.base);
10351311
1036 stack.append(State { .ComparisonExpressionEnd = dest_ptr }) catch unreachable;
1037 try stack.append(State { .BinaryOrExpressionBegin = DestPtr { .Field = &node.rhs } });
1038 continue;
1039 } else {
1040 self.putBackToken(token);
1312 State.AsmOutputItems => |items| {
1313 const lbracket = self.getNextToken();
1314 if (lbracket.id != Token.Id.LBracket) {
1315 self.putBackToken(lbracket);
10411316 continue;
10421317 }
1043 },
10441318
1045 State.BinaryOrExpressionBegin => |dest_ptr| {
1046 stack.append(State { .BinaryOrExpressionEnd = dest_ptr }) catch unreachable;
1047 try stack.append(State { .BinaryXorExpressionBegin = dest_ptr });
1319 const node = try self.createNode(arena, ast.NodeAsmOutput,
1320 ast.NodeAsmOutput {
1321 .base = undefined,
1322 .symbolic_name = undefined,
1323 .constraint = undefined,
1324 .kind = undefined,
1325 }
1326 );
1327 try items.append(node);
1328
1329 stack.append(State { .AsmOutputItems = items }) catch unreachable;
1330 try stack.append(State { .IfToken = Token.Id.Comma });
1331 try stack.append(State { .ExpectToken = Token.Id.RParen });
1332 try stack.append(State { .AsmOutputReturnOrType = node });
1333 try stack.append(State { .ExpectToken = Token.Id.LParen });
1334 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1335 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1336 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
10481337 continue;
10491338 },
1050
1051 State.BinaryOrExpressionEnd => |dest_ptr| {
1339 State.AsmOutputReturnOrType => |node| {
10521340 const token = self.getNextToken();
10531341 switch (token.id) {
1054 Token.Id.Pipe => {
1055 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BitOr);
1056 node.lhs = dest_ptr.get();
1057 dest_ptr.store(&node.base);
1058
1059 stack.append(State { .BinaryOrExpressionEnd = dest_ptr }) catch unreachable;
1060 try stack.append(State { .BinaryXorExpressionBegin = DestPtr { .Field = &node.rhs } });
1342 Token.Id.Identifier => {
1343 node.kind = ast.NodeAsmOutput.Kind { .Variable = try self.createLiteral(arena, ast.NodeIdentifier, token) };
10611344 continue;
10621345 },
1063 else => {
1064 self.putBackToken(token);
1346 Token.Id.Arrow => {
1347 node.kind = ast.NodeAsmOutput.Kind { .Return = undefined };
1348 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.kind.Return } });
10651349 continue;
10661350 },
1351 else => {
1352 return self.parseError(token, "expected '->' or {}, found {}",
1353 @tagName(Token.Id.Identifier),
1354 @tagName(token.id));
1355 },
10671356 }
10681357 },
1358 State.AsmInputItems => |items| {
1359 const lbracket = self.getNextToken();
1360 if (lbracket.id != Token.Id.LBracket) {
1361 self.putBackToken(lbracket);
1362 continue;
1363 }
10691364
1070 State.BinaryXorExpressionBegin => |dest_ptr| {
1071 stack.append(State { .BinaryXorExpressionEnd = dest_ptr }) catch unreachable;
1072 try stack.append(State { .BinaryAndExpressionBegin = dest_ptr });
1365 const node = try self.createNode(arena, ast.NodeAsmInput,
1366 ast.NodeAsmInput {
1367 .base = undefined,
1368 .symbolic_name = undefined,
1369 .constraint = undefined,
1370 .expr = undefined,
1371 }
1372 );
1373 try items.append(node);
1374
1375 stack.append(State { .AsmInputItems = items }) catch unreachable;
1376 try stack.append(State { .IfToken = Token.Id.Comma });
1377 try stack.append(State { .ExpectToken = Token.Id.RParen });
1378 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
1379 try stack.append(State { .ExpectToken = Token.Id.LParen });
1380 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.constraint } });
1381 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1382 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.symbolic_name } });
1383 continue;
1384 },
1385 State.AsmClopperItems => |items| {
1386 stack.append(State { .AsmClopperItems = items }) catch unreachable;
1387 try stack.append(State { .IfToken = Token.Id.Comma });
1388 try stack.append(State { .StringLiteral = OptionalCtx { .Required = try items.addOne() } });
10731389 continue;
10741390 },
10751391
1076 State.BinaryXorExpressionEnd => |dest_ptr| {
1077 const token = self.getNextToken();
1078 switch (token.id) {
1079 Token.Id.Caret => {
1080 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BitXor);
1081 node.lhs = dest_ptr.get();
1082 dest_ptr.store(&node.base);
10831392
1084 stack.append(State { .BinaryXorExpressionEnd = dest_ptr }) catch unreachable;
1085 try stack.append(State { .BinaryAndExpressionBegin = DestPtr { .Field = &node.rhs } });
1086 continue;
1087 },
1088 else => {
1089 self.putBackToken(token);
1090 continue;
1091 },
1393 State.ExprListItemOrEnd => |list_state| {
1394 if (self.eatToken(list_state.end)) |token| {
1395 *list_state.ptr = token;
1396 continue;
10921397 }
1093 },
10941398
1095 State.BinaryAndExpressionBegin => |dest_ptr| {
1096 stack.append(State { .BinaryAndExpressionEnd = dest_ptr }) catch unreachable;
1097 try stack.append(State { .BitShiftExpressionBegin = dest_ptr });
1399 stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable;
1400 try stack.append(State { .Expression = OptionalCtx { .Required = try list_state.list.addOne() } });
10981401 continue;
10991402 },
1100
1101 State.BinaryAndExpressionEnd => |dest_ptr| {
1102 const token = self.getNextToken();
1103 switch (token.id) {
1104 Token.Id.Ampersand => {
1105 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BitAnd);
1106 node.lhs = dest_ptr.get();
1107 dest_ptr.store(&node.base);
1108
1109 stack.append(State { .BinaryAndExpressionEnd = dest_ptr }) catch unreachable;
1110 try stack.append(State { .BitShiftExpressionBegin = DestPtr { .Field = &node.rhs } });
1111 continue;
1112 },
1113 else => {
1114 self.putBackToken(token);
1115 continue;
1116 },
1403 State.ExprListCommaOrEnd => |list_state| {
1404 if (try self.expectCommaOrEnd(list_state.end)) |end| {
1405 *list_state.ptr = end;
1406 continue;
1407 } else {
1408 stack.append(State { .ExprListItemOrEnd = list_state }) catch unreachable;
1409 continue;
11171410 }
11181411 },
1412 State.FieldInitListItemOrEnd => |list_state| {
1413 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1414 *list_state.ptr = rbrace;
1415 continue;
1416 }
1417
1418 const node = try self.createNode(arena, ast.NodeFieldInitializer,
1419 ast.NodeFieldInitializer {
1420 .base = undefined,
1421 .period_token = undefined,
1422 .name_token = undefined,
1423 .expr = undefined,
1424 }
1425 );
1426 try list_state.list.append(node);
11191427
1120 State.BitShiftExpressionBegin => |dest_ptr| {
1121 stack.append(State { .BitShiftExpressionEnd = dest_ptr }) catch unreachable;
1122 try stack.append(State { .AdditionExpressionBegin = dest_ptr });
1428 stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
1429 try stack.append(State { .Expression = OptionalCtx{ .Required = &node.expr } });
1430 try stack.append(State { .ExpectToken = Token.Id.Equal });
1431 try stack.append(State {
1432 .ExpectTokenSave = ExpectTokenSave {
1433 .id = Token.Id.Identifier,
1434 .ptr = &node.name_token,
1435 }
1436 });
1437 try stack.append(State {
1438 .ExpectTokenSave = ExpectTokenSave {
1439 .id = Token.Id.Period,
1440 .ptr = &node.period_token,
1441 }
1442 });
11231443 continue;
11241444 },
1125
1126 State.BitShiftExpressionEnd => |dest_ptr| {
1127 const token = self.getNextToken();
1128 if (tokenIdToBitShift(token.id)) |bitshift_id| {
1129 const node = try self.createInfixOp(arena, token, bitshift_id);
1130 node.lhs = dest_ptr.get();
1131 dest_ptr.store(&node.base);
1132
1133 stack.append(State { .BitShiftExpressionEnd = dest_ptr }) catch unreachable;
1134 try stack.append(State { .AdditionExpressionBegin = DestPtr { .Field = &node.rhs } });
1445 State.FieldInitListCommaOrEnd => |list_state| {
1446 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1447 *list_state.ptr = end;
11351448 continue;
11361449 } else {
1137 self.putBackToken(token);
1450 stack.append(State { .FieldInitListItemOrEnd = list_state }) catch unreachable;
1451 continue;
1452 }
1453 },
1454 State.FieldListCommaOrEnd => |container_decl| {
1455 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1456 container_decl.rbrace_token = end;
1457 continue;
1458 } else {
1459 stack.append(State { .ContainerDecl = container_decl }) catch unreachable;
11381460 continue;
11391461 }
11401462 },
1463 State.IdentifierListItemOrEnd => |list_state| {
1464 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1465 *list_state.ptr = rbrace;
1466 continue;
1467 }
11411468
1142 State.AdditionExpressionBegin => |dest_ptr| {
1143 stack.append(State { .AdditionExpressionEnd = dest_ptr }) catch unreachable;
1144 try stack.append(State { .MultiplyExpressionBegin = dest_ptr });
1469 stack.append(State { .IdentifierListCommaOrEnd = list_state }) catch unreachable;
1470 try stack.append(State { .Identifier = OptionalCtx { .Required = try list_state.list.addOne() } });
11451471 continue;
11461472 },
1147
1148 State.AdditionExpressionEnd => |dest_ptr| {
1149 const token = self.getNextToken();
1150 if (tokenIdToAddition(token.id)) |add_id| {
1151 const node = try self.createInfixOp(arena, token, add_id);
1152 node.lhs = dest_ptr.get();
1153 dest_ptr.store(&node.base);
1154
1155 stack.append(State { .AdditionExpressionEnd = dest_ptr }) catch unreachable;
1156 try stack.append(State { .MultiplyExpressionBegin = DestPtr { .Field = &node.rhs } });
1473 State.IdentifierListCommaOrEnd => |list_state| {
1474 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1475 *list_state.ptr = end;
11571476 continue;
11581477 } else {
1159 self.putBackToken(token);
1478 stack.append(State { .IdentifierListItemOrEnd = list_state }) catch unreachable;
11601479 continue;
11611480 }
11621481 },
1482 State.SwitchCaseOrEnd => |list_state| {
1483 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
1484 *list_state.ptr = rbrace;
1485 continue;
1486 }
11631487
1164 State.MultiplyExpressionBegin => |dest_ptr| {
1165 stack.append(State { .MultiplyExpressionEnd = dest_ptr }) catch unreachable;
1166 try stack.append(State { .CurlySuffixExpressionBegin = dest_ptr });
1488 const node = try self.createNode(arena, ast.NodeSwitchCase,
1489 ast.NodeSwitchCase {
1490 .base = undefined,
1491 .items = ArrayList(&ast.Node).init(arena),
1492 .payload = null,
1493 .expr = undefined,
1494 }
1495 );
1496 try list_state.list.append(node);
1497 stack.append(State { .SwitchCaseCommaOrEnd = list_state }) catch unreachable;
1498 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .Required = &node.expr } });
1499 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
1500 try stack.append(State { .SwitchCaseFirstItem = &node.items });
11671501 continue;
11681502 },
1169
1170 State.MultiplyExpressionEnd => |dest_ptr| {
1503 State.SwitchCaseCommaOrEnd => |list_state| {
1504 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1505 *list_state.ptr = end;
1506 continue;
1507 } else {
1508 stack.append(State { .SwitchCaseOrEnd = list_state }) catch unreachable;
1509 continue;
1510 }
1511 },
1512 State.SwitchCaseFirstItem => |case_items| {
11711513 const token = self.getNextToken();
1172 if (tokenIdToMultiply(token.id)) |mult_id| {
1173 const node = try self.createInfixOp(arena, token, mult_id);
1174 node.lhs = dest_ptr.get();
1175 dest_ptr.store(&node.base);
1176
1177 stack.append(State { .MultiplyExpressionEnd = dest_ptr }) catch unreachable;
1178 try stack.append(State { .CurlySuffixExpressionBegin = DestPtr { .Field = &node.rhs } });
1514 if (token.id == Token.Id.Keyword_else) {
1515 const else_node = try self.createAttachNode(arena, case_items, ast.NodeSwitchElse,
1516 ast.NodeSwitchElse {
1517 .base = undefined,
1518 .token = token,
1519 }
1520 );
1521 try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
11791522 continue;
11801523 } else {
11811524 self.putBackToken(token);
1525 try stack.append(State { .SwitchCaseItem = case_items });
11821526 continue;
11831527 }
11841528 },
1185
1186 State.CurlySuffixExpressionBegin => |dest_ptr| {
1187 stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;
1188 try stack.append(State { .TypeExprBegin = dest_ptr });
1529 State.SwitchCaseItem => |case_items| {
1530 stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
1531 try stack.append(State { .RangeExpressionBegin = OptionalCtx { .Required = try case_items.addOne() } });
1532 },
1533 State.SwitchCaseItemCommaOrEnd => |case_items| {
1534 if ((try self.expectCommaOrEnd(Token.Id.EqualAngleBracketRight)) == null) {
1535 stack.append(State { .SwitchCaseItem = case_items }) catch unreachable;
1536 }
11891537 continue;
11901538 },
11911539
1192 State.CurlySuffixExpressionEnd => |dest_ptr| {
1193 const token = self.getNextToken();
1194 if (token.id != Token.Id.LBrace) {
1195 self.putBackToken(token);
1540
1541 State.SuspendBody => |suspend_node| {
1542 if (suspend_node.payload != null) {
1543 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = &suspend_node.body } });
1544 }
1545 continue;
1546 },
1547 State.AsyncAllocator => |async_node| {
1548 if (self.eatToken(Token.Id.AngleBracketLeft) == null) {
11961549 continue;
11971550 }
11981551
1199 const next = self.getNextToken();
1200 switch (next.id) {
1201 Token.Id.Period => {
1202 const node = try self.createSuffixOp(arena, ast.NodeSuffixOp.SuffixOp {
1203 .StructInitializer = ArrayList(&ast.NodeFieldInitializer).init(arena),
1204 });
1205 node.lhs = dest_ptr.get();
1206 dest_ptr.store(&node.base);
1552 async_node.rangle_bracket = Token(undefined);
1553 try stack.append(State {
1554 .ExpectTokenSave = ExpectTokenSave {
1555 .id = Token.Id.AngleBracketRight,
1556 .ptr = &??async_node.rangle_bracket,
1557 }
1558 });
1559 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &async_node.allocator_type } });
1560 continue;
1561 },
1562 State.AsyncEnd => |ctx| {
1563 const node = ctx.ctx.get() ?? continue;
12071564
1208 stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;
1209 try stack.append(State {
1210 .FieldInitListItemOrEnd = ListSave(&ast.NodeFieldInitializer) {
1211 .list = &node.op.StructInitializer,
1212 .ptr = &node.rtoken,
1213 }
1214 });
1215 self.putBackToken(next);
1565 switch (node.id) {
1566 ast.Node.Id.FnProto => {
1567 const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", node);
1568 fn_proto.async_attr = ctx.attribute;
12161569 continue;
12171570 },
1218 else => {
1219 const node = try self.createSuffixOp(arena, ast.NodeSuffixOp.SuffixOp {
1220 .ArrayInitializer = ArrayList(&ast.Node).init(arena),
1221 });
1222 node.lhs = dest_ptr.get();
1223 dest_ptr.store(&node.base);
1571 ast.Node.Id.SuffixOp => {
1572 const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", node);
1573 if (suffix_op.op == ast.NodeSuffixOp.SuffixOp.Call) {
1574 suffix_op.op.Call.async_attr = ctx.attribute;
1575 continue;
1576 }
12241577
1225 stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;
1226 try stack.append(State {
1227 .ExprListItemOrEnd = ExprListCtx {
1228 .list = &node.op.ArrayInitializer,
1229 .end = Token.Id.RBrace,
1230 .ptr = &node.rtoken,
1231 }
1232 });
1233 self.putBackToken(next);
1234 continue;
1578 return self.parseError(node.firstToken(), "expected {}, found {}.",
1579 @tagName(ast.NodeSuffixOp.SuffixOp.Call),
1580 @tagName(suffix_op.op));
12351581 },
1582 else => {
1583 return self.parseError(node.firstToken(), "expected {} or {}, found {}.",
1584 @tagName(ast.NodeSuffixOp.SuffixOp.Call),
1585 @tagName(ast.Node.Id.FnProto),
1586 @tagName(node.id));
1587 }
12361588 }
12371589 },
12381590
1239 State.TypeExprBegin => |dest_ptr| {
1240 stack.append(State { .TypeExprEnd = dest_ptr }) catch unreachable;
1241 try stack.append(State { .PrefixOpExpression = dest_ptr });
1242 continue;
1243 },
12441591
1245 State.TypeExprEnd => |dest_ptr| {
1246 const token = self.getNextToken();
1247 switch (token.id) {
1248 Token.Id.Bang => {
1249 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.ErrorUnion);
1250 node.lhs = dest_ptr.get();
1251 dest_ptr.store(&node.base);
1592 State.ExternType => |ctx| {
1593 if (self.eatToken(Token.Id.Keyword_fn)) |fn_token| {
1594 const fn_proto = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeFnProto,
1595 ast.NodeFnProto {
1596 .base = undefined,
1597 .visib_token = null,
1598 .name_token = null,
1599 .fn_token = fn_token,
1600 .params = ArrayList(&ast.Node).init(arena),
1601 .return_type = undefined,
1602 .var_args_token = null,
1603 .extern_export_inline_token = ctx.extern_token,
1604 .cc_token = null,
1605 .async_attr = null,
1606 .body_node = null,
1607 .lib_name = null,
1608 .align_expr = null,
1609 }
1610 );
1611 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1612 continue;
1613 }
12521614
1253 stack.append(State { .TypeExprEnd = dest_ptr }) catch unreachable;
1254 try stack.append(State { .PrefixOpExpression = DestPtr { .Field = &node.rhs } });
1255 continue;
1256 },
1257 else => {
1258 self.putBackToken(token);
1259 continue;
1615 stack.append(State {
1616 .ContainerKind = ContainerKindCtx {
1617 .opt_ctx = ctx.opt_ctx,
1618 .ltoken = ctx.extern_token,
1619 .layout = ast.NodeContainerDecl.Layout.Extern,
12601620 },
1261 }
1621 }) catch unreachable;
1622 continue;
12621623 },
1263
1264 State.PrefixOpExpression => |dest_ptr| {
1265 const token = self.getNextToken();
1266 if (tokenIdToPrefixOp(token.id)) |prefix_id| {
1267 const node = try self.createPrefixOp(arena, token, prefix_id);
1268 dest_ptr.store(&node.base);
1269
1270 stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable;
1271 if (node.op == ast.NodePrefixOp.PrefixOp.AddrOf) {
1272 try stack.append(State { .AddrOfModifiers = &node.op.AddrOf });
1273 }
1274 continue;
1275 } else {
1276 self.putBackToken(token);
1277 stack.append(State { .SuffixOpExpressionBegin = dest_ptr }) catch unreachable;
1278 continue;
1279 }
1280 },
1281
1282 State.SuffixOpExpressionBegin => |dest_ptr| {
1283 const token = self.getNextToken();
1624 State.SliceOrArrayAccess => |node| {
1625 var token = self.getNextToken();
12841626 switch (token.id) {
1285 Token.Id.Keyword_async => {
1286 const async_node = try arena.create(ast.NodeAsyncAttribute);
1287 *async_node = ast.NodeAsyncAttribute {
1288 .base = self.initNode(ast.Node.Id.AsyncAttribute),
1289 .async_token = token,
1290 .allocator_type = null,
1291 .rangle_bracket = null,
1627 Token.Id.Ellipsis2 => {
1628 const start = node.op.ArrayAccess;
1629 node.op = ast.NodeSuffixOp.SuffixOp {
1630 .Slice = ast.NodeSuffixOp.SliceRange {
1631 .start = start,
1632 .end = null,
1633 }
12921634 };
12931635
12941636 stack.append(State {
1295 .AsyncEnd = AsyncEndCtx {
1296 .dest_ptr = dest_ptr,
1297 .attribute = async_node,
1298 }
1299 }) catch unreachable;
1300 try stack.append(State { .SuffixOpExpressionEnd = dest_ptr });
1301 try stack.append(State { .PrimaryExpression = dest_ptr });
1302
1303 const langle_bracket = self.getNextToken();
1304 if (langle_bracket.id != Token.Id.AngleBracketLeft) {
1305 self.putBackToken(langle_bracket);
1306 continue;
1307 }
1308
1309 async_node.rangle_bracket = Token(undefined);
1310 try stack.append(State {
13111637 .ExpectTokenSave = ExpectTokenSave {
1312 .id = Token.Id.AngleBracketRight,
1313 .ptr = &??async_node.rangle_bracket,
1314 }
1315 });
1316 try stack.append(State { .TypeExprBegin = DestPtr { .NullableField = &async_node.allocator_type } });
1317 continue;
1318 },
1319 else => {
1320 self.putBackToken(token);
1321 stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
1322 try stack.append(State { .PrimaryExpression = dest_ptr });
1323 continue;
1324 }
1325 }
1326 },
1327
1328 State.SuffixOpExpressionEnd => |dest_ptr| {
1329 const token = self.getNextToken();
1330 switch (token.id) {
1331 Token.Id.LParen => {
1332 const node = try self.createSuffixOp(arena, ast.NodeSuffixOp.SuffixOp {
1333 .Call = ast.NodeSuffixOp.CallInfo {
1334 .params = ArrayList(&ast.Node).init(arena),
1335 .async_attr = null,
1336 }
1337 });
1338 node.lhs = dest_ptr.get();
1339 dest_ptr.store(&node.base);
1340
1341 stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
1342 try stack.append(State {
1343 .ExprListItemOrEnd = ExprListCtx {
1344 .list = &node.op.Call.params,
1345 .end = Token.Id.RParen,
1638 .id = Token.Id.RBracket,
13461639 .ptr = &node.rtoken,
13471640 }
1348 });
1349 continue;
1350 },
1351 Token.Id.LBracket => {
1352 const node = try arena.create(ast.NodeSuffixOp);
1353 *node = ast.NodeSuffixOp {
1354 .base = self.initNode(ast.Node.Id.SuffixOp),
1355 .lhs = undefined,
1356 .op = ast.NodeSuffixOp.SuffixOp {
1357 .ArrayAccess = undefined,
1358 },
1359 .rtoken = undefined,
1360 };
1361 node.lhs = dest_ptr.get();
1362 dest_ptr.store(&node.base);
1363
1364 stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
1365 try stack.append(State { .SliceOrArrayAccess = node });
1366 try stack.append(State { .Expression = DestPtr { .Field = &node.op.ArrayAccess }});
1641 }) catch unreachable;
1642 try stack.append(State { .Expression = OptionalCtx { .Optional = &node.op.Slice.end } });
13671643 continue;
13681644 },
1369 Token.Id.Period => {
1370 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.Period);
1371 node.lhs = dest_ptr.get();
1372 dest_ptr.store(&node.base);
1373
1374 stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
1375 try stack.append(State { .SuffixOpExpressionBegin = DestPtr { .Field = &node.rhs }});
1645 Token.Id.RBracket => {
1646 node.rtoken = token;
13761647 continue;
13771648 },
13781649 else => {
1379 self.putBackToken(token);
1380 continue;
1381 },
1650 return self.parseError(token, "expected ']' or '..', found {}", @tagName(token.id));
1651 }
13821652 }
13831653 },
1654 State.SliceOrArrayType => |node| {
1655 if (self.eatToken(Token.Id.RBracket)) |_| {
1656 node.op = ast.NodePrefixOp.PrefixOp {
1657 .SliceType = ast.NodePrefixOp.AddrOfInfo {
1658 .align_expr = null,
1659 .bit_offset_start_token = null,
1660 .bit_offset_end_token = null,
1661 .const_token = null,
1662 .volatile_token = null,
1663 }
1664 };
1665 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1666 try stack.append(State { .AddrOfModifiers = &node.op.SliceType });
1667 continue;
1668 }
13841669
1385 State.PrimaryExpression => |dest_ptr| {
1386 const token = self.getNextToken();
1670 node.op = ast.NodePrefixOp.PrefixOp { .ArrayType = undefined };
1671 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1672 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1673 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayType } });
1674 continue;
1675 },
1676 State.AddrOfModifiers => |addr_of_info| {
1677 var token = self.getNextToken();
13871678 switch (token.id) {
1388 Token.Id.IntegerLiteral => {
1389 dest_ptr.store(&(try self.createIntegerLiteral(arena, token)).base);
1390 continue;
1391 },
1392 Token.Id.FloatLiteral => {
1393 dest_ptr.store(&(try self.createFloatLiteral(arena, token)).base);
1394 continue;
1395 },
1396 Token.Id.StringLiteral => {
1397 dest_ptr.store(&(try self.createStringLiteral(arena, token)).base);
1398 continue;
1399 },
1400 Token.Id.CharLiteral => {
1401 const node = try arena.create(ast.NodeCharLiteral);
1402 *node = ast.NodeCharLiteral {
1403 .base = self.initNode(ast.Node.Id.CharLiteral),
1404 .token = token,
1405 };
1406 dest_ptr.store(&node.base);
1407 continue;
1408 },
1409 Token.Id.Keyword_undefined => {
1410 dest_ptr.store(&(try self.createUndefined(arena, token)).base);
1411 continue;
1412 },
1413 Token.Id.Keyword_true, Token.Id.Keyword_false => {
1414 const node = try arena.create(ast.NodeBoolLiteral);
1415 *node = ast.NodeBoolLiteral {
1416 .base = self.initNode(ast.Node.Id.BoolLiteral),
1417 .token = token,
1418 };
1419 dest_ptr.store(&node.base);
1420 continue;
1421 },
1422 Token.Id.Keyword_null => {
1423 const node = try arena.create(ast.NodeNullLiteral);
1424 *node = ast.NodeNullLiteral {
1425 .base = self.initNode(ast.Node.Id.NullLiteral),
1426 .token = token,
1427 };
1428 dest_ptr.store(&node.base);
1429 continue;
1430 },
1431 Token.Id.Keyword_this => {
1432 const node = try arena.create(ast.NodeThisLiteral);
1433 *node = ast.NodeThisLiteral {
1434 .base = self.initNode(ast.Node.Id.ThisLiteral),
1435 .token = token,
1436 };
1437 dest_ptr.store(&node.base);
1438 continue;
1439 },
1440 Token.Id.Keyword_var => {
1441 const node = try arena.create(ast.NodeVarType);
1442 *node = ast.NodeVarType {
1443 .base = self.initNode(ast.Node.Id.VarType),
1444 .token = token,
1445 };
1446 dest_ptr.store(&node.base);
1447 },
1448 Token.Id.Keyword_unreachable => {
1449 const node = try arena.create(ast.NodeUnreachable);
1450 *node = ast.NodeUnreachable {
1451 .base = self.initNode(ast.Node.Id.Unreachable),
1452 .token = token,
1453 };
1454 dest_ptr.store(&node.base);
1455 continue;
1456 },
1457 Token.Id.MultilineStringLiteralLine => {
1458 const node = try arena.create(ast.NodeMultilineStringLiteral);
1459 *node = ast.NodeMultilineStringLiteral {
1460 .base = self.initNode(ast.Node.Id.MultilineStringLiteral),
1461 .tokens = ArrayList(Token).init(arena),
1462 };
1463 dest_ptr.store(&node.base);
1464 try node.tokens.append(token);
1465
1466 while (true) {
1467 const multiline_str = self.getNextToken();
1468 if (multiline_str.id != Token.Id.MultilineStringLiteralLine) {
1469 self.putBackToken(multiline_str);
1470 break;
1471 }
1472
1473 try node.tokens.append(multiline_str);
1679 Token.Id.Keyword_align => {
1680 stack.append(state) catch unreachable;
1681 if (addr_of_info.align_expr != null) {
1682 return self.parseError(token, "multiple align qualifiers");
14741683 }
1684 try stack.append(State { .ExpectToken = Token.Id.RParen });
1685 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &addr_of_info.align_expr} });
1686 try stack.append(State { .ExpectToken = Token.Id.LParen });
14751687 continue;
14761688 },
1477 Token.Id.LParen => {
1478 const node = try arena.create(ast.NodeGroupedExpression);
1479 *node = ast.NodeGroupedExpression {
1480 .base = self.initNode(ast.Node.Id.GroupedExpression),
1481 .lparen = token,
1482 .expr = undefined,
1483 .rparen = undefined,
1484 };
1485 dest_ptr.store(&node.base);
1486 stack.append(State {
1487 .ExpectTokenSave = ExpectTokenSave {
1488 .id = Token.Id.RParen,
1489 .ptr = &node.rparen,
1490 }
1491 }) catch unreachable;
1492 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
1493 continue;
1494 },
1495 Token.Id.Builtin => {
1496 const node = try arena.create(ast.NodeBuiltinCall);
1497 *node = ast.NodeBuiltinCall {
1498 .base = self.initNode(ast.Node.Id.BuiltinCall),
1499 .builtin_token = token,
1500 .params = ArrayList(&ast.Node).init(arena),
1501 .rparen_token = undefined,
1502 };
1503 dest_ptr.store(&node.base);
1504 stack.append(State {
1505 .ExprListItemOrEnd = ExprListCtx {
1506 .list = &node.params,
1507 .end = Token.Id.RParen,
1508 .ptr = &node.rparen_token,
1509 }
1510 }) catch unreachable;
1511 try stack.append(State { .ExpectToken = Token.Id.LParen, });
1512 continue;
1513 },
1514 Token.Id.LBracket => {
1515 const rbracket_token = self.getNextToken();
1516 if (rbracket_token.id == Token.Id.RBracket) {
1517 const node = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp{
1518 .SliceType = ast.NodePrefixOp.AddrOfInfo {
1519 .align_expr = null,
1520 .bit_offset_start_token = null,
1521 .bit_offset_end_token = null,
1522 .const_token = null,
1523 .volatile_token = null,
1524 }
1525 });
1526 dest_ptr.store(&node.base);
1527 stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable;
1528 try stack.append(State { .AddrOfModifiers = &node.op.SliceType });
1529 continue;
1530 }
1531
1532 self.putBackToken(rbracket_token);
1533
1534 const node = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp{
1535 .ArrayType = undefined,
1536 });
1537 dest_ptr.store(&node.base);
1538 stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable;
1539 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1540 try stack.append(State { .Expression = DestPtr { .Field = &node.op.ArrayType } });
1541
1542 },
1543 Token.Id.Keyword_error => {
1544 const next = self.getNextToken();
1545
1546 if (next.id != Token.Id.LBrace) {
1547 self.putBackToken(next);
1548 const node = try arena.create(ast.NodeErrorType);
1549 *node = ast.NodeErrorType {
1550 .base = self.initNode(ast.Node.Id.ErrorType),
1551 .token = token,
1552 };
1553 dest_ptr.store(&node.base);
1554 continue;
1555 }
1556
1557 const node = try arena.create(ast.NodeErrorSetDecl);
1558 *node = ast.NodeErrorSetDecl {
1559 .base = self.initNode(ast.Node.Id.ErrorSetDecl),
1560 .error_token = token,
1561 .decls = ArrayList(&ast.NodeIdentifier).init(arena),
1562 .rbrace_token = undefined,
1563 };
1564 dest_ptr.store(&node.base);
1565
1566 while (true) {
1567 const t = self.getNextToken();
1568 switch (t.id) {
1569 Token.Id.RBrace => {
1570 node.rbrace_token = t;
1571 break;
1572 },
1573 Token.Id.Identifier => {
1574 try node.decls.append(
1575 try self.createIdentifier(arena, t)
1576 );
1577 },
1578 else => {
1579 try self.parseError(&stack, token, "expected {} or {}, found {}",
1580 @tagName(Token.Id.RBrace),
1581 @tagName(Token.Id.Identifier),
1582 @tagName(token.id));
1583 continue;
1584 }
1585 }
1586
1587 const t2 = self.getNextToken();
1588 switch (t2.id) {
1589 Token.Id.RBrace => {
1590 node.rbrace_token = t;
1591 break;
1592 },
1593 Token.Id.Comma => continue,
1594 else => {
1595 try self.parseError(&stack, token, "expected {} or {}, found {}",
1596 @tagName(Token.Id.RBrace),
1597 @tagName(Token.Id.Comma),
1598 @tagName(token.id));
1599 continue;
1600 }
1601 }
1689 Token.Id.Keyword_const => {
1690 stack.append(state) catch unreachable;
1691 if (addr_of_info.const_token != null) {
1692 return self.parseError(token, "duplicate qualifier: const");
16021693 }
1694 addr_of_info.const_token = token;
16031695 continue;
16041696 },
1605 Token.Id.Keyword_packed => {
1606 stack.append(State {
1607 .ContainerExtern = ContainerExternCtx {
1608 .dest_ptr = dest_ptr,
1609 .ltoken = token,
1610 .layout = ast.NodeContainerDecl.Layout.Packed,
1611 },
1612 }) catch unreachable;
1613 },
1614 Token.Id.Keyword_extern => {
1615 const next = self.getNextToken();
1616 if (next.id == Token.Id.Keyword_fn) {
1617 // TODO shouldn't need this cast
1618 const fn_proto = try self.createFnProto(arena, next,
1619 (?Token)(token), (?&ast.Node)(null), (?Token)(null), (?Token)(null), (?Token)(null));
1620 dest_ptr.store(&fn_proto.base);
1621 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1622 continue;
1623 }
1624
1625 self.putBackToken(next);
1626 stack.append(State {
1627 .ContainerExtern = ContainerExternCtx {
1628 .dest_ptr = dest_ptr,
1629 .ltoken = token,
1630 .layout = ast.NodeContainerDecl.Layout.Extern,
1631 },
1632 }) catch unreachable;
1633 },
1634 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
1635 self.putBackToken(token);
1636 stack.append(State {
1637 .ContainerExtern = ContainerExternCtx {
1638 .dest_ptr = dest_ptr,
1639 .ltoken = token,
1640 .layout = ast.NodeContainerDecl.Layout.Auto,
1641 },
1642 }) catch unreachable;
1643 },
1644 Token.Id.Identifier => {
1645 const next = self.getNextToken();
1646 if (next.id != Token.Id.Colon) {
1647 self.putBackToken(next);
1648 dest_ptr.store(&(try self.createIdentifier(arena, token)).base);
1649 continue;
1697 Token.Id.Keyword_volatile => {
1698 stack.append(state) catch unreachable;
1699 if (addr_of_info.volatile_token != null) {
1700 return self.parseError(token, "duplicate qualifier: volatile");
16501701 }
1651
1652 stack.append(State {
1653 .LabeledExpression = LabelCtx {
1654 .label = token,
1655 .dest_ptr = dest_ptr
1656 }
1657 }) catch unreachable;
1658 continue;
1659 },
1660 Token.Id.Keyword_fn => {
1661 // TODO shouldn't need these casts
1662 const fn_proto = try self.createFnProto(arena, token,
1663 (?Token)(null), (?&ast.Node)(null), (?Token)(null), (?Token)(null), (?Token)(null));
1664 dest_ptr.store(&fn_proto.base);
1665 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1666 continue;
1667 },
1668 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
1669 const fn_token = (try self.eatToken(&stack, Token.Id.Keyword_fn)) ?? continue;
1670 // TODO shouldn't need this cast
1671 const fn_proto = try self.createFnProto(arena, fn_token,
1672 (?Token)(null), (?&ast.Node)(null), (?Token)(token), (?Token)(null), (?Token)(null));
1673 dest_ptr.store(&fn_proto.base);
1674 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1675 continue;
1676 },
1677 Token.Id.Keyword_asm => {
1678 const is_volatile = blk: {
1679 const volatile_token = self.getNextToken();
1680 if (volatile_token.id != Token.Id.Keyword_volatile) {
1681 self.putBackToken(volatile_token);
1682 break :blk false;
1683 }
1684 break :blk true;
1685 };
1686 _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue;
1687 const template = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue;
1688 // TODO parse template
1689
1690 const node = try arena.create(ast.NodeAsm);
1691 *node = ast.NodeAsm {
1692 .base = self.initNode(ast.Node.Id.Asm),
1693 .asm_token = token,
1694 .is_volatile = is_volatile,
1695 .template = template,
1696 //.tokens = ArrayList(ast.NodeAsm.AsmToken).init(arena),
1697 .outputs = ArrayList(&ast.NodeAsmOutput).init(arena),
1698 .inputs = ArrayList(&ast.NodeAsmInput).init(arena),
1699 .cloppers = ArrayList(&ast.NodeStringLiteral).init(arena),
1700 .rparen = undefined,
1701 };
1702 dest_ptr.store(&node.base);
1703
1704 stack.append(State {
1705 .ExpectTokenSave = ExpectTokenSave {
1706 .id = Token.Id.RParen,
1707 .ptr = &node.rparen,
1708 }
1709 }) catch unreachable;
1710 try stack.append(State { .AsmClopperItems = &node.cloppers });
1711 try stack.append(State { .IfToken = Token.Id.Colon });
1712 try stack.append(State { .AsmInputItems = &node.inputs });
1713 try stack.append(State { .IfToken = Token.Id.Colon });
1714 try stack.append(State { .AsmOutputItems = &node.outputs });
1715 try stack.append(State { .IfToken = Token.Id.Colon });
1716 },
1717 Token.Id.Keyword_inline => {
1718 stack.append(State {
1719 .Inline = InlineCtx {
1720 .label = null,
1721 .inline_token = token,
1722 .dest_ptr = dest_ptr,
1723 }
1724 }) catch unreachable;
1702 addr_of_info.volatile_token = token;
17251703 continue;
17261704 },
17271705 else => {
1728 try self.parseError(&stack, token, "expected primary expression, found {}", @tagName(token.id));
1706 self.putBackToken(token);
17291707 continue;
1730 }
1708 },
17311709 }
17321710 },
17331711
1734 State.SliceOrArrayAccess => |node| {
1735 var token = self.getNextToken();
17361712
1737 switch (token.id) {
1738 Token.Id.Ellipsis2 => {
1739 const start = node.op.ArrayAccess;
1740 node.op = ast.NodeSuffixOp.SuffixOp {
1741 .Slice = ast.NodeSuffixOp.SliceRange {
1742 .start = start,
1743 .end = undefined,
1744 }
1745 };
1746
1747 const rbracket_token = self.getNextToken();
1748 if (rbracket_token.id != Token.Id.RBracket) {
1749 self.putBackToken(rbracket_token);
1750 stack.append(State {
1751 .ExpectTokenSave = ExpectTokenSave {
1752 .id = Token.Id.RBracket,
1753 .ptr = &node.rtoken,
1754 }
1755 }) catch unreachable;
1756 try stack.append(State { .Expression = DestPtr { .NullableField = &node.op.Slice.end } });
1757 } else {
1758 node.rtoken = rbracket_token;
1759 }
1760 continue;
1761 },
1762 Token.Id.RBracket => {
1763 node.rtoken = token;
1764 continue;
1765 },
1766 else => {
1767 try self.parseError(&stack, token, "expected ']' or '..', found {}", @tagName(token.id));
1768 continue;
1713 State.Payload => |opt_ctx| {
1714 const token = self.getNextToken();
1715 if (token.id != Token.Id.Pipe) {
1716 if (opt_ctx != OptionalCtx.Optional) {
1717 return self.parseError(token, "expected {}, found {}.",
1718 @tagName(Token.Id.Pipe),
1719 @tagName(token.id));
17691720 }
1770 }
1771 },
17721721
1773
1774 State.AsmOutputItems => |items| {
1775 const lbracket = self.getNextToken();
1776 if (lbracket.id != Token.Id.LBracket) {
1777 self.putBackToken(lbracket);
1722 self.putBackToken(token);
17781723 continue;
17791724 }
17801725
1781 stack.append(State { .AsmOutputItems = items }) catch unreachable;
1782 try stack.append(State { .IfToken = Token.Id.Comma });
1783
1784 const symbolic_name = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
1785 _ = (try self.eatToken(&stack, Token.Id.RBracket)) ?? continue;
1786 const constraint = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue;
1787
1788 _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue;
1789 try stack.append(State { .ExpectToken = Token.Id.RParen });
1790
1791 const node = try arena.create(ast.NodeAsmOutput);
1792 *node = ast.NodeAsmOutput {
1793 .base = self.initNode(ast.Node.Id.AsmOutput),
1794 .symbolic_name = try self.createIdentifier(arena, symbolic_name),
1795 .constraint = try self.createStringLiteral(arena, constraint),
1796 .kind = undefined,
1797 };
1798 try items.append(node);
1726 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePayload,
1727 ast.NodePayload {
1728 .base = undefined,
1729 .lpipe = token,
1730 .error_symbol = undefined,
1731 .rpipe = undefined
1732 }
1733 );
17991734
1800 const symbol_or_arrow = self.getNextToken();
1801 switch (symbol_or_arrow.id) {
1802 Token.Id.Identifier => {
1803 node.kind = ast.NodeAsmOutput.Kind { .Variable = try self.createIdentifier(arena, symbol_or_arrow) };
1804 },
1805 Token.Id.Arrow => {
1806 node.kind = ast.NodeAsmOutput.Kind { .Return = undefined };
1807 try stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.kind.Return } });
1808 },
1809 else => {
1810 try self.parseError(&stack, symbol_or_arrow, "expected '->' or {}, found {}",
1811 @tagName(Token.Id.Identifier),
1812 @tagName(symbol_or_arrow.id));
1813 continue;
1814 },
1815 }
1735 stack.append(State {
1736 .ExpectTokenSave = ExpectTokenSave {
1737 .id = Token.Id.Pipe,
1738 .ptr = &node.rpipe,
1739 }
1740 }) catch unreachable;
1741 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.error_symbol } });
1742 continue;
18161743 },
1744 State.PointerPayload => |opt_ctx| {
1745 const token = self.getNextToken();
1746 if (token.id != Token.Id.Pipe) {
1747 if (opt_ctx != OptionalCtx.Optional) {
1748 return self.parseError(token, "expected {}, found {}.",
1749 @tagName(Token.Id.Pipe),
1750 @tagName(token.id));
1751 }
18171752
1818 State.AsmInputItems => |items| {
1819 const lbracket = self.getNextToken();
1820 if (lbracket.id != Token.Id.LBracket) {
1821 self.putBackToken(lbracket);
1753 self.putBackToken(token);
18221754 continue;
18231755 }
18241756
1825 stack.append(State { .AsmInputItems = items }) catch unreachable;
1826 try stack.append(State { .IfToken = Token.Id.Comma });
1827
1828 const symbolic_name = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
1829 _ = (try self.eatToken(&stack, Token.Id.RBracket)) ?? continue;
1830 const constraint = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue;
1831
1832 _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue;
1833 try stack.append(State { .ExpectToken = Token.Id.RParen });
1757 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePointerPayload,
1758 ast.NodePointerPayload {
1759 .base = undefined,
1760 .lpipe = token,
1761 .ptr_token = null,
1762 .value_symbol = undefined,
1763 .rpipe = undefined
1764 }
1765 );
18341766
1835 const node = try arena.create(ast.NodeAsmInput);
1836 *node = ast.NodeAsmInput {
1837 .base = self.initNode(ast.Node.Id.AsmInput),
1838 .symbolic_name = try self.createIdentifier(arena, symbolic_name),
1839 .constraint = try self.createStringLiteral(arena, constraint),
1840 .expr = undefined,
1841 };
1842 try items.append(node);
1843 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
1767 stack.append(State {
1768 .ExpectTokenSave = ExpectTokenSave {
1769 .id = Token.Id.Pipe,
1770 .ptr = &node.rpipe,
1771 }
1772 }) catch unreachable;
1773 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1774 try stack.append(State {
1775 .OptionalTokenSave = OptionalTokenSave {
1776 .id = Token.Id.Asterisk,
1777 .ptr = &node.ptr_token,
1778 }
1779 });
1780 continue;
18441781 },
1782 State.PointerIndexPayload => |opt_ctx| {
1783 const token = self.getNextToken();
1784 if (token.id != Token.Id.Pipe) {
1785 if (opt_ctx != OptionalCtx.Optional) {
1786 return self.parseError(token, "expected {}, found {}.",
1787 @tagName(Token.Id.Pipe),
1788 @tagName(token.id));
1789 }
18451790
1846 State.AsmClopperItems => |items| {
1847 const string = self.getNextToken();
1848 if (string.id != Token.Id.StringLiteral) {
1849 self.putBackToken(string);
1791 self.putBackToken(token);
18501792 continue;
18511793 }
18521794
1853 try items.append(try self.createStringLiteral(arena, string));
1854 stack.append(State { .AsmClopperItems = items }) catch unreachable;
1855 try stack.append(State { .IfToken = Token.Id.Comma });
1856 },
1857
1858 State.ExprListItemOrEnd => |list_state| {
1859 var token = self.getNextToken();
1860
1861 const IdTag = @TagType(Token.Id);
1862 if (IdTag(list_state.end) == token.id) {
1863 *list_state.ptr = token;
1864 continue;
1865 }
1795 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePointerIndexPayload,
1796 ast.NodePointerIndexPayload {
1797 .base = undefined,
1798 .lpipe = token,
1799 .ptr_token = null,
1800 .value_symbol = undefined,
1801 .index_symbol = null,
1802 .rpipe = undefined
1803 }
1804 );
18661805
1867 self.putBackToken(token);
1868 stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable;
1869 try stack.append(State { .Expression = DestPtr{ .Field = try list_state.list.addOne() } });
1806 stack.append(State {
1807 .ExpectTokenSave = ExpectTokenSave {
1808 .id = Token.Id.Pipe,
1809 .ptr = &node.rpipe,
1810 }
1811 }) catch unreachable;
1812 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.index_symbol } });
1813 try stack.append(State { .IfToken = Token.Id.Comma });
1814 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1815 try stack.append(State {
1816 .OptionalTokenSave = OptionalTokenSave {
1817 .id = Token.Id.Asterisk,
1818 .ptr = &node.ptr_token,
1819 }
1820 });
1821 continue;
18701822 },
18711823
1872 State.FieldInitListItemOrEnd => |list_state| {
1873 var token = self.getNextToken();
18741824
1875 if (token.id == Token.Id.RBrace){
1876 *list_state.ptr = token;
1877 continue;
1878 }
1825 State.Expression => |opt_ctx| {
1826 const token = self.getNextToken();
1827 switch (token.id) {
1828 Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => {
1829 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeControlFlowExpression,
1830 ast.NodeControlFlowExpression {
1831 .base = undefined,
1832 .ltoken = token,
1833 .kind = undefined,
1834 .rhs = null,
1835 }
1836 );
18791837
1880 self.putBackToken(token);
1838 stack.append(State { .Expression = OptionalCtx { .Optional = &node.rhs } }) catch unreachable;
18811839
1882 const node = try arena.create(ast.NodeFieldInitializer);
1883 *node = ast.NodeFieldInitializer {
1884 .base = self.initNode(ast.Node.Id.FieldInitializer),
1885 .period_token = undefined,
1886 .name_token = undefined,
1887 .expr = undefined,
1888 };
1889 try list_state.list.append(node);
1840 switch (token.id) {
1841 Token.Id.Keyword_break => {
1842 node.kind = ast.NodeControlFlowExpression.Kind { .Break = null };
1843 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Break } });
1844 try stack.append(State { .IfToken = Token.Id.Colon });
1845 },
1846 Token.Id.Keyword_continue => {
1847 node.kind = ast.NodeControlFlowExpression.Kind { .Continue = null };
1848 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Continue } });
1849 try stack.append(State { .IfToken = Token.Id.Colon });
1850 },
1851 Token.Id.Keyword_return => {
1852 node.kind = ast.NodeControlFlowExpression.Kind.Return;
1853 },
1854 else => unreachable,
1855 }
1856 continue;
1857 },
1858 Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
1859 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePrefixOp,
1860 ast.NodePrefixOp {
1861 .base = undefined,
1862 .op_token = token,
1863 .op = switch (token.id) {
1864 Token.Id.Keyword_try => ast.NodePrefixOp.PrefixOp { .Try = void{} },
1865 Token.Id.Keyword_cancel => ast.NodePrefixOp.PrefixOp { .Cancel = void{} },
1866 Token.Id.Keyword_resume => ast.NodePrefixOp.PrefixOp { .Resume = void{} },
1867 else => unreachable,
1868 },
1869 .rhs = undefined,
1870 }
1871 );
18901872
1891 stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
1892 try stack.append(State { .Expression = DestPtr{.Field = &node.expr} });
1893 try stack.append(State { .ExpectToken = Token.Id.Equal });
1894 try stack.append(State {
1895 .ExpectTokenSave = ExpectTokenSave {
1896 .id = Token.Id.Identifier,
1897 .ptr = &node.name_token,
1898 }
1899 });
1900 try stack.append(State {
1901 .ExpectTokenSave = ExpectTokenSave {
1902 .id = Token.Id.Period,
1903 .ptr = &node.period_token,
1873 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1874 continue;
1875 },
1876 else => {
1877 if (!try self.parseBlockExpr(&stack, arena, opt_ctx, token)) {
1878 self.putBackToken(token);
1879 stack.append(State { .UnwrapExpressionBegin = opt_ctx }) catch unreachable;
1880 }
1881 continue;
19041882 }
1905 });
1883 }
19061884 },
1907
1908 State.SwitchCaseOrEnd => |list_state| {
1909 var token = self.getNextToken();
1910
1911 if (token.id == Token.Id.RBrace){
1912 *list_state.ptr = token;
1885 State.RangeExpressionBegin => |opt_ctx| {
1886 stack.append(State { .RangeExpressionEnd = opt_ctx }) catch unreachable;
1887 try stack.append(State { .Expression = opt_ctx });
1888 continue;
1889 },
1890 State.RangeExpressionEnd => |opt_ctx| {
1891 const lhs = opt_ctx.get() ?? continue;
1892
1893 if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
1894 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
1895 ast.NodeInfixOp {
1896 .base = undefined,
1897 .lhs = lhs,
1898 .op_token = ellipsis3,
1899 .op = ast.NodeInfixOp.InfixOp.Range,
1900 .rhs = undefined,
1901 }
1902 );
1903 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
19131904 continue;
19141905 }
1906 },
1907 State.AssignmentExpressionBegin => |opt_ctx| {
1908 stack.append(State { .AssignmentExpressionEnd = opt_ctx }) catch unreachable;
1909 try stack.append(State { .Expression = opt_ctx });
1910 continue;
1911 },
19151912
1916 self.putBackToken(token);
1913 State.AssignmentExpressionEnd => |opt_ctx| {
1914 const lhs = opt_ctx.get() ?? continue;
19171915
1918 const node = try arena.create(ast.NodeSwitchCase);
1919 *node = ast.NodeSwitchCase {
1920 .base = self.initNode(ast.Node.Id.SwitchCase),
1921 .items = ArrayList(&ast.Node).init(arena),
1922 .payload = null,
1923 .expr = undefined,
1924 };
1925 try list_state.list.append(node);
1926 stack.append(State { .SwitchCaseCommaOrEnd = list_state }) catch unreachable;
1927 try stack.append(State { .Expression = DestPtr{ .Field = &node.expr } });
1928 try stack.append(State { .PointerPayload = &node.payload });
1929
1930 const maybe_else = self.getNextToken();
1931 if (maybe_else.id == Token.Id.Keyword_else) {
1932 const else_node = try arena.create(ast.NodeSwitchElse);
1933 *else_node = ast.NodeSwitchElse {
1934 .base = self.initNode(ast.Node.Id.SwitchElse),
1935 .token = maybe_else,
1936 };
1937 try node.items.append(&else_node.base);
1938 try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
1916 const token = self.getNextToken();
1917 if (tokenIdToAssignment(token.id)) |ass_id| {
1918 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
1919 ast.NodeInfixOp {
1920 .base = undefined,
1921 .lhs = lhs,
1922 .op_token = token,
1923 .op = ass_id,
1924 .rhs = undefined,
1925 }
1926 );
1927 stack.append(State { .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1928 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
19391929 continue;
19401930 } else {
1941 self.putBackToken(maybe_else);
1942 try stack.append(State { .SwitchCaseItem = &node.items });
1931 self.putBackToken(token);
19431932 continue;
19441933 }
19451934 },
19461935
1947 State.SwitchCaseItem => |case_items| {
1948 stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
1949 try stack.append(State { .RangeExpressionBegin = DestPtr{ .Field = try case_items.addOne() } });
1950 },
1951
1952 State.ExprListCommaOrEnd => |list_state| {
1953 try self.commaOrEnd(&stack, list_state.end, list_state.ptr, State { .ExprListItemOrEnd = list_state });
1936 State.UnwrapExpressionBegin => |opt_ctx| {
1937 stack.append(State { .UnwrapExpressionEnd = opt_ctx }) catch unreachable;
1938 try stack.append(State { .BoolOrExpressionBegin = opt_ctx });
19541939 continue;
19551940 },
19561941
1957 State.FieldInitListCommaOrEnd => |list_state| {
1958 try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .FieldInitListItemOrEnd = list_state });
1959 continue;
1960 },
1942 State.UnwrapExpressionEnd => |opt_ctx| {
1943 const lhs = opt_ctx.get() ?? continue;
19611944
1962 State.FieldListCommaOrEnd => |container_decl| {
1963 try self.commaOrEnd(&stack, Token.Id.RBrace, &container_decl.rbrace_token,
1964 State { .ContainerDecl = container_decl });
1965 continue;
1966 },
1945 const token = self.getNextToken();
1946 if (tokenIdToUnwrapExpr(token.id)) |unwrap_id| {
1947 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
1948 ast.NodeInfixOp {
1949 .base = undefined,
1950 .lhs = lhs,
1951 .op_token = token,
1952 .op = unwrap_id,
1953 .rhs = undefined,
1954 }
1955 );
19671956
1968 State.SwitchCaseCommaOrEnd => |list_state| {
1969 try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .SwitchCaseOrEnd = list_state });
1970 continue;
1957 stack.append(State { .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1958 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
1959
1960 if (node.op == ast.NodeInfixOp.InfixOp.Catch) {
1961 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.op.Catch } });
1962 }
1963 continue;
1964 } else {
1965 self.putBackToken(token);
1966 continue;
1967 }
19711968 },
19721969
1973 State.SwitchCaseItemCommaOrEnd => |case_items| {
1974 try self.commaOrEnd(&stack, Token.Id.EqualAngleBracketRight, null, State { .SwitchCaseItem = case_items });
1970 State.BoolOrExpressionBegin => |opt_ctx| {
1971 stack.append(State { .BoolOrExpressionEnd = opt_ctx }) catch unreachable;
1972 try stack.append(State { .BoolAndExpressionBegin = opt_ctx });
19751973 continue;
19761974 },
19771975
1978 State.Else => |dest| {
1979 const else_token = self.getNextToken();
1980 if (else_token.id != Token.Id.Keyword_else) {
1981 self.putBackToken(else_token);
1976 State.BoolOrExpressionEnd => |opt_ctx| {
1977 const lhs = opt_ctx.get() ?? continue;
1978
1979 if (self.eatToken(Token.Id.Keyword_or)) |or_token| {
1980 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
1981 ast.NodeInfixOp {
1982 .base = undefined,
1983 .lhs = lhs,
1984 .op_token = or_token,
1985 .op = ast.NodeInfixOp.InfixOp.BoolOr,
1986 .rhs = undefined,
1987 }
1988 );
1989 stack.append(State { .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1990 try stack.append(State { .BoolAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
19821991 continue;
19831992 }
1993 },
19841994
1985 const node = try arena.create(ast.NodeElse);
1986 *node = ast.NodeElse {
1987 .base = self.initNode(ast.Node.Id.Else),
1988 .else_token = else_token,
1989 .payload = null,
1990 .body = undefined,
1991 };
1992 *dest = node;
1993
1994 stack.append(State { .Expression = DestPtr { .Field = &node.body } }) catch unreachable;
1995 try stack.append(State { .Payload = &node.payload });
1995 State.BoolAndExpressionBegin => |opt_ctx| {
1996 stack.append(State { .BoolAndExpressionEnd = opt_ctx }) catch unreachable;
1997 try stack.append(State { .ComparisonExpressionBegin = opt_ctx });
1998 continue;
19961999 },
19972000
1998 State.WhileContinueExpr => |dest| {
1999 const colon = self.getNextToken();
2000 if (colon.id != Token.Id.Colon) {
2001 self.putBackToken(colon);
2001 State.BoolAndExpressionEnd => |opt_ctx| {
2002 const lhs = opt_ctx.get() ?? continue;
2003
2004 if (self.eatToken(Token.Id.Keyword_and)) |and_token| {
2005 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2006 ast.NodeInfixOp {
2007 .base = undefined,
2008 .lhs = lhs,
2009 .op_token = and_token,
2010 .op = ast.NodeInfixOp.InfixOp.BoolAnd,
2011 .rhs = undefined,
2012 }
2013 );
2014 stack.append(State { .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2015 try stack.append(State { .ComparisonExpressionBegin = OptionalCtx { .Required = &node.rhs } });
20022016 continue;
20032017 }
2004
2005 _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue;
2006 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
2007 try stack.append(State { .AssignmentExpressionBegin = DestPtr { .NullableField = dest } });
20082018 },
20092019
2010 State.SuspendBody => |suspend_node| {
2011 if (suspend_node.payload != null) {
2012 try stack.append(State { .AssignmentExpressionBegin = DestPtr { .NullableField = &suspend_node.body } });
2013 }
2020 State.ComparisonExpressionBegin => |opt_ctx| {
2021 stack.append(State { .ComparisonExpressionEnd = opt_ctx }) catch unreachable;
2022 try stack.append(State { .BinaryOrExpressionBegin = opt_ctx });
20142023 continue;
20152024 },
20162025
2017 State.AsyncEnd => |ctx| {
2018 const node = ctx.dest_ptr.get();
2026 State.ComparisonExpressionEnd => |opt_ctx| {
2027 const lhs = opt_ctx.get() ?? continue;
20192028
2020 switch (node.id) {
2021 ast.Node.Id.FnProto => {
2022 const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", node);
2023 fn_proto.async_attr = ctx.attribute;
2024 },
2025 ast.Node.Id.SuffixOp => {
2026 const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", node);
2027 if (suffix_op.op == ast.NodeSuffixOp.SuffixOp.Call) {
2028 suffix_op.op.Call.async_attr = ctx.attribute;
2029 continue;
2029 const token = self.getNextToken();
2030 if (tokenIdToComparison(token.id)) |comp_id| {
2031 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2032 ast.NodeInfixOp {
2033 .base = undefined,
2034 .lhs = lhs,
2035 .op_token = token,
2036 .op = comp_id,
2037 .rhs = undefined,
20302038 }
2031
2032 try self.parseError(&stack, node.firstToken(), "expected call or fn proto, found {}.",
2033 @tagName(suffix_op.op));
2034 continue;
2035 },
2036 else => {
2037 try self.parseError(&stack, node.firstToken(), "expected call or fn proto, found {}.",
2038 @tagName(node.id));
2039 continue;
2040 }
2039 );
2040 stack.append(State { .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2041 try stack.append(State { .BinaryOrExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2042 continue;
2043 } else {
2044 self.putBackToken(token);
2045 continue;
20412046 }
20422047 },
20432048
2044 State.Payload => |dest| {
2045 const lpipe = self.getNextToken();
2046 if (lpipe.id != Token.Id.Pipe) {
2047 self.putBackToken(lpipe);
2049 State.BinaryOrExpressionBegin => |opt_ctx| {
2050 stack.append(State { .BinaryOrExpressionEnd = opt_ctx }) catch unreachable;
2051 try stack.append(State { .BinaryXorExpressionBegin = opt_ctx });
2052 continue;
2053 },
2054
2055 State.BinaryOrExpressionEnd => |opt_ctx| {
2056 const lhs = opt_ctx.get() ?? continue;
2057
2058 if (self.eatToken(Token.Id.Pipe)) |pipe| {
2059 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2060 ast.NodeInfixOp {
2061 .base = undefined,
2062 .lhs = lhs,
2063 .op_token = pipe,
2064 .op = ast.NodeInfixOp.InfixOp.BitOr,
2065 .rhs = undefined,
2066 }
2067 );
2068 stack.append(State { .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2069 try stack.append(State { .BinaryXorExpressionBegin = OptionalCtx { .Required = &node.rhs } });
20482070 continue;
20492071 }
2072 },
20502073
2051 const error_symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
2052 const rpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue;
2053 const node = try arena.create(ast.NodePayload);
2054 *node = ast.NodePayload {
2055 .base = self.initNode(ast.Node.Id.Payload),
2056 .lpipe = lpipe,
2057 .error_symbol = try self.createIdentifier(arena, error_symbol),
2058 .rpipe = rpipe
2059 };
2060 *dest = node;
2074 State.BinaryXorExpressionBegin => |opt_ctx| {
2075 stack.append(State { .BinaryXorExpressionEnd = opt_ctx }) catch unreachable;
2076 try stack.append(State { .BinaryAndExpressionBegin = opt_ctx });
2077 continue;
20612078 },
20622079
2063 State.PointerPayload => |dest| {
2064 const lpipe = self.getNextToken();
2065 if (lpipe.id != Token.Id.Pipe) {
2066 self.putBackToken(lpipe);
2080 State.BinaryXorExpressionEnd => |opt_ctx| {
2081 const lhs = opt_ctx.get() ?? continue;
2082
2083 if (self.eatToken(Token.Id.Caret)) |caret| {
2084 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2085 ast.NodeInfixOp {
2086 .base = undefined,
2087 .lhs = lhs,
2088 .op_token = caret,
2089 .op = ast.NodeInfixOp.InfixOp.BitXor,
2090 .rhs = undefined,
2091 }
2092 );
2093 stack.append(State { .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2094 try stack.append(State { .BinaryAndExpressionBegin = OptionalCtx { .Required = &node.rhs } });
20672095 continue;
20682096 }
2097 },
20692098
2070 const is_ptr = blk: {
2071 const asterik = self.getNextToken();
2072 if (asterik.id == Token.Id.Asterisk) {
2073 break :blk true;
2074 } else {
2075 self.putBackToken(asterik);
2076 break :blk false;
2077 }
2078 };
2079
2080 const value_symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
2081 const rpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue;
2082 const node = try arena.create(ast.NodePointerPayload);
2083 *node = ast.NodePointerPayload {
2084 .base = self.initNode(ast.Node.Id.PointerPayload),
2085 .lpipe = lpipe,
2086 .is_ptr = is_ptr,
2087 .value_symbol = try self.createIdentifier(arena, value_symbol),
2088 .rpipe = rpipe
2089 };
2090 *dest = node;
2099 State.BinaryAndExpressionBegin => |opt_ctx| {
2100 stack.append(State { .BinaryAndExpressionEnd = opt_ctx }) catch unreachable;
2101 try stack.append(State { .BitShiftExpressionBegin = opt_ctx });
2102 continue;
20912103 },
20922104
2093 State.PointerIndexPayload => |dest| {
2094 const lpipe = self.getNextToken();
2095 if (lpipe.id != Token.Id.Pipe) {
2096 self.putBackToken(lpipe);
2105 State.BinaryAndExpressionEnd => |opt_ctx| {
2106 const lhs = opt_ctx.get() ?? continue;
2107
2108 if (self.eatToken(Token.Id.Ampersand)) |ampersand| {
2109 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2110 ast.NodeInfixOp {
2111 .base = undefined,
2112 .lhs = lhs,
2113 .op_token = ampersand,
2114 .op = ast.NodeInfixOp.InfixOp.BitAnd,
2115 .rhs = undefined,
2116 }
2117 );
2118 stack.append(State { .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2119 try stack.append(State { .BitShiftExpressionBegin = OptionalCtx { .Required = &node.rhs } });
20972120 continue;
20982121 }
2122 },
20992123
2100 const is_ptr = blk: {
2101 const asterik = self.getNextToken();
2102 if (asterik.id == Token.Id.Asterisk) {
2103 break :blk true;
2104 } else {
2105 self.putBackToken(asterik);
2106 break :blk false;
2107 }
2108 };
2124 State.BitShiftExpressionBegin => |opt_ctx| {
2125 stack.append(State { .BitShiftExpressionEnd = opt_ctx }) catch unreachable;
2126 try stack.append(State { .AdditionExpressionBegin = opt_ctx });
2127 continue;
2128 },
21092129
2110 const value_symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
2111 const index_symbol = blk: {
2112 const comma = self.getNextToken();
2113 if (comma.id != Token.Id.Comma) {
2114 self.putBackToken(comma);
2115 break :blk null;
2116 }
2130 State.BitShiftExpressionEnd => |opt_ctx| {
2131 const lhs = opt_ctx.get() ?? continue;
21172132
2118 const symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;
2119 break :blk try self.createIdentifier(arena, symbol);
2120 };
2133 const token = self.getNextToken();
2134 if (tokenIdToBitShift(token.id)) |bitshift_id| {
2135 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2136 ast.NodeInfixOp {
2137 .base = undefined,
2138 .lhs = lhs,
2139 .op_token = token,
2140 .op = bitshift_id,
2141 .rhs = undefined,
2142 }
2143 );
2144 stack.append(State { .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2145 try stack.append(State { .AdditionExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2146 continue;
2147 } else {
2148 self.putBackToken(token);
2149 continue;
2150 }
2151 },
21212152
2122 const rpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue;
2123 const node = try arena.create(ast.NodePointerIndexPayload);
2124 *node = ast.NodePointerIndexPayload {
2125 .base = self.initNode(ast.Node.Id.PointerIndexPayload),
2126 .lpipe = lpipe,
2127 .is_ptr = is_ptr,
2128 .value_symbol = try self.createIdentifier(arena, value_symbol),
2129 .index_symbol = index_symbol,
2130 .rpipe = rpipe
2131 };
2132 *dest = node;
2153 State.AdditionExpressionBegin => |opt_ctx| {
2154 stack.append(State { .AdditionExpressionEnd = opt_ctx }) catch unreachable;
2155 try stack.append(State { .MultiplyExpressionBegin = opt_ctx });
2156 continue;
21332157 },
21342158
2135 State.AddrOfModifiers => |addr_of_info| {
2136 var token = self.getNextToken();
2137 switch (token.id) {
2138 Token.Id.Keyword_align => {
2139 stack.append(state) catch unreachable;
2140 if (addr_of_info.align_expr != null) {
2141 try self.parseError(&stack, token, "multiple align qualifiers");
2142 continue;
2143 }
2144 try stack.append(State { .ExpectToken = Token.Id.RParen });
2145 try stack.append(State { .Expression = DestPtr{.NullableField = &addr_of_info.align_expr} });
2146 try stack.append(State { .ExpectToken = Token.Id.LParen });
2147 continue;
2148 },
2149 Token.Id.Keyword_const => {
2150 stack.append(state) catch unreachable;
2151 if (addr_of_info.const_token != null) {
2152 try self.parseError(&stack, token, "duplicate qualifier: const");
2153 continue;
2154 }
2155 addr_of_info.const_token = token;
2156 continue;
2157 },
2158 Token.Id.Keyword_volatile => {
2159 stack.append(state) catch unreachable;
2160 if (addr_of_info.volatile_token != null) {
2161 try self.parseError(&stack, token, "duplicate qualifier: volatile");
2162 continue;
2159 State.AdditionExpressionEnd => |opt_ctx| {
2160 const lhs = opt_ctx.get() ?? continue;
2161
2162 const token = self.getNextToken();
2163 if (tokenIdToAddition(token.id)) |add_id| {
2164 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2165 ast.NodeInfixOp {
2166 .base = undefined,
2167 .lhs = lhs,
2168 .op_token = token,
2169 .op = add_id,
2170 .rhs = undefined,
21632171 }
2164 addr_of_info.volatile_token = token;
2165 continue;
2166 },
2167 else => {
2168 self.putBackToken(token);
2169 continue;
2170 },
2172 );
2173 stack.append(State { .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2174 try stack.append(State { .MultiplyExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2175 continue;
2176 } else {
2177 self.putBackToken(token);
2178 continue;
21712179 }
21722180 },
21732181
2174 State.FnProto => |fn_proto| {
2175 stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable;
2176 try stack.append(State { .ParamDecl = fn_proto });
2177 try stack.append(State { .ExpectToken = Token.Id.LParen });
2182 State.MultiplyExpressionBegin => |opt_ctx| {
2183 stack.append(State { .MultiplyExpressionEnd = opt_ctx }) catch unreachable;
2184 try stack.append(State { .CurlySuffixExpressionBegin = opt_ctx });
2185 continue;
2186 },
21782187
2179 const next_token = self.getNextToken();
2180 if (next_token.id == Token.Id.Identifier) {
2181 fn_proto.name_token = next_token;
2188 State.MultiplyExpressionEnd => |opt_ctx| {
2189 const lhs = opt_ctx.get() ?? continue;
2190
2191 const token = self.getNextToken();
2192 if (tokenIdToMultiply(token.id)) |mult_id| {
2193 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2194 ast.NodeInfixOp {
2195 .base = undefined,
2196 .lhs = lhs,
2197 .op_token = token,
2198 .op = mult_id,
2199 .rhs = undefined,
2200 }
2201 );
2202 stack.append(State { .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2203 try stack.append(State { .CurlySuffixExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2204 continue;
2205 } else {
2206 self.putBackToken(token);
21822207 continue;
21832208 }
2184 self.putBackToken(next_token);
2209 },
2210
2211 State.CurlySuffixExpressionBegin => |opt_ctx| {
2212 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx }) catch unreachable;
2213 try stack.append(State { .IfToken = Token.Id.LBrace });
2214 try stack.append(State { .TypeExprBegin = opt_ctx });
21852215 continue;
21862216 },
21872217
2188 State.FnProtoAlign => |fn_proto| {
2189 const token = self.getNextToken();
2190 if (token.id == Token.Id.Keyword_align) {
2191 @panic("TODO fn proto align");
2218 State.CurlySuffixExpressionEnd => |opt_ctx| {
2219 const lhs = opt_ctx.get() ?? continue;
2220
2221 if (self.isPeekToken(Token.Id.Period)) {
2222 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeSuffixOp,
2223 ast.NodeSuffixOp {
2224 .base = undefined,
2225 .lhs = lhs,
2226 .op = ast.NodeSuffixOp.SuffixOp {
2227 .StructInitializer = ArrayList(&ast.NodeFieldInitializer).init(arena),
2228 },
2229 .rtoken = undefined,
2230 }
2231 );
2232 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2233 try stack.append(State { .IfToken = Token.Id.LBrace });
2234 try stack.append(State {
2235 .FieldInitListItemOrEnd = ListSave(&ast.NodeFieldInitializer) {
2236 .list = &node.op.StructInitializer,
2237 .ptr = &node.rtoken,
2238 }
2239 });
2240 continue;
21922241 }
2193 self.putBackToken(token);
2194 stack.append(State {
2195 .FnProtoReturnType = fn_proto,
2196 }) catch unreachable;
2242
2243 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeSuffixOp,
2244 ast.NodeSuffixOp {
2245 .base = undefined,
2246 .lhs = lhs,
2247 .op = ast.NodeSuffixOp.SuffixOp {
2248 .ArrayInitializer = ArrayList(&ast.Node).init(arena),
2249 },
2250 .rtoken = undefined,
2251 }
2252 );
2253 stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2254 try stack.append(State { .IfToken = Token.Id.LBrace });
2255 try stack.append(State {
2256 .ExprListItemOrEnd = ExprListCtx {
2257 .list = &node.op.ArrayInitializer,
2258 .end = Token.Id.RBrace,
2259 .ptr = &node.rtoken,
2260 }
2261 });
21972262 continue;
21982263 },
21992264
2200 State.FnProtoReturnType => |fn_proto| {
2201 const token = self.getNextToken();
2202 switch (token.id) {
2203 Token.Id.Bang => {
2204 fn_proto.return_type = ast.NodeFnProto.ReturnType { .InferErrorSet = undefined };
2205 stack.append(State {
2206 .TypeExprBegin = DestPtr {.Field = &fn_proto.return_type.InferErrorSet},
2207 }) catch unreachable;
2208 },
2209 else => {
2210 self.putBackToken(token);
2211 fn_proto.return_type = ast.NodeFnProto.ReturnType { .Explicit = undefined };
2212 stack.append(State {
2213 .TypeExprBegin = DestPtr {.Field = &fn_proto.return_type.Explicit},
2214 }) catch unreachable;
2215 },
2216 }
2217 if (token.id == Token.Id.Keyword_align) {
2218 @panic("TODO fn proto align");
2219 }
2265 State.TypeExprBegin => |opt_ctx| {
2266 stack.append(State { .TypeExprEnd = opt_ctx }) catch unreachable;
2267 try stack.append(State { .PrefixOpExpression = opt_ctx });
22202268 continue;
22212269 },
22222270
2223 State.ParamDecl => |fn_proto| {
2224 var token = self.getNextToken();
2225 if (token.id == Token.Id.RParen) {
2271 State.TypeExprEnd => |opt_ctx| {
2272 const lhs = opt_ctx.get() ?? continue;
2273
2274 if (self.eatToken(Token.Id.Bang)) |bang| {
2275 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2276 ast.NodeInfixOp {
2277 .base = undefined,
2278 .lhs = lhs,
2279 .op_token = bang,
2280 .op = ast.NodeInfixOp.InfixOp.ErrorUnion,
2281 .rhs = undefined,
2282 }
2283 );
2284 stack.append(State { .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable;
2285 try stack.append(State { .PrefixOpExpression = OptionalCtx { .Required = &node.rhs } });
22262286 continue;
22272287 }
2228 const param_decl = try self.createAttachParamDecl(arena, &fn_proto.params);
2229 if (token.id == Token.Id.Keyword_comptime) {
2230 param_decl.comptime_token = token;
2231 token = self.getNextToken();
2232 } else if (token.id == Token.Id.Keyword_noalias) {
2233 param_decl.noalias_token = token;
2234 token = self.getNextToken();
2235 }
2236 if (token.id == Token.Id.Identifier) {
2237 const next_token = self.getNextToken();
2238 if (next_token.id == Token.Id.Colon) {
2239 param_decl.name_token = token;
2240 token = self.getNextToken();
2241 } else {
2242 self.putBackToken(next_token);
2288 },
2289
2290 State.PrefixOpExpression => |opt_ctx| {
2291 const token = self.getNextToken();
2292 if (tokenIdToPrefixOp(token.id)) |prefix_id| {
2293 var node = try self.createToCtxNode(arena, opt_ctx, ast.NodePrefixOp,
2294 ast.NodePrefixOp {
2295 .base = undefined,
2296 .op_token = token,
2297 .op = prefix_id,
2298 .rhs = undefined,
2299 }
2300 );
2301
2302 // Treat '**' token as two derefs
2303 if (token.id == Token.Id.AsteriskAsterisk) {
2304 const child = try self.createNode(arena, ast.NodePrefixOp,
2305 ast.NodePrefixOp {
2306 .base = undefined,
2307 .op_token = token,
2308 .op = prefix_id,
2309 .rhs = undefined,
2310 }
2311 );
2312 node.rhs = &child.base;
2313 node = child;
2314 }
2315
2316 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
2317 if (node.op == ast.NodePrefixOp.PrefixOp.AddrOf) {
2318 try stack.append(State { .AddrOfModifiers = &node.op.AddrOf });
22432319 }
2244 }
2245 if (token.id == Token.Id.Ellipsis3) {
2246 param_decl.var_args_token = token;
2247 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
22482320 continue;
22492321 } else {
22502322 self.putBackToken(token);
2323 stack.append(State { .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;
2324 continue;
22512325 }
2326 },
22522327
2253 stack.append(State { .ParamDecl = fn_proto }) catch unreachable;
2254 try stack.append(State.ParamDeclComma);
2255 try stack.append(State {
2256 .TypeExprBegin = DestPtr {.Field = &param_decl.type_node}
2257 });
2328 State.SuffixOpExpressionBegin => |opt_ctx| {
2329 if (self.eatToken(Token.Id.Keyword_async)) |async_token| {
2330 const async_node = try self.createNode(arena, ast.NodeAsyncAttribute,
2331 ast.NodeAsyncAttribute {
2332 .base = undefined,
2333 .async_token = async_token,
2334 .allocator_type = null,
2335 .rangle_bracket = null,
2336 }
2337 );
2338 stack.append(State {
2339 .AsyncEnd = AsyncEndCtx {
2340 .ctx = opt_ctx,
2341 .attribute = async_node,
2342 }
2343 }) catch unreachable;
2344 try stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() });
2345 try stack.append(State { .PrimaryExpression = opt_ctx.toRequired() });
2346 try stack.append(State { .AsyncAllocator = async_node });
2347 continue;
2348 }
2349
2350 stack.append(State { .SuffixOpExpressionEnd = opt_ctx }) catch unreachable;
2351 try stack.append(State { .PrimaryExpression = opt_ctx });
22582352 continue;
22592353 },
22602354
2261 State.ParamDeclComma => {
2355 State.SuffixOpExpressionEnd => |opt_ctx| {
2356 const lhs = opt_ctx.get() ?? continue;
2357
22622358 const token = self.getNextToken();
22632359 switch (token.id) {
2264 Token.Id.RParen => {
2265 _ = stack.pop(); // pop off the ParamDecl
2360 Token.Id.LParen => {
2361 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeSuffixOp,
2362 ast.NodeSuffixOp {
2363 .base = undefined,
2364 .lhs = lhs,
2365 .op = ast.NodeSuffixOp.SuffixOp {
2366 .Call = ast.NodeSuffixOp.CallInfo {
2367 .params = ArrayList(&ast.Node).init(arena),
2368 .async_attr = null,
2369 }
2370 },
2371 .rtoken = undefined,
2372 }
2373 );
2374 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2375 try stack.append(State {
2376 .ExprListItemOrEnd = ExprListCtx {
2377 .list = &node.op.Call.params,
2378 .end = Token.Id.RParen,
2379 .ptr = &node.rtoken,
2380 }
2381 });
22662382 continue;
22672383 },
2268 Token.Id.Comma => continue,
2269 else => {
2270 try self.parseError(&stack, token, "expected ',' or ')', found {}", @tagName(token.id));
2384 Token.Id.LBracket => {
2385 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeSuffixOp,
2386 ast.NodeSuffixOp {
2387 .base = undefined,
2388 .lhs = lhs,
2389 .op = ast.NodeSuffixOp.SuffixOp {
2390 .ArrayAccess = undefined,
2391 },
2392 .rtoken = undefined
2393 }
2394 );
2395 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2396 try stack.append(State { .SliceOrArrayAccess = node });
2397 try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayAccess }});
22712398 continue;
22722399 },
2273 }
2274 },
2275
2276 State.FnDef => |fn_proto| {
2277 const token = self.getNextToken();
2278 switch(token.id) {
2279 Token.Id.LBrace => {
2280 const block = try self.createBlock(arena, (?Token)(null), token);
2281 fn_proto.body_node = &block.base;
2282 stack.append(State { .Block = block }) catch unreachable;
2400 Token.Id.Period => {
2401 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2402 ast.NodeInfixOp {
2403 .base = undefined,
2404 .lhs = lhs,
2405 .op_token = token,
2406 .op = ast.NodeInfixOp.InfixOp.Period,
2407 .rhs = undefined,
2408 }
2409 );
2410 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2411 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.rhs } });
22832412 continue;
22842413 },
2285 Token.Id.Semicolon => continue,
22862414 else => {
2287 try self.parseError(&stack, token, "expected ';' or '{{', found {}", @tagName(token.id));
2415 self.putBackToken(token);
22882416 continue;
22892417 },
22902418 }
22912419 },
22922420
2293 State.LabeledExpression => |ctx| {
2421 State.PrimaryExpression => |opt_ctx| {
22942422 const token = self.getNextToken();
22952423 switch (token.id) {
2296 Token.Id.LBrace => {
2297 const block = try self.createBlock(arena, (?Token)(ctx.label), token);
2298 ctx.dest_ptr.store(&block.base);
2299
2300 stack.append(State { .Block = block }) catch unreachable;
2424 Token.Id.IntegerLiteral => {
2425 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeStringLiteral, token);
23012426 continue;
23022427 },
2303 Token.Id.Keyword_while => {
2428 Token.Id.FloatLiteral => {
2429 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeFloatLiteral, token);
2430 continue;
2431 },
2432 Token.Id.CharLiteral => {
2433 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeCharLiteral, token);
2434 continue;
2435 },
2436 Token.Id.Keyword_undefined => {
2437 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeUndefinedLiteral, token);
2438 continue;
2439 },
2440 Token.Id.Keyword_true, Token.Id.Keyword_false => {
2441 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeBoolLiteral, token);
2442 continue;
2443 },
2444 Token.Id.Keyword_null => {
2445 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeNullLiteral, token);
2446 continue;
2447 },
2448 Token.Id.Keyword_this => {
2449 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeThisLiteral, token);
2450 continue;
2451 },
2452 Token.Id.Keyword_var => {
2453 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeVarType, token);
2454 continue;
2455 },
2456 Token.Id.Keyword_unreachable => {
2457 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeUnreachable, token);
2458 continue;
2459 },
2460 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
2461 opt_ctx.store((try self.parseStringLiteral(arena, token)) ?? unreachable);
2462 continue;
2463 },
2464 Token.Id.LParen => {
2465 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeGroupedExpression,
2466 ast.NodeGroupedExpression {
2467 .base = undefined,
2468 .lparen = token,
2469 .expr = undefined,
2470 .rparen = undefined,
2471 }
2472 );
23042473 stack.append(State {
2305 .While = LoopCtx {
2306 .label = ctx.label,
2307 .inline_token = null,
2308 .loop_token = token,
2309 .dest_ptr = ctx.dest_ptr,
2474 .ExpectTokenSave = ExpectTokenSave {
2475 .id = Token.Id.RParen,
2476 .ptr = &node.rparen,
23102477 }
23112478 }) catch unreachable;
2479 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
23122480 continue;
23132481 },
2314 Token.Id.Keyword_for => {
2482 Token.Id.Builtin => {
2483 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeBuiltinCall,
2484 ast.NodeBuiltinCall {
2485 .base = undefined,
2486 .builtin_token = token,
2487 .params = ArrayList(&ast.Node).init(arena),
2488 .rparen_token = undefined,
2489 }
2490 );
23152491 stack.append(State {
2316 .For = LoopCtx {
2317 .label = ctx.label,
2318 .inline_token = null,
2319 .loop_token = token,
2320 .dest_ptr = ctx.dest_ptr,
2492 .ExprListItemOrEnd = ExprListCtx {
2493 .list = &node.params,
2494 .end = Token.Id.RParen,
2495 .ptr = &node.rparen_token,
23212496 }
23222497 }) catch unreachable;
2498 try stack.append(State { .ExpectToken = Token.Id.LParen, });
23232499 continue;
23242500 },
2325 Token.Id.Keyword_inline => {
2501 Token.Id.LBracket => {
2502 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePrefixOp,
2503 ast.NodePrefixOp {
2504 .base = undefined,
2505 .op_token = token,
2506 .op = undefined,
2507 .rhs = undefined,
2508 }
2509 );
2510 stack.append(State { .SliceOrArrayType = node }) catch unreachable;
2511 continue;
2512 },
2513 Token.Id.Keyword_error => {
23262514 stack.append(State {
2327 .Inline = InlineCtx {
2328 .label = ctx.label,
2329 .inline_token = token,
2330 .dest_ptr = ctx.dest_ptr,
2515 .ErrorTypeOrSetDecl = ErrorTypeOrSetDeclCtx {
2516 .error_token = token,
2517 .opt_ctx = opt_ctx
23312518 }
23322519 }) catch unreachable;
23332520 continue;
23342521 },
2335 else => {
2336 try self.parseError(&stack, token, "expected 'while', 'for', 'inline' or '{{', found {}", @tagName(token.id));
2522 Token.Id.Keyword_packed => {
2523 stack.append(State {
2524 .ContainerKind = ContainerKindCtx {
2525 .opt_ctx = opt_ctx,
2526 .ltoken = token,
2527 .layout = ast.NodeContainerDecl.Layout.Packed,
2528 },
2529 }) catch unreachable;
23372530 continue;
23382531 },
2339 }
2340 },
2341
2342 State.Inline => |ctx| {
2343 const token = self.getNextToken();
2344 switch (token.id) {
2345 Token.Id.Keyword_while => {
2532 Token.Id.Keyword_extern => {
23462533 stack.append(State {
2347 .While = LoopCtx {
2348 .inline_token = ctx.inline_token,
2349 .label = ctx.label,
2350 .loop_token = token,
2351 .dest_ptr = ctx.dest_ptr,
2534 .ExternType = ExternTypeCtx {
2535 .opt_ctx = opt_ctx,
2536 .extern_token = token,
2537 },
2538 }) catch unreachable;
2539 continue;
2540 },
2541 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
2542 self.putBackToken(token);
2543 stack.append(State {
2544 .ContainerKind = ContainerKindCtx {
2545 .opt_ctx = opt_ctx,
2546 .ltoken = token,
2547 .layout = ast.NodeContainerDecl.Layout.Auto,
2548 },
2549 }) catch unreachable;
2550 continue;
2551 },
2552 Token.Id.Identifier => {
2553 stack.append(State {
2554 .MaybeLabeledExpression = MaybeLabeledExpressionCtx {
2555 .label = token,
2556 .opt_ctx = opt_ctx
23522557 }
23532558 }) catch unreachable;
23542559 continue;
23552560 },
2356 Token.Id.Keyword_for => {
2561 Token.Id.Keyword_fn => {
2562 const fn_proto = try self.createToCtxNode(arena, opt_ctx, ast.NodeFnProto,
2563 ast.NodeFnProto {
2564 .base = undefined,
2565 .visib_token = null,
2566 .name_token = null,
2567 .fn_token = token,
2568 .params = ArrayList(&ast.Node).init(arena),
2569 .return_type = undefined,
2570 .var_args_token = null,
2571 .extern_export_inline_token = null,
2572 .cc_token = null,
2573 .async_attr = null,
2574 .body_node = null,
2575 .lib_name = null,
2576 .align_expr = null,
2577 }
2578 );
2579 stack.append(State { .FnProto = fn_proto }) catch unreachable;
2580 continue;
2581 },
2582 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
2583 const fn_proto = try self.createToCtxNode(arena, opt_ctx, ast.NodeFnProto,
2584 ast.NodeFnProto {
2585 .base = undefined,
2586 .visib_token = null,
2587 .name_token = null,
2588 .fn_token = undefined,
2589 .params = ArrayList(&ast.Node).init(arena),
2590 .return_type = undefined,
2591 .var_args_token = null,
2592 .extern_export_inline_token = null,
2593 .cc_token = token,
2594 .async_attr = null,
2595 .body_node = null,
2596 .lib_name = null,
2597 .align_expr = null,
2598 }
2599 );
2600 stack.append(State { .FnProto = fn_proto }) catch unreachable;
2601 try stack.append(State {
2602 .ExpectTokenSave = ExpectTokenSave {
2603 .id = Token.Id.Keyword_fn,
2604 .ptr = &fn_proto.fn_token
2605 }
2606 });
2607 continue;
2608 },
2609 Token.Id.Keyword_asm => {
2610 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeAsm,
2611 ast.NodeAsm {
2612 .base = undefined,
2613 .asm_token = token,
2614 .volatile_token = null,
2615 .template = undefined,
2616 //.tokens = ArrayList(ast.NodeAsm.AsmToken).init(arena),
2617 .outputs = ArrayList(&ast.NodeAsmOutput).init(arena),
2618 .inputs = ArrayList(&ast.NodeAsmInput).init(arena),
2619 .cloppers = ArrayList(&ast.Node).init(arena),
2620 .rparen = undefined,
2621 }
2622 );
23572623 stack.append(State {
2358 .For = LoopCtx {
2359 .inline_token = ctx.inline_token,
2360 .label = ctx.label,
2361 .loop_token = token,
2362 .dest_ptr = ctx.dest_ptr,
2624 .ExpectTokenSave = ExpectTokenSave {
2625 .id = Token.Id.RParen,
2626 .ptr = &node.rparen,
2627 }
2628 }) catch unreachable;
2629 try stack.append(State { .AsmClopperItems = &node.cloppers });
2630 try stack.append(State { .IfToken = Token.Id.Colon });
2631 try stack.append(State { .AsmInputItems = &node.inputs });
2632 try stack.append(State { .IfToken = Token.Id.Colon });
2633 try stack.append(State { .AsmOutputItems = &node.outputs });
2634 try stack.append(State { .IfToken = Token.Id.Colon });
2635 try stack.append(State { .StringLiteral = OptionalCtx { .Required = &node.template } });
2636 try stack.append(State { .ExpectToken = Token.Id.LParen });
2637 try stack.append(State {
2638 .OptionalTokenSave = OptionalTokenSave {
2639 .id = Token.Id.Keyword_volatile,
2640 .ptr = &node.volatile_token,
2641 }
2642 });
2643 },
2644 Token.Id.Keyword_inline => {
2645 stack.append(State {
2646 .Inline = InlineCtx {
2647 .label = null,
2648 .inline_token = token,
2649 .opt_ctx = opt_ctx,
23632650 }
23642651 }) catch unreachable;
23652652 continue;
23662653 },
23672654 else => {
2368 try self.parseError(&stack, token, "expected 'while' or 'for', found {}", @tagName(token.id));
2655 if (!try self.parseBlockExpr(&stack, arena, opt_ctx, token)) {
2656 self.putBackToken(token);
2657 if (opt_ctx != OptionalCtx.Optional) {
2658 return self.parseError(token, "expected primary expression, found {}", @tagName(token.id));
2659 }
2660 }
23692661 continue;
2370 },
2662 }
23712663 }
23722664 },
23732665
2374 State.While => |ctx| {
2375 const node = try arena.create(ast.NodeWhile);
2376 *node = ast.NodeWhile {
2377 .base = self.initNode(ast.Node.Id.While),
2378 .label = ctx.label,
2379 .inline_token = ctx.inline_token,
2380 .while_token = ctx.loop_token,
2381 .condition = undefined,
2382 .payload = null,
2383 .continue_expr = null,
2384 .body = undefined,
2385 .@"else" = null,
2386 };
2387 ctx.dest_ptr.store(&node.base);
23882666
2389 stack.append(State { .Else = &node.@"else" }) catch unreachable;
2390 try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
2391 try stack.append(State { .WhileContinueExpr = &node.continue_expr });
2392 try stack.append(State { .PointerPayload = &node.payload });
2393 try stack.append(State { .ExpectToken = Token.Id.RParen });
2394 try stack.append(State { .Expression = DestPtr { .Field = &node.condition } });
2395 try stack.append(State { .ExpectToken = Token.Id.LParen });
2396 },
2667 State.ErrorTypeOrSetDecl => |ctx| {
2668 if (self.eatToken(Token.Id.LBrace) == null) {
2669 _ = try self.createToCtxLiteral(arena, ctx.opt_ctx, ast.NodeErrorType, ctx.error_token);
2670 continue;
2671 }
23972672
2398 State.For => |ctx| {
2399 const node = try arena.create(ast.NodeFor);
2400 *node = ast.NodeFor {
2401 .base = self.initNode(ast.Node.Id.For),
2402 .label = ctx.label,
2403 .inline_token = ctx.inline_token,
2404 .for_token = ctx.loop_token,
2405 .array_expr = undefined,
2406 .payload = null,
2407 .body = undefined,
2408 .@"else" = null,
2409 };
2410 ctx.dest_ptr.store(&node.base);
2673 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeErrorSetDecl,
2674 ast.NodeErrorSetDecl {
2675 .base = undefined,
2676 .error_token = ctx.error_token,
2677 .decls = ArrayList(&ast.Node).init(arena),
2678 .rbrace_token = undefined,
2679 }
2680 );
24112681
2412 stack.append(State { .Else = &node.@"else" }) catch unreachable;
2413 try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
2414 try stack.append(State { .PointerIndexPayload = &node.payload });
2415 try stack.append(State { .ExpectToken = Token.Id.RParen });
2416 try stack.append(State { .Expression = DestPtr { .Field = &node.array_expr } });
2417 try stack.append(State { .ExpectToken = Token.Id.LParen });
2682 stack.append(State {
2683 .IdentifierListItemOrEnd = ListSave(&ast.Node) {
2684 .list = &node.decls,
2685 .ptr = &node.rbrace_token,
2686 }
2687 }) catch unreachable;
2688 continue;
24182689 },
2419
2420 State.Block => |block| {
2690 State.StringLiteral => |opt_ctx| {
24212691 const token = self.getNextToken();
2422 switch (token.id) {
2423 Token.Id.RBrace => {
2424 block.rbrace = token;
2425 continue;
2426 },
2427 else => {
2692 opt_ctx.store(
2693 (try self.parseStringLiteral(arena, token)) ?? {
24282694 self.putBackToken(token);
2429 stack.append(State { .Block = block }) catch unreachable;
2430 try stack.append(State { .Statement = block });
2695 if (opt_ctx != OptionalCtx.Optional) {
2696 return self.parseError(token, "expected primary expression, found {}", @tagName(token.id));
2697 }
2698
24312699 continue;
2432 },
2433 }
2700 }
2701 );
24342702 },
2703 State.Identifier => |opt_ctx| {
2704 if (self.eatToken(Token.Id.Identifier)) |ident_token| {
2705 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeIdentifier, ident_token);
2706 continue;
2707 }
24352708
2436 State.Statement => |block| {
2437 const next = self.getNextToken();
2438 switch (next.id) {
2439 Token.Id.Keyword_comptime => {
2440 const mut_token = self.getNextToken();
2441 if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) {
2442 // TODO shouldn't need these casts
2443 const var_decl = try self.createAttachVarDecl(arena, &block.statements, (?Token)(null),
2444 mut_token, (?Token)(next), (?Token)(null), null);
2445 stack.append(State { .VarDecl = var_decl }) catch unreachable;
2446 continue;
2447 } else {
2448 self.putBackToken(mut_token);
2449 self.putBackToken(next);
2450 const statememt = try block.statements.addOne();
2451 stack.append(State { .Semicolon = statememt }) catch unreachable;
2452 try stack.append(State { .Expression = DestPtr{.Field = statememt } });
2453 }
2454 },
2455 Token.Id.Keyword_var, Token.Id.Keyword_const => {
2456 const var_decl = try self.createAttachVarDecl(arena, &block.statements, (?Token)(null),
2457 next, (?Token)(null), (?Token)(null), null);
2458 stack.append(State { .VarDecl = var_decl }) catch unreachable;
2459 continue;
2460 },
2461 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
2462 const node = try arena.create(ast.NodeDefer);
2463 *node = ast.NodeDefer {
2464 .base = self.initNode(ast.Node.Id.Defer),
2465 .defer_token = next,
2466 .kind = switch (next.id) {
2467 Token.Id.Keyword_defer => ast.NodeDefer.Kind.Unconditional,
2468 Token.Id.Keyword_errdefer => ast.NodeDefer.Kind.Error,
2469 else => unreachable,
2470 },
2471 .expr = undefined,
2472 };
2473 try block.statements.append(&node.base);
2709 if (opt_ctx != OptionalCtx.Optional) {
2710 const token = self.getNextToken();
2711 return self.parseError(token, "expected identifier, found {}", @tagName(token.id));
2712 }
2713 },
24742714
2475 stack.append(State { .Semicolon = &node.base }) catch unreachable;
2476 try stack.append(State { .AssignmentExpressionBegin = DestPtr{.Field = &node.expr } });
2477 continue;
2478 },
2479 Token.Id.LBrace => {
2480 const inner_block = try self.createBlock(arena, (?Token)(null), next);
2481 try block.statements.append(&inner_block.base);
24822715
2483 stack.append(State { .Block = inner_block }) catch unreachable;
2484 continue;
2485 },
2486 else => {
2487 self.putBackToken(next);
2488 const statememt = try block.statements.addOne();
2489 stack.append(State { .Semicolon = statememt }) catch unreachable;
2490 try stack.append(State { .AssignmentExpressionBegin = DestPtr{.Field = statememt } });
2491 continue;
2492 }
2716 State.ExpectToken => |token_id| {
2717 _ = try self.expectToken(token_id);
2718 continue;
2719 },
2720 State.ExpectTokenSave => |expect_token_save| {
2721 *expect_token_save.ptr = try self.expectToken(expect_token_save.id);
2722 continue;
2723 },
2724 State.IfToken => |token_id| {
2725 if (self.eatToken(token_id)) |_| {
2726 continue;
24932727 }
24942728
2729 _ = stack.pop();
2730 continue;
24952731 },
2732 State.IfTokenSave => |if_token_save| {
2733 if (self.eatToken(if_token_save.id)) |token| {
2734 *if_token_save.ptr = token;
2735 continue;
2736 }
24962737
2497 State.Semicolon => |node_ptr| {
2498 const node = *node_ptr;
2499 if (requireSemiColon(node)) {
2500 _ = (try self.eatToken(&stack, Token.Id.Semicolon)) ?? continue;
2738 _ = stack.pop();
2739 continue;
2740 },
2741 State.OptionalTokenSave => |optional_token_save| {
2742 if (self.eatToken(optional_token_save.id)) |token| {
2743 *optional_token_save.ptr = token;
2744 continue;
25012745 }
2502 }
2746
2747 continue;
2748 },
25032749 }
25042750 }
25052751 }
......@@ -2530,7 +2776,7 @@ pub const Parser = struct {
25302776 continue;
25312777 }
25322778
2533 n = while_node.body;
2779 return while_node.body.id != ast.Node.Id.Block;
25342780 },
25352781 ast.Node.Id.For => {
25362782 const for_node = @fieldParentPtr(ast.NodeFor, "base", n);
......@@ -2539,7 +2785,7 @@ pub const Parser = struct {
25392785 continue;
25402786 }
25412787
2542 n = for_node.body;
2788 return for_node.body.id != ast.Node.Id.Block;
25432789 },
25442790 ast.Node.Id.If => {
25452791 const if_node = @fieldParentPtr(ast.NodeIf, "base", n);
......@@ -2548,25 +2794,25 @@ pub const Parser = struct {
25482794 continue;
25492795 }
25502796
2551 n = if_node.body;
2797 return if_node.body.id != ast.Node.Id.Block;
25522798 },
25532799 ast.Node.Id.Else => {
25542800 const else_node = @fieldParentPtr(ast.NodeElse, "base", n);
25552801 n = else_node.body;
2802 continue;
25562803 },
25572804 ast.Node.Id.Defer => {
25582805 const defer_node = @fieldParentPtr(ast.NodeDefer, "base", n);
2559 n = defer_node.expr;
2806 return defer_node.expr.id != ast.Node.Id.Block;
25602807 },
25612808 ast.Node.Id.Comptime => {
25622809 const comptime_node = @fieldParentPtr(ast.NodeComptime, "base", n);
2563 n = comptime_node.expr;
2810 return comptime_node.expr.id != ast.Node.Id.Block;
25642811 },
25652812 ast.Node.Id.Suspend => {
25662813 const suspend_node = @fieldParentPtr(ast.NodeSuspend, "base", n);
25672814 if (suspend_node.body) |body| {
2568 n = body;
2569 continue;
2815 return body.id != ast.Node.Id.Block;
25702816 }
25712817
25722818 return true;
......@@ -2576,22 +2822,158 @@ pub const Parser = struct {
25762822 }
25772823 }
25782824
2579 fn commaOrEnd(self: &Parser, stack: &ArrayList(State), end: &const Token.Id, maybe_ptr: ?&Token, state_after_comma: &const State) !void {
2580 var token = self.getNextToken();
2825 fn parseStringLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !?&ast.Node {
25812826 switch (token.id) {
2582 Token.Id.Comma => {
2583 stack.append(state_after_comma) catch unreachable;
2827 Token.Id.StringLiteral => {
2828 return &(try self.createLiteral(arena, ast.NodeStringLiteral, token)).base;
25842829 },
2585 else => {
2586 const IdTag = @TagType(Token.Id);
2587 if (IdTag(*end) == token.id) {
2588 if (maybe_ptr) |ptr| {
2589 *ptr = token;
2830 Token.Id.MultilineStringLiteralLine => {
2831 const node = try self.createNode(arena, ast.NodeMultilineStringLiteral,
2832 ast.NodeMultilineStringLiteral {
2833 .base = undefined,
2834 .tokens = ArrayList(Token).init(arena),
2835 }
2836 );
2837 try node.tokens.append(token);
2838 while (true) {
2839 const multiline_str = self.getNextToken();
2840 if (multiline_str.id != Token.Id.MultilineStringLiteralLine) {
2841 self.putBackToken(multiline_str);
2842 break;
2843 }
2844
2845 try node.tokens.append(multiline_str);
2846 }
2847
2848 return &node.base;
2849 },
2850 // TODO: We shouldn't need a cast, but:
2851 // zig: /home/jc/Documents/zig/src/ir.cpp:7962: TypeTableEntry* ir_resolve_peer_types(IrAnalyze*, AstNode*, IrInstruction**, size_t): Assertion `err_set_type != nullptr' failed.
2852 else => return (?&ast.Node)(null),
2853 }
2854 }
2855
2856 fn parseBlockExpr(self: &Parser, stack: &ArrayList(State), arena: &mem.Allocator, ctx: &const OptionalCtx, token: &const Token) !bool {
2857 switch (token.id) {
2858 Token.Id.Keyword_suspend => {
2859 const node = try self.createToCtxNode(arena, ctx, ast.NodeSuspend,
2860 ast.NodeSuspend {
2861 .base = undefined,
2862 .suspend_token = *token,
2863 .payload = null,
2864 .body = null,
2865 }
2866 );
2867
2868 stack.append(State { .SuspendBody = node }) catch unreachable;
2869 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
2870 return true;
2871 },
2872 Token.Id.Keyword_if => {
2873 const node = try self.createToCtxNode(arena, ctx, ast.NodeIf,
2874 ast.NodeIf {
2875 .base = undefined,
2876 .if_token = *token,
2877 .condition = undefined,
2878 .payload = null,
2879 .body = undefined,
2880 .@"else" = null,
2881 }
2882 );
2883
2884 stack.append(State { .Else = &node.@"else" }) catch unreachable;
2885 try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } });
2886 try stack.append(State { .PointerPayload = OptionalCtx { .Optional = &node.payload } });
2887 try stack.append(State { .ExpectToken = Token.Id.RParen });
2888 try stack.append(State { .Expression = OptionalCtx { .Required = &node.condition } });
2889 try stack.append(State { .ExpectToken = Token.Id.LParen });
2890 return true;
2891 },
2892 Token.Id.Keyword_while => {
2893 stack.append(State {
2894 .While = LoopCtx {
2895 .label = null,
2896 .inline_token = null,
2897 .loop_token = *token,
2898 .opt_ctx = *ctx,
2899 }
2900 }) catch unreachable;
2901 return true;
2902 },
2903 Token.Id.Keyword_for => {
2904 stack.append(State {
2905 .For = LoopCtx {
2906 .label = null,
2907 .inline_token = null,
2908 .loop_token = *token,
2909 .opt_ctx = *ctx,
2910 }
2911 }) catch unreachable;
2912 return true;
2913 },
2914 Token.Id.Keyword_switch => {
2915 const node = try self.createToCtxNode(arena, ctx, ast.NodeSwitch,
2916 ast.NodeSwitch {
2917 .base = undefined,
2918 .switch_token = *token,
2919 .expr = undefined,
2920 .cases = ArrayList(&ast.NodeSwitchCase).init(arena),
2921 .rbrace = undefined,
2922 }
2923 );
2924
2925 stack.append(State {
2926 .SwitchCaseOrEnd = ListSave(&ast.NodeSwitchCase) {
2927 .list = &node.cases,
2928 .ptr = &node.rbrace,
2929 },
2930 }) catch unreachable;
2931 try stack.append(State { .ExpectToken = Token.Id.LBrace });
2932 try stack.append(State { .ExpectToken = Token.Id.RParen });
2933 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
2934 try stack.append(State { .ExpectToken = Token.Id.LParen });
2935 return true;
2936 },
2937 Token.Id.Keyword_comptime => {
2938 const node = try self.createToCtxNode(arena, ctx, ast.NodeComptime,
2939 ast.NodeComptime {
2940 .base = undefined,
2941 .comptime_token = *token,
2942 .expr = undefined,
2943 }
2944 );
2945 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
2946 return true;
2947 },
2948 Token.Id.LBrace => {
2949 const block = try self.createToCtxNode(arena, ctx, ast.NodeBlock,
2950 ast.NodeBlock {
2951 .base = undefined,
2952 .label = null,
2953 .lbrace = *token,
2954 .statements = ArrayList(&ast.Node).init(arena),
2955 .rbrace = undefined,
25902956 }
2591 return;
2957 );
2958 stack.append(State { .Block = block }) catch unreachable;
2959 return true;
2960 },
2961 else => {
2962 return false;
2963 }
2964 }
2965 }
2966
2967 fn expectCommaOrEnd(self: &Parser, end: @TagType(Token.Id)) !?Token {
2968 var token = self.getNextToken();
2969 switch (token.id) {
2970 Token.Id.Comma => return null,
2971 else => {
2972 if (end == token.id) {
2973 return token;
25922974 }
25932975
2594 try self.parseError(stack, token, "expected ',' or {}, found {}", @tagName(*end), @tagName(token.id));
2976 return self.parseError(token, "expected ',' or {}, found {}", @tagName(end), @tagName(token.id));
25952977 },
25962978 }
25972979 }
......@@ -2600,84 +2982,82 @@ pub const Parser = struct {
26002982 // TODO: We have to cast all cases because of this:
26012983 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
26022984 return switch (*id) {
2603 Token.Id.AmpersandEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitAnd),
2604 Token.Id.AngleBracketAngleBracketLeftEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitShiftLeft),
2605 Token.Id.AngleBracketAngleBracketRightEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitShiftRight),
2606 Token.Id.AsteriskEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignTimes),
2607 Token.Id.AsteriskPercentEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignTimesWarp),
2608 Token.Id.CaretEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitXor),
2609 Token.Id.Equal => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Assign),
2610 Token.Id.MinusEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignMinus),
2611 Token.Id.MinusPercentEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignMinusWrap),
2612 Token.Id.PercentEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignMod),
2613 Token.Id.PipeEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitOr),
2614 Token.Id.PlusEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignPlus),
2615 Token.Id.PlusPercentEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignPlusWrap),
2616 Token.Id.SlashEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignDiv),
2985 Token.Id.AmpersandEqual => ast.NodeInfixOp.InfixOp { .AssignBitAnd = void{} },
2986 Token.Id.AngleBracketAngleBracketLeftEqual => ast.NodeInfixOp.InfixOp { .AssignBitShiftLeft = void{} },
2987 Token.Id.AngleBracketAngleBracketRightEqual => ast.NodeInfixOp.InfixOp { .AssignBitShiftRight = void{} },
2988 Token.Id.AsteriskEqual => ast.NodeInfixOp.InfixOp { .AssignTimes = void{} },
2989 Token.Id.AsteriskPercentEqual => ast.NodeInfixOp.InfixOp { .AssignTimesWarp = void{} },
2990 Token.Id.CaretEqual => ast.NodeInfixOp.InfixOp { .AssignBitXor = void{} },
2991 Token.Id.Equal => ast.NodeInfixOp.InfixOp { .Assign = void{} },
2992 Token.Id.MinusEqual => ast.NodeInfixOp.InfixOp { .AssignMinus = void{} },
2993 Token.Id.MinusPercentEqual => ast.NodeInfixOp.InfixOp { .AssignMinusWrap = void{} },
2994 Token.Id.PercentEqual => ast.NodeInfixOp.InfixOp { .AssignMod = void{} },
2995 Token.Id.PipeEqual => ast.NodeInfixOp.InfixOp { .AssignBitOr = void{} },
2996 Token.Id.PlusEqual => ast.NodeInfixOp.InfixOp { .AssignPlus = void{} },
2997 Token.Id.PlusPercentEqual => ast.NodeInfixOp.InfixOp { .AssignPlusWrap = void{} },
2998 Token.Id.SlashEqual => ast.NodeInfixOp.InfixOp { .AssignDiv = void{} },
26172999 else => null,
26183000 };
26193001 }
26203002
2621 fn tokenIdToComparison(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
2622 // TODO: We have to cast all cases because of this:
2623 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
2624 return switch (*id) {
2625 Token.Id.BangEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.BangEqual),
2626 Token.Id.EqualEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.EqualEqual),
2627 Token.Id.AngleBracketLeft => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.LessThan),
2628 Token.Id.AngleBracketLeftEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.LessOrEqual),
2629 Token.Id.AngleBracketRight => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.GreaterThan),
2630 Token.Id.AngleBracketRightEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.GreaterOrEqual),
3003 fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
3004 return switch (id) {
3005 Token.Id.Keyword_catch => ast.NodeInfixOp.InfixOp { .Catch = null },
3006 Token.Id.QuestionMarkQuestionMark => ast.NodeInfixOp.InfixOp { .UnwrapMaybe = void{} },
26313007 else => null,
26323008 };
26333009 }
26343010
2635 fn tokenIdToBitShift(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
2636 // TODO: We have to cast all cases because of this:
2637 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
2638 return switch (*id) {
2639 Token.Id.AngleBracketAngleBracketLeft => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.BitShiftLeft),
2640 Token.Id.AngleBracketAngleBracketRight => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.BitShiftRight),
3011 fn tokenIdToComparison(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
3012 return switch (id) {
3013 Token.Id.BangEqual => ast.NodeInfixOp.InfixOp { .BangEqual = void{} },
3014 Token.Id.EqualEqual => ast.NodeInfixOp.InfixOp { .EqualEqual = void{} },
3015 Token.Id.AngleBracketLeft => ast.NodeInfixOp.InfixOp { .LessThan = void{} },
3016 Token.Id.AngleBracketLeftEqual => ast.NodeInfixOp.InfixOp { .LessOrEqual = void{} },
3017 Token.Id.AngleBracketRight => ast.NodeInfixOp.InfixOp { .GreaterThan = void{} },
3018 Token.Id.AngleBracketRightEqual => ast.NodeInfixOp.InfixOp { .GreaterOrEqual = void{} },
26413019 else => null,
26423020 };
26433021 }
26443022
2645 fn tokenIdToAddition(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
2646 // TODO: We have to cast all cases because of this:
2647 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
2648 return switch (*id) {
2649 Token.Id.Minus => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Sub),
2650 Token.Id.MinusPercent => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.SubWrap),
2651 Token.Id.Plus => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Add),
2652 Token.Id.PlusPercent => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AddWrap),
2653 Token.Id.PlusPlus => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.ArrayCat),
3023 fn tokenIdToBitShift(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
3024 return switch (id) {
3025 Token.Id.AngleBracketAngleBracketLeft => ast.NodeInfixOp.InfixOp { .BitShiftLeft = void{} },
3026 Token.Id.AngleBracketAngleBracketRight => ast.NodeInfixOp.InfixOp { .BitShiftRight = void{} },
26543027 else => null,
26553028 };
26563029 }
26573030
2658 fn tokenIdToMultiply(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
2659 // TODO: We have to cast all cases because of this:
2660 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
2661 return switch (*id) {
2662 Token.Id.Slash => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Div),
2663 Token.Id.Asterisk => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Mult),
2664 Token.Id.AsteriskAsterisk => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.ArrayMult),
2665 Token.Id.AsteriskPercent => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.MultWrap),
2666 Token.Id.Percent => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Mod),
2667 Token.Id.PipePipe => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.MergeErrorSets),
3031 fn tokenIdToAddition(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
3032 return switch (id) {
3033 Token.Id.Minus => ast.NodeInfixOp.InfixOp { .Sub = void{} },
3034 Token.Id.MinusPercent => ast.NodeInfixOp.InfixOp { .SubWrap = void{} },
3035 Token.Id.Plus => ast.NodeInfixOp.InfixOp { .Add = void{} },
3036 Token.Id.PlusPercent => ast.NodeInfixOp.InfixOp { .AddWrap = void{} },
3037 Token.Id.PlusPlus => ast.NodeInfixOp.InfixOp { .ArrayCat = void{} },
26683038 else => null,
26693039 };
26703040 }
26713041
2672 fn tokenIdToPrefixOp(id: &const Token.Id) ?ast.NodePrefixOp.PrefixOp {
2673 // TODO: We have to cast all cases because of this:
2674 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
2675 return switch (*id) {
2676 Token.Id.Bang => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.BoolNot),
2677 Token.Id.Tilde => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.BitNot),
2678 Token.Id.Minus => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.Negation),
2679 Token.Id.MinusPercent => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.NegationWrap),
2680 Token.Id.Asterisk => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.Deref),
3042 fn tokenIdToMultiply(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
3043 return switch (id) {
3044 Token.Id.Slash => ast.NodeInfixOp.InfixOp { .Div = void{} },
3045 Token.Id.Asterisk => ast.NodeInfixOp.InfixOp { .Mult = void{} },
3046 Token.Id.AsteriskAsterisk => ast.NodeInfixOp.InfixOp { .ArrayMult = void{} },
3047 Token.Id.AsteriskPercent => ast.NodeInfixOp.InfixOp { .MultWrap = void{} },
3048 Token.Id.Percent => ast.NodeInfixOp.InfixOp { .Mod = void{} },
3049 Token.Id.PipePipe => ast.NodeInfixOp.InfixOp { .MergeErrorSets = void{} },
3050 else => null,
3051 };
3052 }
3053
3054 fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.NodePrefixOp.PrefixOp {
3055 return switch (id) {
3056 Token.Id.Bang => ast.NodePrefixOp.PrefixOp { .BoolNot = void{} },
3057 Token.Id.Tilde => ast.NodePrefixOp.PrefixOp { .BitNot = void{} },
3058 Token.Id.Minus => ast.NodePrefixOp.PrefixOp { .Negation = void{} },
3059 Token.Id.MinusPercent => ast.NodePrefixOp.PrefixOp { .NegationWrap = void{} },
3060 Token.Id.Asterisk, Token.Id.AsteriskAsterisk => ast.NodePrefixOp.PrefixOp { .Deref = void{} },
26813061 Token.Id.Ampersand => ast.NodePrefixOp.PrefixOp {
26823062 .AddrOf = ast.NodePrefixOp.AddrOfInfo {
26833063 .align_expr = null,
......@@ -2687,307 +3067,93 @@ pub const Parser = struct {
26873067 .volatile_token = null,
26883068 },
26893069 },
2690 Token.Id.QuestionMark => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.MaybeType),
2691 Token.Id.QuestionMarkQuestionMark => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.UnwrapMaybe),
2692 Token.Id.Keyword_await => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.Await),
3070 Token.Id.QuestionMark => ast.NodePrefixOp.PrefixOp { .MaybeType = void{} },
3071 Token.Id.QuestionMarkQuestionMark => ast.NodePrefixOp.PrefixOp { .UnwrapMaybe = void{} },
3072 Token.Id.Keyword_await => ast.NodePrefixOp.PrefixOp { .Await = void{} },
3073 Token.Id.Keyword_try => ast.NodePrefixOp.PrefixOp { .Try = void{ } },
26933074 else => null,
26943075 };
26953076 }
26963077
2697 fn initNode(self: &Parser, id: ast.Node.Id) ast.Node {
2698 if (self.pending_line_comment_node) |comment_node| {
2699 self.pending_line_comment_node = null;
2700 return ast.Node {.id = id, .comment = comment_node};
2701 }
2702 return ast.Node {.id = id, .comment = null };
2703 }
2704
2705 fn createRoot(self: &Parser, arena: &mem.Allocator) !&ast.NodeRoot {
2706 const node = try arena.create(ast.NodeRoot);
2707
2708 *node = ast.NodeRoot {
2709 .base = self.initNode(ast.Node.Id.Root),
2710 .decls = ArrayList(&ast.Node).init(arena),
2711 // initialized when we get the eof token
2712 .eof_token = undefined,
2713 };
2714 return node;
2715 }
2716
2717 fn createVarDecl(self: &Parser, arena: &mem.Allocator, visib_token: &const ?Token, mut_token: &const Token,
2718 comptime_token: &const ?Token, extern_token: &const ?Token, lib_name: ?&ast.Node) !&ast.NodeVarDecl
2719 {
2720 const node = try arena.create(ast.NodeVarDecl);
2721
2722 *node = ast.NodeVarDecl {
2723 .base = self.initNode(ast.Node.Id.VarDecl),
2724 .visib_token = *visib_token,
2725 .mut_token = *mut_token,
2726 .comptime_token = *comptime_token,
2727 .extern_token = *extern_token,
2728 .type_node = null,
2729 .align_node = null,
2730 .init_node = null,
2731 .lib_name = lib_name,
2732 // initialized later
2733 .name_token = undefined,
2734 .eq_token = undefined,
2735 .semicolon_token = undefined,
2736 };
2737 return node;
2738 }
2739
2740 fn createStringLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !&ast.NodeStringLiteral {
2741 const node = try arena.create(ast.NodeStringLiteral);
2742
2743 assert(token.id == Token.Id.StringLiteral);
2744 *node = ast.NodeStringLiteral {
2745 .base = self.initNode(ast.Node.Id.StringLiteral),
2746 .token = *token,
2747 };
2748 return node;
2749 }
2750
2751 fn createTestDecl(self: &Parser, arena: &mem.Allocator, test_token: &const Token, name: &ast.Node,
2752 block: &ast.NodeBlock) !&ast.NodeTestDecl
2753 {
2754 const node = try arena.create(ast.NodeTestDecl);
2755
2756 *node = ast.NodeTestDecl {
2757 .base = self.initNode(ast.Node.Id.TestDecl),
2758 .test_token = *test_token,
2759 .name = name,
2760 .body_node = &block.base,
2761 };
2762 return node;
2763 }
2764
2765 fn createFnProto(self: &Parser, arena: &mem.Allocator, fn_token: &const Token, extern_token: &const ?Token,
2766 lib_name: ?&ast.Node, cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) !&ast.NodeFnProto
2767 {
2768 const node = try arena.create(ast.NodeFnProto);
2769
2770 *node = ast.NodeFnProto {
2771 .base = self.initNode(ast.Node.Id.FnProto),
2772 .visib_token = *visib_token,
2773 .name_token = null,
2774 .fn_token = *fn_token,
2775 .params = ArrayList(&ast.Node).init(arena),
2776 .return_type = undefined,
2777 .var_args_token = null,
2778 .extern_token = *extern_token,
2779 .inline_token = *inline_token,
2780 .cc_token = *cc_token,
2781 .async_attr = null,
2782 .body_node = null,
2783 .lib_name = lib_name,
2784 .align_expr = null,
2785 };
2786 return node;
2787 }
2788
2789 fn createParamDecl(self: &Parser, arena: &mem.Allocator) !&ast.NodeParamDecl {
2790 const node = try arena.create(ast.NodeParamDecl);
2791
2792 *node = ast.NodeParamDecl {
2793 .base = self.initNode(ast.Node.Id.ParamDecl),
2794 .comptime_token = null,
2795 .noalias_token = null,
2796 .name_token = null,
2797 .type_node = undefined,
2798 .var_args_token = null,
2799 };
2800 return node;
2801 }
2802
2803 fn createBlock(self: &Parser, arena: &mem.Allocator, label: &const ?Token, lbrace: &const Token) !&ast.NodeBlock {
2804 const node = try arena.create(ast.NodeBlock);
2805
2806 *node = ast.NodeBlock {
2807 .base = self.initNode(ast.Node.Id.Block),
2808 .label = *label,
2809 .lbrace = *lbrace,
2810 .statements = ArrayList(&ast.Node).init(arena),
2811 .rbrace = undefined,
2812 };
2813 return node;
2814 }
2815
2816 fn createControlFlowExpr(self: &Parser, arena: &mem.Allocator, ltoken: &const Token,
2817 kind: &const ast.NodeControlFlowExpression.Kind) !&ast.NodeControlFlowExpression
2818 {
2819 const node = try arena.create(ast.NodeControlFlowExpression);
2820 *node = ast.NodeControlFlowExpression {
2821 .base = self.initNode(ast.Node.Id.ControlFlowExpression),
2822 .ltoken = *ltoken,
2823 .kind = *kind,
2824 .rhs = null,
2825 };
2826 return node;
2827 }
2828
2829 fn createInfixOp(self: &Parser, arena: &mem.Allocator, op_token: &const Token, op: &const ast.NodeInfixOp.InfixOp) !&ast.NodeInfixOp {
2830 const node = try arena.create(ast.NodeInfixOp);
2831
2832 *node = ast.NodeInfixOp {
2833 .base = self.initNode(ast.Node.Id.InfixOp),
2834 .op_token = *op_token,
2835 .lhs = undefined,
2836 .op = *op,
2837 .rhs = undefined,
2838 };
2839 return node;
2840 }
2841
2842 fn createPrefixOp(self: &Parser, arena: &mem.Allocator, op_token: &const Token, op: &const ast.NodePrefixOp.PrefixOp) !&ast.NodePrefixOp {
2843 const node = try arena.create(ast.NodePrefixOp);
2844
2845 *node = ast.NodePrefixOp {
2846 .base = self.initNode(ast.Node.Id.PrefixOp),
2847 .op_token = *op_token,
2848 .op = *op,
2849 .rhs = undefined,
2850 };
2851 return node;
2852 }
2853
2854 fn createSuffixOp(self: &Parser, arena: &mem.Allocator, op: &const ast.NodeSuffixOp.SuffixOp) !&ast.NodeSuffixOp {
2855 const node = try arena.create(ast.NodeSuffixOp);
2856
2857 *node = ast.NodeSuffixOp {
2858 .base = self.initNode(ast.Node.Id.SuffixOp),
2859 .lhs = undefined,
2860 .op = *op,
2861 .rtoken = undefined,
2862 };
2863 return node;
2864 }
2865
2866 fn createIdentifier(self: &Parser, arena: &mem.Allocator, name_token: &const Token) !&ast.NodeIdentifier {
2867 const node = try arena.create(ast.NodeIdentifier);
2868
2869 *node = ast.NodeIdentifier {
2870 .base = self.initNode(ast.Node.Id.Identifier),
2871 .name_token = *name_token,
2872 };
2873 return node;
2874 }
2875
2876 fn createIntegerLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !&ast.NodeIntegerLiteral {
2877 const node = try arena.create(ast.NodeIntegerLiteral);
2878
2879 *node = ast.NodeIntegerLiteral {
2880 .base = self.initNode(ast.Node.Id.IntegerLiteral),
2881 .token = *token,
3078 fn createNode(self: &Parser, arena: &mem.Allocator, comptime T: type, init_to: &const T) !&T {
3079 const node = try arena.create(T);
3080 *node = *init_to;
3081 node.base = blk: {
3082 const id = ast.Node.typeToId(T);
3083 if (self.pending_line_comment_node) |comment_node| {
3084 self.pending_line_comment_node = null;
3085 break :blk ast.Node {.id = id, .comment = comment_node};
3086 }
3087 break :blk ast.Node {.id = id, .comment = null };
28823088 };
2883 return node;
2884 }
2885
2886 fn createFloatLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !&ast.NodeFloatLiteral {
2887 const node = try arena.create(ast.NodeFloatLiteral);
28883089
2889 *node = ast.NodeFloatLiteral {
2890 .base = self.initNode(ast.Node.Id.FloatLiteral),
2891 .token = *token,
2892 };
28933090 return node;
28943091 }
28953092
2896 fn createUndefined(self: &Parser, arena: &mem.Allocator, token: &const Token) !&ast.NodeUndefinedLiteral {
2897 const node = try arena.create(ast.NodeUndefinedLiteral);
3093 fn createAttachNode(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node), comptime T: type, init_to: &const T) !&T {
3094 const node = try self.createNode(arena, T, init_to);
3095 try list.append(&node.base);
28983096
2899 *node = ast.NodeUndefinedLiteral {
2900 .base = self.initNode(ast.Node.Id.UndefinedLiteral),
2901 .token = *token,
2902 };
29033097 return node;
29043098 }
29053099
2906 fn createAttachIdentifier(self: &Parser, arena: &mem.Allocator, dest_ptr: &const DestPtr, name_token: &const Token) !&ast.NodeIdentifier {
2907 const node = try self.createIdentifier(arena, name_token);
2908 try dest_ptr.store(&node.base);
2909 return node;
2910 }
3100 fn createToCtxNode(self: &Parser, arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, init_to: &const T) !&T {
3101 const node = try self.createNode(arena, T, init_to);
3102 opt_ctx.store(&node.base);
29113103
2912 fn createAttachParamDecl(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node)) !&ast.NodeParamDecl {
2913 const node = try self.createParamDecl(arena);
2914 try list.append(&node.base);
29153104 return node;
29163105 }
29173106
2918 fn createAttachFnProto(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node), fn_token: &const Token,
2919 extern_token: &const ?Token, lib_name: ?&ast.Node, cc_token: &const ?Token, visib_token: &const ?Token,
2920 inline_token: &const ?Token) !&ast.NodeFnProto
2921 {
2922 const node = try self.createFnProto(arena, fn_token, extern_token, lib_name, cc_token, visib_token, inline_token);
2923 try list.append(&node.base);
2924 return node;
3107 fn createLiteral(self: &Parser, arena: &mem.Allocator, comptime T: type, token: &const Token) !&T {
3108 return self.createNode(arena, T,
3109 T {
3110 .base = undefined,
3111 .token = *token,
3112 }
3113 );
29253114 }
29263115
2927 fn createAttachVarDecl(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node),
2928 visib_token: &const ?Token, mut_token: &const Token, comptime_token: &const ?Token,
2929 extern_token: &const ?Token, lib_name: ?&ast.Node) !&ast.NodeVarDecl
2930 {
2931 const node = try self.createVarDecl(arena, visib_token, mut_token, comptime_token, extern_token, lib_name);
2932 try list.append(&node.base);
2933 return node;
2934 }
3116 fn createToCtxLiteral(self: &Parser, arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, token: &const Token) !&T {
3117 const node = try self.createLiteral(arena, T, token);
3118 opt_ctx.store(&node.base);
29353119
2936 fn createAttachTestDecl(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node),
2937 test_token: &const Token, name: &ast.Node, block: &ast.NodeBlock) !&ast.NodeTestDecl
2938 {
2939 const node = try self.createTestDecl(arena, test_token, name, block);
2940 try list.append(&node.base);
29413120 return node;
29423121 }
29433122
2944 fn parseError(self: &Parser, stack: &ArrayList(State), token: &const Token, comptime fmt: []const u8, args: ...) !void {
2945 // Before reporting an error. We pop the stack to see if our state was optional
2946 self.revertIfOptional(stack) catch {
2947 const loc = self.tokenizer.getTokenLocation(0, token);
2948 warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args);
2949 warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]);
2950 {
2951 var i: usize = 0;
2952 while (i < loc.column) : (i += 1) {
2953 warn(" ");
2954 }
3123 fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) (error{ParseError}) {
3124 const loc = self.tokenizer.getTokenLocation(0, token);
3125 warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args);
3126 warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]);
3127 {
3128 var i: usize = 0;
3129 while (i < loc.column) : (i += 1) {
3130 warn(" ");
29553131 }
2956 {
2957 const caret_count = token.end - token.start;
2958 var i: usize = 0;
2959 while (i < caret_count) : (i += 1) {
2960 warn("~");
2961 }
3132 }
3133 {
3134 const caret_count = token.end - token.start;
3135 var i: usize = 0;
3136 while (i < caret_count) : (i += 1) {
3137 warn("~");
29623138 }
2963 warn("\n");
2964 return error.ParseError;
2965 };
3139 }
3140 warn("\n");
3141 return error.ParseError;
29663142 }
29673143
2968 fn eatToken(self: &Parser, stack: &ArrayList(State), id: @TagType(Token.Id)) !?Token {
3144 fn expectToken(self: &Parser, id: @TagType(Token.Id)) !Token {
29693145 const token = self.getNextToken();
29703146 if (token.id != id) {
2971 try self.parseError(stack, token, "expected {}, found {}", @tagName(id), @tagName(token.id));
2972 return null;
3147 return self.parseError(token, "expected {}, found {}", @tagName(id), @tagName(token.id));
29733148 }
29743149 return token;
29753150 }
29763151
2977 fn revertIfOptional(self: &Parser, stack: &ArrayList(State)) !void {
2978 while (stack.popOrNull()) |state| {
2979 switch (state) {
2980 State.Optional => |revert| {
2981 *self = revert.parser;
2982 *self.tokenizer = revert.tokenizer;
2983 *revert.ptr = null;
2984 return;
2985 },
2986 else => { }
2987 }
3152 fn eatToken(self: &Parser, id: @TagType(Token.Id)) ?Token {
3153 if (self.isPeekToken(id)) {
3154 return self.getNextToken();
29883155 }
2989
2990 return error.NoOptionalStateFound;
3156 return null;
29913157 }
29923158
29933159 fn putBackToken(self: &Parser, token: &const Token) void {
......@@ -3006,6 +3172,12 @@ pub const Parser = struct {
30063172 }
30073173 }
30083174
3175 fn isPeekToken(self: &Parser, id: @TagType(Token.Id)) bool {
3176 const token = self.getNextToken();
3177 defer self.putBackToken(token);
3178 return id == token.id;
3179 }
3180
30093181 const RenderAstFrame = struct {
30103182 node: &ast.Node,
30113183 indent: usize,
......@@ -3040,7 +3212,6 @@ pub const Parser = struct {
30403212
30413213 const RenderState = union(enum) {
30423214 TopLevelDecl: &ast.Node,
3043 FnProtoRParen: &ast.NodeFnProto,
30443215 ParamDecl: &ast.Node,
30453216 Text: []const u8,
30463217 Expression: &ast.Node,
......@@ -3118,6 +3289,9 @@ pub const Parser = struct {
31183289 },
31193290 ast.Node.Id.StructField => {
31203291 const field = @fieldParentPtr(ast.NodeStructField, "base", decl);
3292 if (field.visib_token) |visib_token| {
3293 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
3294 }
31213295 try stream.print("{}: ", self.tokenizer.getTokenSlice(field.name_token));
31223296 try stack.append(RenderState { .Expression = field.type_expr});
31233297 },
......@@ -3179,13 +3353,13 @@ pub const Parser = struct {
31793353 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(comptime_token) });
31803354 }
31813355
3182 if (var_decl.extern_token) |extern_token| {
3356 if (var_decl.extern_export_token) |extern_export_token| {
31833357 if (var_decl.lib_name != null) {
31843358 try stack.append(RenderState { .Text = " " });
31853359 try stack.append(RenderState { .Expression = ??var_decl.lib_name });
31863360 }
31873361 try stack.append(RenderState { .Text = " " });
3188 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_token) });
3362 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_export_token) });
31893363 }
31903364
31913365 if (var_decl.visib_token) |visib_token| {
......@@ -3217,7 +3391,7 @@ pub const Parser = struct {
32173391 RenderState.Expression => |base| switch (base.id) {
32183392 ast.Node.Id.Identifier => {
32193393 const identifier = @fieldParentPtr(ast.NodeIdentifier, "base", base);
3220 try stream.print("{}", self.tokenizer.getTokenSlice(identifier.name_token));
3394 try stream.print("{}", self.tokenizer.getTokenSlice(identifier.token));
32213395 },
32223396 ast.Node.Id.Block => {
32233397 const block = @fieldParentPtr(ast.NodeBlock, "base", base);
......@@ -3285,7 +3459,7 @@ pub const Parser = struct {
32853459 }
32863460
32873461 if (suspend_node.payload) |payload| {
3288 try stack.append(RenderState { .Expression = &payload.base });
3462 try stack.append(RenderState { .Expression = payload });
32893463 try stack.append(RenderState { .Text = " " });
32903464 }
32913465 },
......@@ -3296,7 +3470,7 @@ pub const Parser = struct {
32963470 if (prefix_op_node.op == ast.NodeInfixOp.InfixOp.Catch) {
32973471 if (prefix_op_node.op.Catch) |payload| {
32983472 try stack.append(RenderState { .Text = " " });
3299 try stack.append(RenderState { .Expression = &payload.base });
3473 try stack.append(RenderState { .Expression = payload });
33003474 }
33013475 try stack.append(RenderState { .Text = " catch " });
33023476 } else {
......@@ -3440,50 +3614,70 @@ pub const Parser = struct {
34403614 try stack.append(RenderState { .Expression = suffix_op.lhs });
34413615 },
34423616 ast.NodeSuffixOp.SuffixOp.StructInitializer => |field_inits| {
3443 try stack.append(RenderState { .Text = " }"});
3617 if (field_inits.len == 0) {
3618 try stack.append(RenderState { .Text = "{}" });
3619 try stack.append(RenderState { .Expression = suffix_op.lhs });
3620 continue;
3621 }
3622 try stack.append(RenderState { .Text = "}"});
3623 try stack.append(RenderState.PrintIndent);
3624 try stack.append(RenderState { .Indent = indent });
34443625 var i = field_inits.len;
34453626 while (i != 0) {
34463627 i -= 1;
34473628 const field_init = field_inits.at(i);
3629 try stack.append(RenderState { .Text = ",\n" });
34483630 try stack.append(RenderState { .FieldInitializer = field_init });
3449 try stack.append(RenderState { .Text = " " });
3450 if (i != 0) {
3451 try stack.append(RenderState { .Text = "," });
3452 }
3631 try stack.append(RenderState.PrintIndent);
34533632 }
3454 try stack.append(RenderState { .Text = "{"});
3633 try stack.append(RenderState { .Indent = indent + indent_delta });
3634 try stack.append(RenderState { .Text = " {\n"});
34553635 try stack.append(RenderState { .Expression = suffix_op.lhs });
34563636 },
34573637 ast.NodeSuffixOp.SuffixOp.ArrayInitializer => |exprs| {
3458 try stack.append(RenderState { .Text = " }"});
3638 if (exprs.len == 0) {
3639 try stack.append(RenderState { .Text = "{}" });
3640 try stack.append(RenderState { .Expression = suffix_op.lhs });
3641 continue;
3642 }
3643 try stack.append(RenderState { .Text = "}"});
3644 try stack.append(RenderState.PrintIndent);
3645 try stack.append(RenderState { .Indent = indent });
34593646 var i = exprs.len;
34603647 while (i != 0) {
34613648 i -= 1;
34623649 const expr = exprs.at(i);
3650 try stack.append(RenderState { .Text = ",\n" });
34633651 try stack.append(RenderState { .Expression = expr });
3464 try stack.append(RenderState { .Text = " " });
3465 if (i != 0) {
3466 try stack.append(RenderState { .Text = "," });
3467 }
3652 try stack.append(RenderState.PrintIndent);
34683653 }
3469 try stack.append(RenderState { .Text = "{"});
3654 try stack.append(RenderState { .Indent = indent + indent_delta });
3655 try stack.append(RenderState { .Text = " {\n"});
34703656 try stack.append(RenderState { .Expression = suffix_op.lhs });
34713657 },
34723658 }
34733659 },
34743660 ast.Node.Id.ControlFlowExpression => {
34753661 const flow_expr = @fieldParentPtr(ast.NodeControlFlowExpression, "base", base);
3662
3663 if (flow_expr.rhs) |rhs| {
3664 try stack.append(RenderState { .Expression = rhs });
3665 try stack.append(RenderState { .Text = " " });
3666 }
3667
34763668 switch (flow_expr.kind) {
3477 ast.NodeControlFlowExpression.Kind.Break => |maybe_blk_token| {
3669 ast.NodeControlFlowExpression.Kind.Break => |maybe_label| {
34783670 try stream.print("break");
3479 if (maybe_blk_token) |blk_token| {
3480 try stream.print(" :{}", self.tokenizer.getTokenSlice(blk_token));
3671 if (maybe_label) |label| {
3672 try stream.print(" :");
3673 try stack.append(RenderState { .Expression = label });
34813674 }
34823675 },
3483 ast.NodeControlFlowExpression.Kind.Continue => |maybe_blk_token| {
3676 ast.NodeControlFlowExpression.Kind.Continue => |maybe_label| {
34843677 try stream.print("continue");
3485 if (maybe_blk_token) |blk_token| {
3486 try stream.print(" :{}", self.tokenizer.getTokenSlice(blk_token));
3678 if (maybe_label) |label| {
3679 try stream.print(" :");
3680 try stack.append(RenderState { .Expression = label });
34873681 }
34883682 },
34893683 ast.NodeControlFlowExpression.Kind.Return => {
......@@ -3491,25 +3685,20 @@ pub const Parser = struct {
34913685 },
34923686
34933687 }
3494
3495 if (flow_expr.rhs) |rhs| {
3496 try stream.print(" ");
3497 try stack.append(RenderState { .Expression = rhs });
3498 }
34993688 },
35003689 ast.Node.Id.Payload => {
35013690 const payload = @fieldParentPtr(ast.NodePayload, "base", base);
35023691 try stack.append(RenderState { .Text = "|"});
3503 try stack.append(RenderState { .Expression = &payload.error_symbol.base });
3692 try stack.append(RenderState { .Expression = payload.error_symbol });
35043693 try stack.append(RenderState { .Text = "|"});
35053694 },
35063695 ast.Node.Id.PointerPayload => {
35073696 const payload = @fieldParentPtr(ast.NodePointerPayload, "base", base);
35083697 try stack.append(RenderState { .Text = "|"});
3509 try stack.append(RenderState { .Expression = &payload.value_symbol.base });
3698 try stack.append(RenderState { .Expression = payload.value_symbol });
35103699
3511 if (payload.is_ptr) {
3512 try stack.append(RenderState { .Text = "*"});
3700 if (payload.ptr_token) |ptr_token| {
3701 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(ptr_token) });
35133702 }
35143703
35153704 try stack.append(RenderState { .Text = "|"});
......@@ -3519,14 +3708,14 @@ pub const Parser = struct {
35193708 try stack.append(RenderState { .Text = "|"});
35203709
35213710 if (payload.index_symbol) |index_symbol| {
3522 try stack.append(RenderState { .Expression = &index_symbol.base });
3711 try stack.append(RenderState { .Expression = index_symbol });
35233712 try stack.append(RenderState { .Text = ", "});
35243713 }
35253714
3526 try stack.append(RenderState { .Expression = &payload.value_symbol.base });
3715 try stack.append(RenderState { .Expression = payload.value_symbol });
35273716
3528 if (payload.is_ptr) {
3529 try stack.append(RenderState { .Text = "*"});
3717 if (payload.ptr_token) |ptr_token| {
3718 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(ptr_token) });
35303719 }
35313720
35323721 try stack.append(RenderState { .Text = "|"});
......@@ -3607,6 +3796,14 @@ pub const Parser = struct {
36073796 while (i != 0) {
36083797 i -= 1;
36093798 const node = fields_and_decls[i];
3799 switch (node.id) {
3800 ast.Node.Id.StructField,
3801 ast.Node.Id.UnionTag,
3802 ast.Node.Id.EnumTag => {
3803 try stack.append(RenderState { .Text = "," });
3804 },
3805 else => { }
3806 }
36103807 try stack.append(RenderState { .TopLevelDecl = node});
36113808 try stack.append(RenderState.PrintIndent);
36123809 try stack.append(RenderState {
......@@ -3621,18 +3818,6 @@ pub const Parser = struct {
36213818 break :blk "\n";
36223819 },
36233820 });
3624
3625 if (i != 0) {
3626 const prev_node = fields_and_decls[i - 1];
3627 switch (prev_node.id) {
3628 ast.Node.Id.StructField,
3629 ast.Node.Id.UnionTag,
3630 ast.Node.Id.EnumTag => {
3631 try stack.append(RenderState { .Text = "," });
3632 },
3633 else => { }
3634 }
3635 }
36363821 }
36373822 try stack.append(RenderState { .Indent = indent + indent_delta});
36383823 try stack.append(RenderState { .Text = "{"});
......@@ -3661,7 +3846,8 @@ pub const Parser = struct {
36613846 while (i != 0) {
36623847 i -= 1;
36633848 const node = decls[i];
3664 try stack.append(RenderState { .Expression = &node.base});
3849 try stack.append(RenderState { .Text = "," });
3850 try stack.append(RenderState { .Expression = node });
36653851 try stack.append(RenderState.PrintIndent);
36663852 try stack.append(RenderState {
36673853 .Text = blk: {
......@@ -3675,10 +3861,6 @@ pub const Parser = struct {
36753861 break :blk "\n";
36763862 },
36773863 });
3678
3679 if (i != 0) {
3680 try stack.append(RenderState { .Text = "," });
3681 }
36823864 }
36833865 try stack.append(RenderState { .Indent = indent + indent_delta});
36843866 try stack.append(RenderState { .Text = "{"});
......@@ -3726,8 +3908,10 @@ pub const Parser = struct {
37263908 },
37273909 }
37283910
3729 if (fn_proto.align_expr != null) {
3730 @panic("TODO");
3911 if (fn_proto.align_expr) |align_expr| {
3912 try stack.append(RenderState { .Text = ") " });
3913 try stack.append(RenderState { .Expression = align_expr});
3914 try stack.append(RenderState { .Text = "align(" });
37313915 }
37323916
37333917 try stack.append(RenderState { .Text = ") " });
......@@ -3763,9 +3947,9 @@ pub const Parser = struct {
37633947 try stack.append(RenderState { .Text = " " });
37643948 try stack.append(RenderState { .Expression = lib_name });
37653949 }
3766 if (fn_proto.extern_token) |extern_token| {
3950 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
37673951 try stack.append(RenderState { .Text = " " });
3768 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_token) });
3952 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_export_inline_token) });
37693953 }
37703954
37713955 if (fn_proto.visib_token) |visib_token| {
......@@ -3789,6 +3973,7 @@ pub const Parser = struct {
37893973 while (i != 0) {
37903974 i -= 1;
37913975 const node = cases[i];
3976 try stack.append(RenderState { .Text = ","});
37923977 try stack.append(RenderState { .Expression = &node.base});
37933978 try stack.append(RenderState.PrintIndent);
37943979 try stack.append(RenderState {
......@@ -3803,10 +3988,6 @@ pub const Parser = struct {
38033988 break :blk "\n";
38043989 },
38053990 });
3806
3807 if (i != 0) {
3808 try stack.append(RenderState { .Text = "," });
3809 }
38103991 }
38113992 try stack.append(RenderState { .Indent = indent + indent_delta});
38123993 try stack.append(RenderState { .Text = ") {"});
......@@ -3818,7 +3999,7 @@ pub const Parser = struct {
38183999 try stack.append(RenderState { .Expression = switch_case.expr });
38194000 if (switch_case.payload) |payload| {
38204001 try stack.append(RenderState { .Text = " " });
3821 try stack.append(RenderState { .Expression = &payload.base });
4002 try stack.append(RenderState { .Expression = payload });
38224003 }
38234004 try stack.append(RenderState { .Text = " => "});
38244005
......@@ -3829,7 +4010,8 @@ pub const Parser = struct {
38294010 try stack.append(RenderState { .Expression = items[i] });
38304011
38314012 if (i != 0) {
3832 try stack.append(RenderState { .Text = ", " });
4013 try stack.append(RenderState.PrintIndent);
4014 try stack.append(RenderState { .Text = ",\n" });
38334015 }
38344016 }
38354017 },
......@@ -3859,7 +4041,7 @@ pub const Parser = struct {
38594041
38604042 if (else_node.payload) |payload| {
38614043 try stack.append(RenderState { .Text = " " });
3862 try stack.append(RenderState { .Expression = &payload.base });
4044 try stack.append(RenderState { .Expression = payload });
38634045 }
38644046 },
38654047 ast.Node.Id.While => {
......@@ -3904,7 +4086,7 @@ pub const Parser = struct {
39044086 }
39054087
39064088 if (while_node.payload) |payload| {
3907 try stack.append(RenderState { .Expression = &payload.base });
4089 try stack.append(RenderState { .Expression = payload });
39084090 try stack.append(RenderState { .Text = " " });
39094091 }
39104092
......@@ -3947,7 +4129,7 @@ pub const Parser = struct {
39474129 }
39484130
39494131 if (for_node.payload) |payload| {
3950 try stack.append(RenderState { .Expression = &payload.base });
4132 try stack.append(RenderState { .Expression = payload });
39514133 try stack.append(RenderState { .Text = " " });
39524134 }
39534135
......@@ -3980,7 +4162,7 @@ pub const Parser = struct {
39804162
39814163 if (@"else".payload) |payload| {
39824164 try stack.append(RenderState { .Text = " " });
3983 try stack.append(RenderState { .Expression = &payload.base });
4165 try stack.append(RenderState { .Expression = payload });
39844166 }
39854167
39864168 try stack.append(RenderState { .Text = " " });
......@@ -3994,7 +4176,7 @@ pub const Parser = struct {
39944176 try stack.append(RenderState { .Text = " " });
39954177
39964178 if (if_node.payload) |payload| {
3997 try stack.append(RenderState { .Expression = &payload.base });
4179 try stack.append(RenderState { .Expression = payload });
39984180 try stack.append(RenderState { .Text = " " });
39994181 }
40004182
......@@ -4006,12 +4188,10 @@ pub const Parser = struct {
40064188 const asm_node = @fieldParentPtr(ast.NodeAsm, "base", base);
40074189 try stream.print("{} ", self.tokenizer.getTokenSlice(asm_node.asm_token));
40084190
4009 if (asm_node.is_volatile) {
4010 try stream.write("volatile ");
4191 if (asm_node.volatile_token) |volatile_token| {
4192 try stream.print("{} ", self.tokenizer.getTokenSlice(volatile_token));
40114193 }
40124194
4013 try stream.print("({}", self.tokenizer.getTokenSlice(asm_node.template));
4014
40154195 try stack.append(RenderState { .Indent = indent });
40164196 try stack.append(RenderState { .Text = ")" });
40174197 {
......@@ -4019,7 +4199,7 @@ pub const Parser = struct {
40194199 var i = cloppers.len;
40204200 while (i != 0) {
40214201 i -= 1;
4022 try stack.append(RenderState { .Expression = &cloppers[i].base });
4202 try stack.append(RenderState { .Expression = cloppers[i] });
40234203
40244204 if (i != 0) {
40254205 try stack.append(RenderState { .Text = ", " });
......@@ -4088,6 +4268,8 @@ pub const Parser = struct {
40884268 try stack.append(RenderState.PrintIndent);
40894269 try stack.append(RenderState { .Indent = indent + indent_delta});
40904270 try stack.append(RenderState { .Text = "\n" });
4271 try stack.append(RenderState { .Expression = asm_node.template });
4272 try stack.append(RenderState { .Text = "(" });
40914273 },
40924274 ast.Node.Id.AsmInput => {
40934275 const asm_input = @fieldParentPtr(ast.NodeAsmInput, "base", base);
......@@ -4095,9 +4277,9 @@ pub const Parser = struct {
40954277 try stack.append(RenderState { .Text = ")"});
40964278 try stack.append(RenderState { .Expression = asm_input.expr});
40974279 try stack.append(RenderState { .Text = " ("});
4098 try stack.append(RenderState { .Expression = &asm_input.constraint.base});
4280 try stack.append(RenderState { .Expression = asm_input.constraint });
40994281 try stack.append(RenderState { .Text = "] "});
4100 try stack.append(RenderState { .Expression = &asm_input.symbolic_name.base});
4282 try stack.append(RenderState { .Expression = asm_input.symbolic_name });
41014283 try stack.append(RenderState { .Text = "["});
41024284 },
41034285 ast.Node.Id.AsmOutput => {
......@@ -4114,9 +4296,9 @@ pub const Parser = struct {
41144296 },
41154297 }
41164298 try stack.append(RenderState { .Text = " ("});
4117 try stack.append(RenderState { .Expression = &asm_output.constraint.base});
4299 try stack.append(RenderState { .Expression = asm_output.constraint });
41184300 try stack.append(RenderState { .Text = "] "});
4119 try stack.append(RenderState { .Expression = &asm_output.symbolic_name.base});
4301 try stack.append(RenderState { .Expression = asm_output.symbolic_name });
41204302 try stack.append(RenderState { .Text = "["});
41214303 },
41224304
......@@ -4129,26 +4311,6 @@ pub const Parser = struct {
41294311 ast.Node.Id.TestDecl,
41304312 ast.Node.Id.ParamDecl => unreachable,
41314313 },
4132 RenderState.FnProtoRParen => |fn_proto| {
4133 try stream.print(")");
4134 if (fn_proto.align_expr != null) {
4135 @panic("TODO");
4136 }
4137 try stream.print(" ");
4138 if (fn_proto.body_node) |body_node| {
4139 try stack.append(RenderState { .Expression = body_node});
4140 try stack.append(RenderState { .Text = " "});
4141 }
4142 switch (fn_proto.return_type) {
4143 ast.NodeFnProto.ReturnType.Explicit => |node| {
4144 try stack.append(RenderState { .Expression = node});
4145 },
4146 ast.NodeFnProto.ReturnType.InferErrorSet => |node| {
4147 try stream.print("!");
4148 try stack.append(RenderState { .Expression = node});
4149 },
4150 }
4151 },
41524314 RenderState.Statement => |base| {
41534315 if (base.comment) |comment| {
41544316 for (comment.lines.toSliceConst()) |line_token| {
......@@ -4441,10 +4603,10 @@ test "zig fmt: precedence" {
44414603 \\ (a!b)();
44424604 \\ !a!b;
44434605 \\ !(a!b);
4444 \\ !a{ };
4445 \\ !(a{ });
4446 \\ a + b{ };
4447 \\ (a + b){ };
4606 \\ !a{};
4607 \\ !(a{});
4608 \\ a + b{};
4609 \\ (a + b){};
44484610 \\ a << b + c;
44494611 \\ (a << b) + c;
44504612 \\ a & b << c;
......@@ -4502,10 +4664,20 @@ test "zig fmt: var type" {
45024664 );
45034665}
45044666
4505test "zig fmt: extern function" {
4667test "zig fmt: functions" {
45064668 try testCanonical(
45074669 \\extern fn puts(s: &const u8) c_int;
45084670 \\extern "c" fn puts(s: &const u8) c_int;
4671 \\export fn puts(s: &const u8) c_int;
4672 \\inline fn puts(s: &const u8) c_int;
4673 \\pub extern fn puts(s: &const u8) c_int;
4674 \\pub extern "c" fn puts(s: &const u8) c_int;
4675 \\pub export fn puts(s: &const u8) c_int;
4676 \\pub inline fn puts(s: &const u8) c_int;
4677 \\pub extern fn puts(s: &const u8) align(2 + 2) c_int;
4678 \\pub extern "c" fn puts(s: &const u8) align(2 + 2) c_int;
4679 \\pub export fn puts(s: &const u8) align(2 + 2) c_int;
4680 \\pub inline fn puts(s: &const u8) align(2 + 2) c_int;
45094681 \\
45104682 );
45114683}
......@@ -4565,26 +4737,27 @@ test "zig fmt: struct declaration" {
45654737 \\const S = struct {
45664738 \\ const Self = this;
45674739 \\ f1: u8,
4740 \\ pub f3: u8,
45684741 \\
45694742 \\ fn method(self: &Self) Self {
45704743 \\ return *self;
45714744 \\ }
45724745 \\
4573 \\ f2: u8
4746 \\ f2: u8,
45744747 \\};
45754748 \\
45764749 \\const Ps = packed struct {
45774750 \\ a: u8,
4578 \\ b: u8,
4751 \\ pub b: u8,
45794752 \\
4580 \\ c: u8
4753 \\ c: u8,
45814754 \\};
45824755 \\
45834756 \\const Es = extern struct {
45844757 \\ a: u8,
4585 \\ b: u8,
4758 \\ pub b: u8,
45864759 \\
4587 \\ c: u8
4760 \\ c: u8,
45884761 \\};
45894762 \\
45904763 );
......@@ -4594,25 +4767,25 @@ test "zig fmt: enum declaration" {
45944767 try testCanonical(
45954768 \\const E = enum {
45964769 \\ Ok,
4597 \\ SomethingElse = 0
4770 \\ SomethingElse = 0,
45984771 \\};
45994772 \\
46004773 \\const E2 = enum(u8) {
46014774 \\ Ok,
46024775 \\ SomethingElse = 255,
4603 \\ SomethingThird
4776 \\ SomethingThird,
46044777 \\};
46054778 \\
46064779 \\const Ee = extern enum {
46074780 \\ Ok,
46084781 \\ SomethingElse,
4609 \\ SomethingThird
4782 \\ SomethingThird,
46104783 \\};
46114784 \\
46124785 \\const Ep = packed enum {
46134786 \\ Ok,
46144787 \\ SomethingElse,
4615 \\ SomethingThird
4788 \\ SomethingThird,
46164789 \\};
46174790 \\
46184791 );
......@@ -4624,35 +4797,35 @@ test "zig fmt: union declaration" {
46244797 \\ Int: u8,
46254798 \\ Float: f32,
46264799 \\ None,
4627 \\ Bool: bool
4800 \\ Bool: bool,
46284801 \\};
46294802 \\
46304803 \\const Ue = union(enum) {
46314804 \\ Int: u8,
46324805 \\ Float: f32,
46334806 \\ None,
4634 \\ Bool: bool
4807 \\ Bool: bool,
46354808 \\};
46364809 \\
46374810 \\const E = enum {
46384811 \\ Int,
46394812 \\ Float,
46404813 \\ None,
4641 \\ Bool
4814 \\ Bool,
46424815 \\};
46434816 \\
46444817 \\const Ue2 = union(E) {
46454818 \\ Int: u8,
46464819 \\ Float: f32,
46474820 \\ None,
4648 \\ Bool: bool
4821 \\ Bool: bool,
46494822 \\};
46504823 \\
46514824 \\const Eu = extern union {
46524825 \\ Int: u8,
46534826 \\ Float: f32,
46544827 \\ None,
4655 \\ Bool: bool
4828 \\ Bool: bool,
46564829 \\};
46574830 \\
46584831 );
......@@ -4664,7 +4837,7 @@ test "zig fmt: error set declaration" {
46644837 \\ A,
46654838 \\ B,
46664839 \\
4667 \\ C
4840 \\ C,
46684841 \\};
46694842 \\
46704843 );
......@@ -4673,9 +4846,15 @@ test "zig fmt: error set declaration" {
46734846test "zig fmt: arrays" {
46744847 try testCanonical(
46754848 \\test "test array" {
4676 \\ const a: [2]u8 = [2]u8{ 1, 2 };
4677 \\ const a: [2]u8 = []u8{ 1, 2 };
4678 \\ const a: [0]u8 = []u8{ };
4849 \\ const a: [2]u8 = [2]u8 {
4850 \\ 1,
4851 \\ 2,
4852 \\ };
4853 \\ const a: [2]u8 = []u8 {
4854 \\ 1,
4855 \\ 2,
4856 \\ };
4857 \\ const a: [0]u8 = []u8{};
46794858 \\}
46804859 \\
46814860 );
......@@ -4683,10 +4862,18 @@ test "zig fmt: arrays" {
46834862
46844863test "zig fmt: container initializers" {
46854864 try testCanonical(
4686 \\const a1 = []u8{ };
4687 \\const a2 = []u8{ 1, 2, 3, 4 };
4688 \\const s1 = S{ };
4689 \\const s2 = S{ .a = 1, .b = 2 };
4865 \\const a1 = []u8{};
4866 \\const a2 = []u8 {
4867 \\ 1,
4868 \\ 2,
4869 \\ 3,
4870 \\ 4,
4871 \\};
4872 \\const s1 = S{};
4873 \\const s2 = S {
4874 \\ .a = 1,
4875 \\ .b = 2,
4876 \\};
46904877 \\
46914878 );
46924879}
......@@ -4730,30 +4917,34 @@ test "zig fmt: switch" {
47304917 \\ switch (0) {
47314918 \\ 0 => {},
47324919 \\ 1 => unreachable,
4733 \\ 2, 3 => {},
4920 \\ 2,
4921 \\ 3 => {},
47344922 \\ 4 ... 7 => {},
47354923 \\ 1 + 4 * 3 + 22 => {},
47364924 \\ else => {
47374925 \\ const a = 1;
47384926 \\ const b = a;
4739 \\ }
4927 \\ },
47404928 \\ }
47414929 \\
47424930 \\ const res = switch (0) {
47434931 \\ 0 => 0,
47444932 \\ 1 => 2,
4745 \\ else => 4
4933 \\ 1 => a = 4,
4934 \\ else => 4,
47464935 \\ };
47474936 \\
47484937 \\ const Union = union(enum) {
47494938 \\ Int: i64,
4750 \\ Float: f64
4939 \\ Float: f64,
47514940 \\ };
47524941 \\
4753 \\ const u = Union{ .Int = 0 };
4942 \\ const u = Union {
4943 \\ .Int = 0,
4944 \\ };
47544945 \\ switch (u) {
47554946 \\ Union.Int => |int| {},
4756 \\ Union.Float => |*float| unreachable
4947 \\ Union.Float => |*float| unreachable,
47574948 \\ }
47584949 \\}
47594950 \\
......@@ -4829,7 +5020,11 @@ test "zig fmt: while" {
48295020test "zig fmt: for" {
48305021 try testCanonical(
48315022 \\test "for" {
4832 \\ const a = []u8{ 1, 2, 3 };
5023 \\ const a = []u8 {
5024 \\ 1,
5025 \\ 2,
5026 \\ 3,
5027 \\ };
48335028 \\ for (a) |v| {
48345029 \\ continue;
48355030 \\ }
......@@ -4887,6 +5082,7 @@ test "zig fmt: if" {
48875082 \\ }
48885083 \\
48895084 \\ const is_world_broken = if (10 < 0) true else false;
5085 \\ const some_number = 1 + if (10 < 0) 2 else 3;
48905086 \\
48915087 \\ const a: ?u8 = 10;
48925088 \\ const b: ?u8 = null;
......@@ -5000,6 +5196,7 @@ test "zig fmt: inline asm" {
50005196test "zig fmt: coroutines" {
50015197 try testCanonical(
50025198 \\async fn simpleAsyncFn() void {
5199 \\ const a = async a.b();
50035200 \\ x += 1;
50045201 \\ suspend;
50055202 \\ x += 1;
......@@ -5047,3 +5244,22 @@ test "zig fmt: string identifier" {
50475244 \\
50485245 );
50495246}
5247
5248test "zig fmt: error return" {
5249 try testCanonical(
5250 \\fn err() error {
5251 \\ call();
5252 \\ return error.InvalidArgs;
5253 \\}
5254 \\
5255 );
5256}
5257
5258test "zig fmt: struct literals with fields on each line" {
5259 try testCanonical(
5260 \\var self = BufSet {
5261 \\ .hash_map = BufSetHashMap.init(a),
5262 \\};
5263 \\
5264 );
5265}
test/cases/fn.zig+17
......@@ -94,3 +94,20 @@ test "inline function call" {
9494}
9595
9696fn add(a: i32, b: i32) i32 { return a + b; }
97
98
99test "number literal as an argument" {
100 numberLiteralArg(3);
101 comptime numberLiteralArg(3);
102}
103
104fn numberLiteralArg(a: var) void {
105 assert(a == 3);
106}
107
108test "assign inline fn to const variable" {
109 const a = inlineFn;
110 a();
111}
112
113inline fn inlineFn() void { }
test/compile_errors.zig+10-1
......@@ -1,6 +1,15 @@
11const tests = @import("tests.zig");
22
33pub fn addCases(cases: &tests.CompileErrorContext) void {
4 cases.add("assign inline fn to non-comptime var",
5 \\export fn entry() void {
6 \\ var a = b;
7 \\}
8 \\inline fn b() void { }
9 ,
10 ".tmp_source.zig:2:5: error: functions marked inline must be stored in const or comptime var",
11 ".tmp_source.zig:4:8: note: declared here");
12
413 cases.add("wrong type passed to @panic",
514 \\export fn entry() void {
615 \\ var e = error.Foo;
......@@ -1723,7 +1732,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
17231732 \\}
17241733 \\
17251734 \\export fn entry() usize { return @sizeOf(@typeOf(bar)); }
1726 , ".tmp_source.zig:10:16: error: parameter of type '(integer literal)' requires comptime");
1735 , ".tmp_source.zig:10:16: error: compiler bug: integer and float literals in var args function must be casted");
17271736
17281737 cases.add("assign too big number to u16",
17291738 \\export fn foo() void {