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...@@ -19,5 +19,5 @@ if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then
19 echo "secret_key = $AWS_SECRET_ACCESS_KEY" >> ~/.s3cfg19 echo "secret_key = $AWS_SECRET_ACCESS_KEY" >> ~/.s3cfg
20 s3cmd put -P $TRAVIS_BUILD_DIR/artifacts/* s3://ziglang.org/builds/20 s3cmd put -P $TRAVIS_BUILD_DIR/artifacts/* s3://ziglang.org/builds/
21 touch empty21 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)
23fi23fi
deps/lld/ELF/MarkLive.cpp+9
...@@ -301,6 +301,15 @@ template <class ELFT> void elf::markLive() {...@@ -301,6 +301,15 @@ template <class ELFT> void elf::markLive() {
301 // Follow the graph to mark all live sections.301 // Follow the graph to mark all live sections.
302 doGcSections<ELFT>();302 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
304 // Report garbage-collected sections.313 // Report garbage-collected sections.
305 if (Config->PrintGcSections)314 if (Config->PrintGcSections)
306 for (InputSectionBase *Sec : InputSections)315 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 @@...@@ -1,613 +1,165 @@
1const std = @import("std");1const 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;
13const builtin = @import("builtin");2const 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 {11const arg = @import("arg.zig");
20 None,12const c = @import("c.zig");
21 Build,13const introspect = @import("introspect.zig");
22 Test,14const Args = arg.Args;
23 Version,15const Flag = arg.Flag;
24 Zen,16const Module = @import("module.zig").Module;
25 TranslateC,17const Target = @import("target.zig").Target;
26 Targets,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,
27};45};
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
38pub fn main() !void {47pub 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
41 const args = try os.argsAlloc(allocator);58 const args = try os.argsAlloc(allocator);
42 defer os.argsFree(allocator, args);59 defer os.argsFree(allocator, args);
4360
44 if (args.len >= 2 and mem.eql(u8, args[1], "build")) {61 if (args.len <= 1) {
45 return buildMain(allocator, args[2..]);62 try stderr.write(usage);
46 }63 os.exit(1);
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 }
302 }64 }
30365
304 target.initializeAll();66 const commands = []Command {
30567 Command { .name = "build", .exec = cmdBuild },
306 // TODO68 Command { .name = "build-exe", .exec = cmdBuildExe },
307// ZigTarget alloc_target;69 Command { .name = "build-lib", .exec = cmdBuildLib },
308// ZigTarget *target;70 Command { .name = "build-obj", .exec = cmdBuildObj },
309// if (!target_arch && !target_os && !target_environ) {71 Command { .name = "fmt", .exec = cmdFmt },
310// target = nullptr;72 Command { .name = "run", .exec = cmdRun },
311// } else {73 Command { .name = "targets", .exec = cmdTargets },
312// target = &alloc_target;74 Command { .name = "test", .exec = cmdTest },
313// get_unknown_target(target);75 Command { .name = "translate-c", .exec = cmdTranslateC },
314// if (target_arch) {76 Command { .name = "version", .exec = cmdVersion },
315// if (parse_target_arch(target_arch, &target->arch)) {77 Command { .name = "zen", .exec = cmdZen },
316// fprintf(stderr, "invalid --target-arch argument\n");78
317// return usage(arg0);79 // undocumented commands
318// }80 Command { .name = "help", .exec = cmdHelp },
319// }81 Command { .name = "internal", .exec = cmdInternal },
320// if (target_os) {82 };
321// if (parse_target_os(target_os, &target->os)) {83
322// fprintf(stderr, "invalid --target-os argument\n");84 for (commands) |command| {
323// return usage(arg0);85 if (mem.eql(u8, command.name, args[1])) {
324// }86 try command.exec(allocator, args[2..]);
325// }87 return;
326// if (target_environ) {88 }
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"),
467 }89 }
468}
46990
470fn printUsage(stream: var) !void {91 try stderr.print("unknown command: {}\n\n", args[1]);
471 try stream.write(92 try stderr.write(usage);
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 );
565}93}
56694
567fn buildMain(allocator: &mem.Allocator, argv: []const []const u8) !void {95// cmd:build ///////////////////////////////////////////////////////////////////////////////////////
568 var build_file: [] const u8 = "build.zig";96
569 var cache_dir: ?[] const u8 = null;97const usage_build =
570 var zig_install_prefix: ?[] const u8 = null;98 \\usage: zig build <options>
571 var asked_for_help = false;99 \\
572 var asked_for_init = false;100 \\General Options:
573101 \\ --help Print this help and exit
574 var args = ArrayList([] const u8).init(allocator);102 \\ --init Generate a build.zig template
575 defer args.deinit();103 \\ --build-file [file] Override path to build.zig
576104 \\ --cache-dir [path] Override path to cache directory
577 var zig_exe_path = try os.selfExePath(allocator);105 \\ --verbose Print commands before executing them
578 defer allocator.free(zig_exe_path);106 \\ --prefix [path] Override default install prefix
579107 \\
580 try args.append(""); // Placeholder for zig-cache/build108 \\Project-Specific Options:
581 try args.append(""); // Placeholder for zig_exe_path109 \\
582 try args.append(""); // Placeholder for build_file_dirname110 \\ Project-specific options become available when the build file is found.
583 try args.append(""); // Placeholder for full_cache_dir111 \\
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;143const missing_build_file =
586 while (i < argv.len) : (i += 1) {144 \\No 'build.zig' file found.
587 var arg = argv[i];145 \\
588 if (mem.eql(u8, arg, "--help")) {146 \\Initialize a 'build.zig' template file with `zig build --init`,
589 asked_for_help = true;147 \\or build an executable directly with `zig build-exe $FILENAME.zig`.
590 try args.append(argv[i]);148 \\
591 } else if (mem.eql(u8, arg, "--init")) {149 \\See: `zig build --help` or `zig help` for more options.
592 asked_for_init = true;150 \\
593 try args.append(argv[i]);151 ;
594 } else if (i + 1 < argv.len and mem.eql(u8, arg, "--build-file")) {152
595 build_file = argv[i + 1];153fn cmdBuild(allocator: &Allocator, args: []const []const u8) !void {
596 i += 1;154 var flags = try Args.parse(allocator, args_build_spec, args);
597 } else if (i + 1 < argv.len and mem.eql(u8, arg, "--cache-dir")) {155 defer flags.deinit();
598 cache_dir = argv[i + 1];156
599 i += 1;157 if (flags.present("help")) {
600 } else if (i + 1 < argv.len and mem.eql(u8, arg, "--zig-install-prefix")) {158 try stderr.write(usage_build);
601 try args.append(arg);159 os.exit(0);
602 i += 1;
603 zig_install_prefix = argv[i];
604 try args.append(argv[i]);
605 } else {
606 try args.append(arg);
607 }
608 }160 }
609161
610 const zig_lib_dir = try resolveZigLibDir(allocator, zig_install_prefix);162 const zig_lib_dir = try introspect.resolveZigLibDir(allocator);
611 defer allocator.free(zig_lib_dir);163 defer allocator.free(zig_lib_dir);
612164
613 const zig_std_dir = try os.path.join(allocator, zig_lib_dir, "std");165 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 {...@@ -619,113 +171,502 @@ fn buildMain(allocator: &mem.Allocator, argv: []const []const u8) !void {
619 const build_runner_path = try os.path.join(allocator, special_dir, "build_runner.zig");171 const build_runner_path = try os.path.join(allocator, special_dir, "build_runner.zig");
620 defer allocator.free(build_runner_path);172 defer allocator.free(build_runner_path);
621173
622 // g = codegen_create(build_runner_path, ...)174 const build_file = flags.single("build-file") ?? "build.zig";
623 // codegen_set_out_name(g, "build")
624
625 const build_file_abs = try os.path.resolve(allocator, ".", build_file);175 const build_file_abs = try os.path.resolve(allocator, ".", build_file);
626 defer allocator.free(build_file_abs);176 defer allocator.free(build_file_abs);
627177
628 const build_file_basename = os.path.basename(build_file_abs);178 const build_file_exists = os.File.access(allocator, build_file_abs, os.default_file_mode) catch false;
629 const build_file_dirname = os.path.dirname(build_file_abs);
630179
631 var full_cache_dir: []u8 = undefined;180 if (flags.present("init")) {
632 if (cache_dir == null) {181 if (build_file_exists) {
633 full_cache_dir = try os.path.join(allocator, build_file_dirname, "zig-cache");182 try stderr.print("build.zig already exists\n");
634 } else {183 os.exit(1);
635 full_cache_dir = try os.path.resolve(allocator, ".", ??cache_dir, full_cache_dir);184 }
636 }
637 defer allocator.free(full_cache_dir);
638185
639 const path_to_build_exe = try os.path.join(allocator, full_cache_dir, "build");186 // need a new scope for proper defer scope finalization on exit
640 defer allocator.free(path_to_build_exe);187 {
641 // codegen_set_cache_dir(g, full_cache_dir)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;191 try os.copyFile(allocator, build_template_path, build_file_abs);
644 args.items[1] = zig_exe_path;192 try stderr.print("wrote build.zig template\n");
645 args.items[2] = build_file_dirname;193 }
646 args.items[3] = full_cache_dir;
647194
648 var build_file_exists: bool = undefined;195 os.exit(0);
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;
654 }196 }
655197
656 if (!build_file_exists and asked_for_help) {198 if (!build_file_exists) {
657 // TODO(bnoordhuis) Print help message from std/special/build_runner.zig199 try stderr.write(missing_build_file);
658 return;200 os.exit(1);
659 }201 }
660202
661 if (!build_file_exists and asked_for_init) {203 // TODO: Invoke build.zig entrypoint directly?
662 const build_template_path = try os.path.join(allocator, special_dir, "build_file_template.zig");204 var zig_exe_path = try os.selfExePath(allocator);
663 defer allocator.free(build_template_path);205 defer allocator.free(zig_exe_path);
664
665 var srcfile = try os.File.openRead(allocator, build_template_path);
666 defer srcfile.close();
667206
668 var dstfile = try os.File.openWrite(allocator, build_file_abs);207 var build_args = ArrayList([]const u8).init(allocator);
669 defer dstfile.close();208 defer build_args.deinit();
670209
671 while (true) {210 const build_file_basename = os.path.basename(build_file_abs);
672 var buffer: [4096]u8 = undefined;211 const build_file_dirname = os.path.dirname(build_file_abs);
673 const n = try srcfile.read(buffer[0..]);
674 if (n == 0) break;
675 try dstfile.write(buffer[0..n]);
676 }
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");
679 }218 }
219 defer allocator.free(full_cache_dir);
680220
681 if (!build_file_exists) {221 const path_to_build_exe = try os.path.join(allocator, full_cache_dir, "build");
682 warn(222 defer allocator.free(path_to_build_exe);
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 }
691223
692 // codegen_build(g)224 try build_args.append(path_to_build_exe);
693 // codegen_link(g, path_to_build_exe)225 try build_args.append(zig_exe_path);
694 // codegen_destroy(g)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);
697 defer proc.deinit();230 defer proc.deinit();
698231
699 var term = try proc.spawnAndWait();232 var term = try proc.spawnAndWait();
700 switch (term) {233 switch (term) {
701 os.ChildProcess.Term.Exited => |status| {234 os.ChildProcess.Term.Exited => |status| {
702 if (status != 0) {235 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);
704 os.exit(1);237 os.exit(1);
705 }238 }
706 },239 },
707 os.ChildProcess.Term.Signal => |signal| {240 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);
709 os.exit(1);242 os.exit(1);
710 },243 },
711 os.ChildProcess.Term.Stopped => |signal| {244 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);
713 os.exit(1);246 os.exit(1);
714 },247 },
715 os.ChildProcess.Term.Unknown => |status| {248 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");
717 os.exit(1);456 os.exit(1);
718 },457 },
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;
719 }575 }
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);
720}617}
721618
722fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {619// cmd:build-lib ///////////////////////////////////////////////////////////////////////////////////
723 for (file_paths) |file_path| {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| {
724 var file = try os.File.openRead(allocator, file_path);665 var file = try os.File.openRead(allocator, file_path);
725 defer file.close();666 defer file.close();
726667
727 const source_code = io.readFileAlloc(allocator, file_path) catch |err| {668 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);
729 continue;670 continue;
730 };671 };
731 defer allocator.free(source_code);672 defer allocator.free(source_code);
...@@ -734,72 +675,312 @@ fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {...@@ -734,72 +675,312 @@ fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {
734 var parser = std.zig.Parser.init(&tokenizer, allocator, file_path);675 var parser = std.zig.Parser.init(&tokenizer, allocator, file_path);
735 defer parser.deinit();676 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 };
738 defer tree.deinit();682 defer tree.deinit();
739683
740 const baf = try io.BufferedAtomicFile.create(allocator, file_path);684 var original_file_backup = try Buffer.init(allocator, file_path);
741 defer baf.destroy();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);690 try stderr.print("{}\n", file_path);
744 try baf.finish();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 }
745 }702 }
746}703}
747704
748/// Caller must free result705// cmd:targets /////////////////////////////////////////////////////////////////////////////////////
749fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const u8) ![]u8 {706
750 if (zig_install_prefix_arg) |zig_install_prefix| {707fn cmdTargets(allocator: &Allocator, args: []const []const u8) !void {
751 return testZigInstallPrefix(allocator, zig_install_prefix) catch |err| {708 try stdout.write("Architectures:\n");
752 warn("No Zig installation found at prefix {}: {}\n", zig_install_prefix_arg, @errorName(err));709 {
753 return error.ZigInstallationNotFound;710 comptime var i: usize = 0;
754 };711 inline while (i < @memberCount(builtin.Arch)) : (i += 1) {
755 } else {712 comptime const arch_tag = @memberName(builtin.Arch, i);
756 return findZigLibDir(allocator) catch |err| {713 // NOTE: Cannot use empty string, see #918.
757 warn("Unable to find zig lib directory: {}.\nReinstall Zig or use --zig-install-prefix.\n",714 comptime const native_str =
758 @errorName(err));715 if (comptime mem.eql(u8, arch_tag, @tagName(builtin.arch))) " (native)\n" else "\n";
759 return error.ZigLibDirNotFound;716
760 };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 }
761 }747 }
762}748}
763749
764/// Caller must free result750// cmd:version /////////////////////////////////////////////////////////////////////////////////////
765fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) ![]u8 {751
766 const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig");752fn cmdVersion(allocator: &Allocator, args: []const []const u8) !void {
767 errdefer allocator.free(test_zig_dir);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");756// cmd:test ////////////////////////////////////////////////////////////////////////////////////////
770 defer allocator.free(test_index_file);
771757
772 var file = try os.File.openRead(allocator, test_index_file);758const usage_test =
773 file.close();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));
776}790}
777791
778/// Caller must free result792// cmd:run /////////////////////////////////////////////////////////////////////////////////////////
779fn findZigLibDir(allocator: &mem.Allocator) ![]u8 {793
780 const self_exe_path = try os.selfExeDirPath(allocator);794// Run should be simple and not expose the full set of arguments provided by build-exe. If specific
781 defer allocator.free(self_exe_path);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..];
788 break;818 break;
789 }819 }
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| {824 if (flags.present("help")) {
792 cur_path = test_dir;825 try stderr.write(usage_run);
793 continue;826 os.exit(0);
794 };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;
795 }893 }
796894
797 // TODO look in hard coded installation path from configuration895 // ast_render(g, output_stream, g->root_import->root, 4);
798 //if (ZIG_INSTALL_PREFIX != nullptr) {896 try output_stream.write("pub const example = 10;\n");
799 // if (test_zig_install_prefix(buf_create_from_str(ZIG_INSTALL_PREFIX), out_path)) {897
800 // return 0;898 if (flags.present("enable-timing-info")) {
801 // }899 // codegen_print_timing_info(g, stdout);
802 //}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 );
805}986}
src-self-hosted/module.zig+23
...@@ -109,6 +109,29 @@ pub const Module = struct {...@@ -109,6 +109,29 @@ pub const Module = struct {
109 LlvmIr,109 LlvmIr,
110 };110 };
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
112 pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target,135 pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target,
113 kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) !&Module136 kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) !&Module
114 {137 {
src/codegen.cpp+1-1
...@@ -467,7 +467,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {...@@ -467,7 +467,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
467 fn_table_entry->llvm_value, buf_ptr(&fn_export->name));467 fn_table_entry->llvm_value, buf_ptr(&fn_export->name));
468 }468 }
469 }469 }
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
472 switch (fn_table_entry->fn_inline) {472 switch (fn_table_entry->fn_inline) {
473 case FnInlineAlways:473 case FnInlineAlways:
src/ir.cpp+21-2
...@@ -11395,7 +11395,19 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc...@@ -11395,7 +11395,19 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
11395 }11395 }
11396 break;11396 break;
11397 case VarClassRequiredAny:11397 case VarClassRequiredAny:
11398 // OK11398 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 }
11399 break;11411 break;
11400 }11412 }
11401 }11413 }
...@@ -11804,7 +11816,8 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod...@@ -11804,7 +11816,8 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
11804 }11816 }
11805 }11817 }
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
11809 ConstExprValue *arg_val;11822 ConstExprValue *arg_val;
1181011823
...@@ -11829,6 +11842,12 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod...@@ -11829,6 +11842,12 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
11829 var->shadowable = !comptime_arg;11842 var->shadowable = !comptime_arg;
1183011843
11831 *next_proto_i += 1;11844 *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;
11832 }11851 }
1183311852
11834 if (!comptime_arg) {11853 if (!comptime_arg) {
src/main.cpp+8-25
...@@ -54,7 +54,6 @@ static int usage(const char *arg0) {...@@ -54,7 +54,6 @@ static int usage(const char *arg0) {
54 " --verbose-ir turn on compiler debug output for Zig IR\n"54 " --verbose-ir turn on compiler debug output for Zig IR\n"
55 " --verbose-llvm-ir turn on compiler debug output for LLVM IR\n"55 " --verbose-llvm-ir turn on compiler debug output for LLVM IR\n"
56 " --verbose-cimport turn on compiler debug output for C imports\n"56 " --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"
58 " -dirafter [dir] same as -isystem but do it last\n"57 " -dirafter [dir] same as -isystem but do it last\n"
59 " -isystem [dir] add additional search path for other .h files\n"58 " -isystem [dir] add additional search path for other .h files\n"
60 " -mllvm [arg] additional arguments to forward to LLVM's option processing\n"59 " -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) {...@@ -177,6 +176,7 @@ static int find_zig_lib_dir(Buf *out_path) {
177 int err;176 int err;
178177
179 Buf self_exe_path = BUF_INIT;178 Buf self_exe_path = BUF_INIT;
179 buf_resize(&self_exe_path, 0);
180 if (!(err = os_self_exe_path(&self_exe_path))) {180 if (!(err = os_self_exe_path(&self_exe_path))) {
181 Buf *cur_path = &self_exe_path;181 Buf *cur_path = &self_exe_path;
182182
...@@ -199,23 +199,14 @@ static int find_zig_lib_dir(Buf *out_path) {...@@ -199,23 +199,14 @@ static int find_zig_lib_dir(Buf *out_path) {
199 return ErrorFileNotFound;199 return ErrorFileNotFound;
200}200}
201201
202static Buf *resolve_zig_lib_dir(const char *zig_install_prefix_arg) {202static Buf *resolve_zig_lib_dir(void) {
203 int err;203 int err;
204 Buf *result = buf_alloc();204 Buf *result = buf_alloc();
205 if (zig_install_prefix_arg == nullptr) {205 if ((err = find_zig_lib_dir(result))) {
206 if ((err = find_zig_lib_dir(result))) {206 fprintf(stderr, "Unable to find zig lib directory\n");
207 fprintf(stderr, "Unable to find zig lib directory. Reinstall Zig or use --zig-install-prefix.\n");207 exit(EXIT_FAILURE);
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;
215 }208 }
216209 return result;
217 fprintf(stderr, "No Zig installation found at prefix: %s\n", zig_install_prefix_arg);
218 exit(EXIT_FAILURE);
219}210}
220211
221enum Cmd {212enum Cmd {
...@@ -299,7 +290,6 @@ int main(int argc, char **argv) {...@@ -299,7 +290,6 @@ int main(int argc, char **argv) {
299 const char *libc_include_dir = nullptr;290 const char *libc_include_dir = nullptr;
300 const char *msvc_lib_dir = nullptr;291 const char *msvc_lib_dir = nullptr;
301 const char *kernel32_lib_dir = nullptr;292 const char *kernel32_lib_dir = nullptr;
302 const char *zig_install_prefix = nullptr;
303 const char *dynamic_linker = nullptr;293 const char *dynamic_linker = nullptr;
304 ZigList<const char *> clang_argv = {0};294 ZigList<const char *> clang_argv = {0};
305 ZigList<const char *> llvm_argv = {0};295 ZigList<const char *> llvm_argv = {0};
...@@ -359,17 +349,12 @@ int main(int argc, char **argv) {...@@ -359,17 +349,12 @@ int main(int argc, char **argv) {
359 } else if (i + 1 < argc && strcmp(argv[i], "--cache-dir") == 0) {349 } else if (i + 1 < argc && strcmp(argv[i], "--cache-dir") == 0) {
360 cache_dir = argv[i + 1];350 cache_dir = argv[i + 1];
361 i += 1;351 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);
367 } else {352 } else {
368 args.append(argv[i]);353 args.append(argv[i]);
369 }354 }
370 }355 }
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
374 Buf *zig_std_dir = buf_alloc();359 Buf *zig_std_dir = buf_alloc();
375 os_path_join(zig_lib_dir_buf, buf_create_from_str("std"), zig_std_dir);360 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) {...@@ -590,8 +575,6 @@ int main(int argc, char **argv) {
590 msvc_lib_dir = argv[i];575 msvc_lib_dir = argv[i];
591 } else if (strcmp(arg, "--kernel32-lib-dir") == 0) {576 } else if (strcmp(arg, "--kernel32-lib-dir") == 0) {
592 kernel32_lib_dir = argv[i];577 kernel32_lib_dir = argv[i];
593 } else if (strcmp(arg, "--zig-install-prefix") == 0) {
594 zig_install_prefix = argv[i];
595 } else if (strcmp(arg, "--dynamic-linker") == 0) {578 } else if (strcmp(arg, "--dynamic-linker") == 0) {
596 dynamic_linker = argv[i];579 dynamic_linker = argv[i];
597 } else if (strcmp(arg, "-isystem") == 0) {580 } else if (strcmp(arg, "-isystem") == 0) {
...@@ -803,7 +786,7 @@ int main(int argc, char **argv) {...@@ -803,7 +786,7 @@ int main(int argc, char **argv) {
803 full_cache_dir);786 full_cache_dir);
804 }787 }
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
808 CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, zig_lib_dir_buf);791 CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, zig_lib_dir_buf);
809 codegen_set_out_name(g, buf_out_name);792 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;...@@ -28,6 +28,7 @@ pub extern "c" fn unlink(path: &const u8) c_int;
28pub extern "c" fn getcwd(buf: &u8, size: usize) ?&u8;28pub extern "c" fn getcwd(buf: &u8, size: usize) ?&u8;
29pub extern "c" fn waitpid(pid: c_int, stat_loc: &c_int, options: c_int) c_int;29pub extern "c" fn waitpid(pid: c_int, stat_loc: &c_int, options: c_int) c_int;
30pub extern "c" fn fork() c_int;30pub extern "c" fn fork() c_int;
31pub extern "c" fn access(path: &const u8, mode: c_uint) c_int;
31pub extern "c" fn pipe(fds: &c_int) c_int;32pub extern "c" fn pipe(fds: &c_int) c_int;
32pub extern "c" fn mkdir(path: &const u8, mode: c_uint) c_int;33pub extern "c" fn mkdir(path: &const u8, mode: c_uint) c_int;
33pub extern "c" fn symlink(existing: &const u8, new: &const u8) c_int;34pub 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...@@ -41,6 +41,11 @@ pub const SA_64REGSET = 0x0200; /// signal handler with SA_SIGINFO args with 64
41pub const O_LARGEFILE = 0x0000;41pub const O_LARGEFILE = 0x0000;
42pub const O_PATH = 0x0000;42pub 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
44pub const O_RDONLY = 0x0000; /// open for reading only49pub const O_RDONLY = 0x0000; /// open for reading only
45pub const O_WRONLY = 0x0001; /// open for writing only50pub const O_WRONLY = 0x0001; /// open for writing only
46pub const O_RDWR = 0x0002; /// open for reading and writing51pub const O_RDWR = 0x0002; /// open for reading and writing
...@@ -209,6 +214,10 @@ pub fn fork() usize {...@@ -209,6 +214,10 @@ pub fn fork() usize {
209 return errnoWrap(c.fork());214 return errnoWrap(c.fork());
210}215}
211216
217pub fn access(path: &const u8, mode: u32) usize {
218 return errnoWrap(c.access(path, mode));
219}
220
212pub fn pipe(fds: &[2]i32) usize {221pub fn pipe(fds: &[2]i32) usize {
213 comptime assert(i32.bit_count == c_int.bit_count);222 comptime assert(i32.bit_count == c_int.bit_count);
214 return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));223 return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));
std/os/file.zig+44-1
...@@ -85,6 +85,47 @@ pub const File = struct {...@@ -85,6 +85,47 @@ pub const File = struct {
85 };85 };
86 }86 }
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
89 /// Upon success, the stream is in an uninitialized state. To continue using it,130 /// Upon success, the stream is in an uninitialized state. To continue using it,
90 /// you must use the open() function.131 /// you must use the open() function.
...@@ -245,7 +286,9 @@ pub const File = struct {...@@ -245,7 +286,9 @@ pub const File = struct {
245 };286 };
246 }287 }
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);
249 } else if (is_windows) {292 } else if (is_windows) {
250 return {};293 return {};
251 } else {294 } else {
std/os/linux/index.zig+9
...@@ -38,6 +38,11 @@ pub const MAP_STACK = 0x20000;...@@ -38,6 +38,11 @@ pub const MAP_STACK = 0x20000;
38pub const MAP_HUGETLB = 0x40000;38pub const MAP_HUGETLB = 0x40000;
39pub const MAP_FILE = 0;39pub 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
41pub const WNOHANG = 1;46pub const WNOHANG = 1;
42pub const WUNTRACED = 2;47pub const WUNTRACED = 2;
43pub const WSTOPPED = 2;48pub const WSTOPPED = 2;
...@@ -705,6 +710,10 @@ pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) usize {...@@ -705,6 +710,10 @@ pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) usize {
705 return syscall4(SYS_pread, usize(fd), @ptrToInt(buf), count, offset);710 return syscall4(SYS_pread, usize(fd), @ptrToInt(buf), count, offset);
706}711}
707712
713pub fn access(path: &const u8, mode: u32) usize {
714 return syscall2(SYS_access, @ptrToInt(path), mode);
715}
716
708pub fn pipe(fd: &[2]i32) usize {717pub fn pipe(fd: &[2]i32) usize {
709 return pipe2(fd, 0);718 return pipe2(fd, 0);
710}719}
std/os/test.zig+17
...@@ -23,3 +23,20 @@ test "makePath, put some files in it, deleteTree" {...@@ -23,3 +23,20 @@ test "makePath, put some files in it, deleteTree" {
23 assert(err == error.PathNotFound);23 assert(err == error.PathNotFound);
24 }24 }
25}25}
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...@@ -78,6 +78,8 @@ pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem
78pub extern "kernel32" stdcallcc fn MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR,78pub extern "kernel32" stdcallcc fn MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR,
79 dwFlags: DWORD) BOOL;79 dwFlags: DWORD) BOOL;
8080
81pub extern "kernel32" stdcallcc fn PathFileExists(pszPath: ?LPCTSTR) BOOL;
82
81pub extern "kernel32" stdcallcc fn ReadFile(in_hFile: HANDLE, out_lpBuffer: &c_void,83pub extern "kernel32" stdcallcc fn ReadFile(in_hFile: HANDLE, out_lpBuffer: &c_void,
82 in_nNumberOfBytesToRead: DWORD, out_lpNumberOfBytesRead: &DWORD,84 in_nNumberOfBytesToRead: DWORD, out_lpNumberOfBytesRead: &DWORD,
83 in_out_lpOverlapped: ?&OVERLAPPED) BOOL;85 in_out_lpOverlapped: ?&OVERLAPPED) BOOL;
std/zig/ast.zig+215-240
...@@ -9,38 +9,34 @@ pub const Node = struct {...@@ -9,38 +9,34 @@ pub const Node = struct {
9 comment: ?&NodeLineComment,9 comment: ?&NodeLineComment,
1010
11 pub const Id = enum {11 pub const Id = enum {
12 // Top level
12 Root,13 Root,
13 VarDecl,
14 Use,14 Use,
15 ErrorSetDecl,15 TestDecl,
16 ContainerDecl,16
17 StructField,17 // Statements
18 UnionTag,18 VarDecl,
19 EnumTag,
20 Identifier,
21 AsyncAttribute,
22 FnProto,
23 ParamDecl,
24 Block,
25 Defer,19 Defer,
26 Comptime,20
27 Payload,21 // Operators
28 PointerPayload,22 InfixOp,
29 PointerIndexPayload,23 PrefixOp,
30 Else,24 SuffixOp,
25
26 // Control flow
31 Switch,27 Switch,
32 SwitchCase,
33 SwitchElse,
34 While,28 While,
35 For,29 For,
36 If,30 If,
37 InfixOp,
38 PrefixOp,
39 SuffixOp,
40 GroupedExpression,
41 ControlFlowExpression,31 ControlFlowExpression,
42 Suspend,32 Suspend,
43 FieldInitializer,33
34 // Type expressions
35 VarType,
36 ErrorType,
37 FnProto,
38
39 // Primary expressions
44 IntegerLiteral,40 IntegerLiteral,
45 FloatLiteral,41 FloatLiteral,
46 StringLiteral,42 StringLiteral,
...@@ -50,180 +46,143 @@ pub const Node = struct {...@@ -50,180 +46,143 @@ pub const Node = struct {
50 NullLiteral,46 NullLiteral,
51 UndefinedLiteral,47 UndefinedLiteral,
52 ThisLiteral,48 ThisLiteral,
53 Asm,
54 AsmInput,
55 AsmOutput,
56 Unreachable,49 Unreachable,
57 ErrorType,50 Identifier,
58 VarType,51 GroupedExpression,
59 BuiltinCall,52 BuiltinCall,
53 ErrorSetDecl,
54 ContainerDecl,
55 Asm,
56 Comptime,
57 Block,
58
59 // Misc
60 LineComment,60 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 },
62 };141 };
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
64 pub fn iterate(base: &Node, index: usize) ?&Node {161 pub fn iterate(base: &Node, index: usize) ?&Node {
65 return switch (base.id) {162 inline for (idTypeTable) |id_type_pair| {
66 Id.Root => @fieldParentPtr(NodeRoot, "base", base).iterate(index),163 if (base.id == id_type_pair.id)
67 Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).iterate(index),164 return @fieldParentPtr(id_type_pair.Type, "base", base).iterate(index);
68 Id.Use => @fieldParentPtr(NodeUse, "base", base).iterate(index),165 }
69 Id.ErrorSetDecl => @fieldParentPtr(NodeErrorSetDecl, "base", base).iterate(index),166
70 Id.ContainerDecl => @fieldParentPtr(NodeContainerDecl, "base", base).iterate(index),167 unreachable;
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 };
117 }168 }
118169
119 pub fn firstToken(base: &Node) Token {170 pub fn firstToken(base: &Node) Token {
120 return switch (base.id) {171 inline for (idTypeTable) |id_type_pair| {
121 Id.Root => @fieldParentPtr(NodeRoot, "base", base).firstToken(),172 if (base.id == id_type_pair.id)
122 Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).firstToken(),173 return @fieldParentPtr(id_type_pair.Type, "base", base).firstToken();
123 Id.Use => @fieldParentPtr(NodeUse, "base", base).firstToken(),174 }
124 Id.ErrorSetDecl => @fieldParentPtr(NodeErrorSetDecl, "base", base).firstToken(),175
125 Id.ContainerDecl => @fieldParentPtr(NodeContainerDecl, "base", base).firstToken(),176 unreachable;
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 };
172 }177 }
173178
174 pub fn lastToken(base: &Node) Token {179 pub fn lastToken(base: &Node) Token {
175 return switch (base.id) {180 inline for (idTypeTable) |id_type_pair| {
176 Id.Root => @fieldParentPtr(NodeRoot, "base", base).lastToken(),181 if (base.id == id_type_pair.id)
177 Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).lastToken(),182 return @fieldParentPtr(id_type_pair.Type, "base", base).lastToken();
178 Id.Use => @fieldParentPtr(NodeUse, "base", base).lastToken(),183 }
179 Id.ErrorSetDecl => @fieldParentPtr(NodeErrorSetDecl, "base", base).lastToken(),184
180 Id.ContainerDecl => @fieldParentPtr(NodeContainerDecl, "base", base).lastToken(),185 unreachable;
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 };
227 }186 }
228};187};
229188
...@@ -255,7 +214,7 @@ pub const NodeVarDecl = struct {...@@ -255,7 +214,7 @@ pub const NodeVarDecl = struct {
255 eq_token: Token,214 eq_token: Token,
256 mut_token: Token,215 mut_token: Token,
257 comptime_token: ?Token,216 comptime_token: ?Token,
258 extern_token: ?Token,217 extern_export_token: ?Token,
259 lib_name: ?&Node,218 lib_name: ?&Node,
260 type_node: ?&Node,219 type_node: ?&Node,
261 align_node: ?&Node,220 align_node: ?&Node,
...@@ -286,7 +245,7 @@ pub const NodeVarDecl = struct {...@@ -286,7 +245,7 @@ pub const NodeVarDecl = struct {
286 pub fn firstToken(self: &NodeVarDecl) Token {245 pub fn firstToken(self: &NodeVarDecl) Token {
287 if (self.visib_token) |visib_token| return visib_token;246 if (self.visib_token) |visib_token| return visib_token;
288 if (self.comptime_token) |comptime_token| return comptime_token;247 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;
290 assert(self.lib_name == null);249 assert(self.lib_name == null);
291 return self.mut_token;250 return self.mut_token;
292 }251 }
...@@ -324,13 +283,13 @@ pub const NodeUse = struct {...@@ -324,13 +283,13 @@ pub const NodeUse = struct {
324pub const NodeErrorSetDecl = struct {283pub const NodeErrorSetDecl = struct {
325 base: Node,284 base: Node,
326 error_token: Token,285 error_token: Token,
327 decls: ArrayList(&NodeIdentifier),286 decls: ArrayList(&Node),
328 rbrace_token: Token,287 rbrace_token: Token,
329288
330 pub fn iterate(self: &NodeErrorSetDecl, index: usize) ?&Node {289 pub fn iterate(self: &NodeErrorSetDecl, index: usize) ?&Node {
331 var i = index;290 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);
334 i -= self.decls.len;293 i -= self.decls.len;
335294
336 return null;295 return null;
...@@ -401,6 +360,7 @@ pub const NodeContainerDecl = struct {...@@ -401,6 +360,7 @@ pub const NodeContainerDecl = struct {
401360
402pub const NodeStructField = struct {361pub const NodeStructField = struct {
403 base: Node,362 base: Node,
363 visib_token: ?Token,
404 name_token: Token,364 name_token: Token,
405 type_expr: &Node,365 type_expr: &Node,
406366
...@@ -414,6 +374,7 @@ pub const NodeStructField = struct {...@@ -414,6 +374,7 @@ pub const NodeStructField = struct {
414 }374 }
415375
416 pub fn firstToken(self: &NodeStructField) Token {376 pub fn firstToken(self: &NodeStructField) Token {
377 if (self.visib_token) |visib_token| return visib_token;
417 return self.name_token;378 return self.name_token;
418 }379 }
419380
...@@ -482,18 +443,18 @@ pub const NodeEnumTag = struct {...@@ -482,18 +443,18 @@ pub const NodeEnumTag = struct {
482443
483pub const NodeIdentifier = struct {444pub const NodeIdentifier = struct {
484 base: Node,445 base: Node,
485 name_token: Token,446 token: Token,
486447
487 pub fn iterate(self: &NodeIdentifier, index: usize) ?&Node {448 pub fn iterate(self: &NodeIdentifier, index: usize) ?&Node {
488 return null;449 return null;
489 }450 }
490451
491 pub fn firstToken(self: &NodeIdentifier) Token {452 pub fn firstToken(self: &NodeIdentifier) Token {
492 return self.name_token;453 return self.token;
493 }454 }
494455
495 pub fn lastToken(self: &NodeIdentifier) Token {456 pub fn lastToken(self: &NodeIdentifier) Token {
496 return self.name_token;457 return self.token;
497 }458 }
498};459};
499460
...@@ -535,8 +496,7 @@ pub const NodeFnProto = struct {...@@ -535,8 +496,7 @@ pub const NodeFnProto = struct {
535 params: ArrayList(&Node),496 params: ArrayList(&Node),
536 return_type: ReturnType,497 return_type: ReturnType,
537 var_args_token: ?Token,498 var_args_token: ?Token,
538 extern_token: ?Token,499 extern_export_inline_token: ?Token,
539 inline_token: ?Token,
540 cc_token: ?Token,500 cc_token: ?Token,
541 async_attr: ?&NodeAsyncAttribute,501 async_attr: ?&NodeAsyncAttribute,
542 body_node: ?&Node,502 body_node: ?&Node,
...@@ -586,9 +546,8 @@ pub const NodeFnProto = struct {...@@ -586,9 +546,8 @@ pub const NodeFnProto = struct {
586546
587 pub fn firstToken(self: &NodeFnProto) Token {547 pub fn firstToken(self: &NodeFnProto) Token {
588 if (self.visib_token) |visib_token| return visib_token;548 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;
590 assert(self.lib_name == null);550 assert(self.lib_name == null);
591 if (self.inline_token) |inline_token| return inline_token;
592 if (self.cc_token) |cc_token| return cc_token;551 if (self.cc_token) |cc_token| return cc_token;
593 return self.fn_token;552 return self.fn_token;
594 }553 }
...@@ -717,13 +676,13 @@ pub const NodeComptime = struct {...@@ -717,13 +676,13 @@ pub const NodeComptime = struct {
717pub const NodePayload = struct {676pub const NodePayload = struct {
718 base: Node,677 base: Node,
719 lpipe: Token,678 lpipe: Token,
720 error_symbol: &NodeIdentifier,679 error_symbol: &Node,
721 rpipe: Token,680 rpipe: Token,
722681
723 pub fn iterate(self: &NodePayload, index: usize) ?&Node {682 pub fn iterate(self: &NodePayload, index: usize) ?&Node {
724 var i = index;683 var i = index;
725684
726 if (i < 1) return &self.error_symbol.base;685 if (i < 1) return self.error_symbol;
727 i -= 1;686 i -= 1;
728687
729 return null;688 return null;
...@@ -741,14 +700,14 @@ pub const NodePayload = struct {...@@ -741,14 +700,14 @@ pub const NodePayload = struct {
741pub const NodePointerPayload = struct {700pub const NodePointerPayload = struct {
742 base: Node,701 base: Node,
743 lpipe: Token,702 lpipe: Token,
744 is_ptr: bool,703 ptr_token: ?Token,
745 value_symbol: &NodeIdentifier,704 value_symbol: &Node,
746 rpipe: Token,705 rpipe: Token,
747706
748 pub fn iterate(self: &NodePointerPayload, index: usize) ?&Node {707 pub fn iterate(self: &NodePointerPayload, index: usize) ?&Node {
749 var i = index;708 var i = index;
750709
751 if (i < 1) return &self.value_symbol.base;710 if (i < 1) return self.value_symbol;
752 i -= 1;711 i -= 1;
753712
754 return null;713 return null;
...@@ -766,19 +725,19 @@ pub const NodePointerPayload = struct {...@@ -766,19 +725,19 @@ pub const NodePointerPayload = struct {
766pub const NodePointerIndexPayload = struct {725pub const NodePointerIndexPayload = struct {
767 base: Node,726 base: Node,
768 lpipe: Token,727 lpipe: Token,
769 is_ptr: bool,728 ptr_token: ?Token,
770 value_symbol: &NodeIdentifier,729 value_symbol: &Node,
771 index_symbol: ?&NodeIdentifier,730 index_symbol: ?&Node,
772 rpipe: Token,731 rpipe: Token,
773732
774 pub fn iterate(self: &NodePointerIndexPayload, index: usize) ?&Node {733 pub fn iterate(self: &NodePointerIndexPayload, index: usize) ?&Node {
775 var i = index;734 var i = index;
776735
777 if (i < 1) return &self.value_symbol.base;736 if (i < 1) return self.value_symbol;
778 i -= 1;737 i -= 1;
779738
780 if (self.index_symbol) |index_symbol| {739 if (self.index_symbol) |index_symbol| {
781 if (i < 1) return &index_symbol.base;740 if (i < 1) return index_symbol;
782 i -= 1;741 i -= 1;
783 }742 }
784743
...@@ -797,14 +756,14 @@ pub const NodePointerIndexPayload = struct {...@@ -797,14 +756,14 @@ pub const NodePointerIndexPayload = struct {
797pub const NodeElse = struct {756pub const NodeElse = struct {
798 base: Node,757 base: Node,
799 else_token: Token,758 else_token: Token,
800 payload: ?&NodePayload,759 payload: ?&Node,
801 body: &Node,760 body: &Node,
802761
803 pub fn iterate(self: &NodeElse, index: usize) ?&Node {762 pub fn iterate(self: &NodeElse, index: usize) ?&Node {
804 var i = index;763 var i = index;
805764
806 if (self.payload) |payload| {765 if (self.payload) |payload| {
807 if (i < 1) return &payload.base;766 if (i < 1) return payload;
808 i -= 1;767 i -= 1;
809 }768 }
810769
...@@ -854,7 +813,7 @@ pub const NodeSwitch = struct {...@@ -854,7 +813,7 @@ pub const NodeSwitch = struct {
854pub const NodeSwitchCase = struct {813pub const NodeSwitchCase = struct {
855 base: Node,814 base: Node,
856 items: ArrayList(&Node),815 items: ArrayList(&Node),
857 payload: ?&NodePointerPayload,816 payload: ?&Node,
858 expr: &Node,817 expr: &Node,
859818
860 pub fn iterate(self: &NodeSwitchCase, index: usize) ?&Node {819 pub fn iterate(self: &NodeSwitchCase, index: usize) ?&Node {
...@@ -864,7 +823,7 @@ pub const NodeSwitchCase = struct {...@@ -864,7 +823,7 @@ pub const NodeSwitchCase = struct {
864 i -= self.items.len;823 i -= self.items.len;
865824
866 if (self.payload) |payload| {825 if (self.payload) |payload| {
867 if (i < 1) return &payload.base;826 if (i < 1) return payload;
868 i -= 1;827 i -= 1;
869 }828 }
870829
...@@ -906,7 +865,7 @@ pub const NodeWhile = struct {...@@ -906,7 +865,7 @@ pub const NodeWhile = struct {
906 inline_token: ?Token,865 inline_token: ?Token,
907 while_token: Token,866 while_token: Token,
908 condition: &Node,867 condition: &Node,
909 payload: ?&NodePointerPayload,868 payload: ?&Node,
910 continue_expr: ?&Node,869 continue_expr: ?&Node,
911 body: &Node,870 body: &Node,
912 @"else": ?&NodeElse,871 @"else": ?&NodeElse,
...@@ -918,7 +877,7 @@ pub const NodeWhile = struct {...@@ -918,7 +877,7 @@ pub const NodeWhile = struct {
918 i -= 1;877 i -= 1;
919878
920 if (self.payload) |payload| {879 if (self.payload) |payload| {
921 if (i < 1) return &payload.base;880 if (i < 1) return payload;
922 i -= 1;881 i -= 1;
923 }882 }
924883
...@@ -965,7 +924,7 @@ pub const NodeFor = struct {...@@ -965,7 +924,7 @@ pub const NodeFor = struct {
965 inline_token: ?Token,924 inline_token: ?Token,
966 for_token: Token,925 for_token: Token,
967 array_expr: &Node,926 array_expr: &Node,
968 payload: ?&NodePointerIndexPayload,927 payload: ?&Node,
969 body: &Node,928 body: &Node,
970 @"else": ?&NodeElse,929 @"else": ?&NodeElse,
971930
...@@ -976,7 +935,7 @@ pub const NodeFor = struct {...@@ -976,7 +935,7 @@ pub const NodeFor = struct {
976 i -= 1;935 i -= 1;
977936
978 if (self.payload) |payload| {937 if (self.payload) |payload| {
979 if (i < 1) return &payload.base;938 if (i < 1) return payload;
980 i -= 1;939 i -= 1;
981 }940 }
982941
...@@ -1016,7 +975,7 @@ pub const NodeIf = struct {...@@ -1016,7 +975,7 @@ pub const NodeIf = struct {
1016 base: Node,975 base: Node,
1017 if_token: Token,976 if_token: Token,
1018 condition: &Node,977 condition: &Node,
1019 payload: ?&NodePointerPayload,978 payload: ?&Node,
1020 body: &Node,979 body: &Node,
1021 @"else": ?&NodeElse,980 @"else": ?&NodeElse,
1022981
...@@ -1027,7 +986,7 @@ pub const NodeIf = struct {...@@ -1027,7 +986,7 @@ pub const NodeIf = struct {
1027 i -= 1;986 i -= 1;
1028987
1029 if (self.payload) |payload| {988 if (self.payload) |payload| {
1030 if (i < 1) return &payload.base;989 if (i < 1) return payload;
1031 i -= 1;990 i -= 1;
1032 }991 }
1033992
...@@ -1089,7 +1048,7 @@ pub const NodeInfixOp = struct {...@@ -1089,7 +1048,7 @@ pub const NodeInfixOp = struct {
1089 BitXor,1048 BitXor,
1090 BoolAnd,1049 BoolAnd,
1091 BoolOr,1050 BoolOr,
1092 Catch: ?&NodePayload,1051 Catch: ?&Node,
1093 Div,1052 Div,
1094 EqualEqual,1053 EqualEqual,
1095 ErrorUnion,1054 ErrorUnion,
...@@ -1117,7 +1076,7 @@ pub const NodeInfixOp = struct {...@@ -1117,7 +1076,7 @@ pub const NodeInfixOp = struct {
1117 switch (self.op) {1076 switch (self.op) {
1118 InfixOp.Catch => |maybe_payload| {1077 InfixOp.Catch => |maybe_payload| {
1119 if (maybe_payload) |payload| {1078 if (maybe_payload) |payload| {
1120 if (i < 1) return &payload.base;1079 if (i < 1) return payload;
1121 i -= 1;1080 i -= 1;
1122 }1081 }
1123 },1082 },
...@@ -1385,14 +1344,30 @@ pub const NodeControlFlowExpression = struct {...@@ -1385,14 +1344,30 @@ pub const NodeControlFlowExpression = struct {
1385 rhs: ?&Node,1344 rhs: ?&Node,
13861345
1387 const Kind = union(enum) {1346 const Kind = union(enum) {
1388 Break: ?Token,1347 Break: ?&Node,
1389 Continue: ?Token,1348 Continue: ?&Node,
1390 Return,1349 Return,
1391 };1350 };
13921351
1393 pub fn iterate(self: &NodeControlFlowExpression, index: usize) ?&Node {1352 pub fn iterate(self: &NodeControlFlowExpression, index: usize) ?&Node {
1394 var i = index;1353 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
1396 if (self.rhs) |rhs| {1371 if (self.rhs) |rhs| {
1397 if (i < 1) return rhs;1372 if (i < 1) return rhs;
1398 i -= 1;1373 i -= 1;
...@@ -1411,14 +1386,14 @@ pub const NodeControlFlowExpression = struct {...@@ -1411,14 +1386,14 @@ pub const NodeControlFlowExpression = struct {
1411 }1386 }
14121387
1413 switch (self.kind) {1388 switch (self.kind) {
1414 Kind.Break => |maybe_blk_token| {1389 Kind.Break => |maybe_label| {
1415 if (maybe_blk_token) |blk_token| {1390 if (maybe_label) |label| {
1416 return blk_token;1391 return label.lastToken();
1417 }1392 }
1418 },1393 },
1419 Kind.Continue => |maybe_blk_token| {1394 Kind.Continue => |maybe_label| {
1420 if (maybe_blk_token) |blk_token| {1395 if (maybe_label) |label| {
1421 return blk_token;1396 return label.lastToken();
1422 }1397 }
1423 },1398 },
1424 Kind.Return => return self.ltoken,1399 Kind.Return => return self.ltoken,
...@@ -1431,14 +1406,14 @@ pub const NodeControlFlowExpression = struct {...@@ -1431,14 +1406,14 @@ pub const NodeControlFlowExpression = struct {
1431pub const NodeSuspend = struct {1406pub const NodeSuspend = struct {
1432 base: Node,1407 base: Node,
1433 suspend_token: Token,1408 suspend_token: Token,
1434 payload: ?&NodePayload,1409 payload: ?&Node,
1435 body: ?&Node,1410 body: ?&Node,
14361411
1437 pub fn iterate(self: &NodeSuspend, index: usize) ?&Node {1412 pub fn iterate(self: &NodeSuspend, index: usize) ?&Node {
1438 var i = index;1413 var i = index;
14391414
1440 if (self.payload) |payload| {1415 if (self.payload) |payload| {
1441 if (i < 1) return &payload.base;1416 if (i < 1) return payload;
1442 i -= 1;1417 i -= 1;
1443 }1418 }
14441419
...@@ -1646,8 +1621,8 @@ pub const NodeThisLiteral = struct {...@@ -1646,8 +1621,8 @@ pub const NodeThisLiteral = struct {
16461621
1647pub const NodeAsmOutput = struct {1622pub const NodeAsmOutput = struct {
1648 base: Node,1623 base: Node,
1649 symbolic_name: &NodeIdentifier,1624 symbolic_name: &Node,
1650 constraint: &NodeStringLiteral,1625 constraint: &Node,
1651 kind: Kind,1626 kind: Kind,
16521627
1653 const Kind = union(enum) {1628 const Kind = union(enum) {
...@@ -1658,10 +1633,10 @@ pub const NodeAsmOutput = struct {...@@ -1658,10 +1633,10 @@ pub const NodeAsmOutput = struct {
1658 pub fn iterate(self: &NodeAsmOutput, index: usize) ?&Node {1633 pub fn iterate(self: &NodeAsmOutput, index: usize) ?&Node {
1659 var i = index;1634 var i = index;
16601635
1661 if (i < 1) return &self.symbolic_name.base;1636 if (i < 1) return self.symbolic_name;
1662 i -= 1;1637 i -= 1;
16631638
1664 if (i < 1) return &self.constraint.base;1639 if (i < 1) return self.constraint;
1665 i -= 1;1640 i -= 1;
16661641
1667 switch (self.kind) {1642 switch (self.kind) {
...@@ -1692,17 +1667,17 @@ pub const NodeAsmOutput = struct {...@@ -1692,17 +1667,17 @@ pub const NodeAsmOutput = struct {
16921667
1693pub const NodeAsmInput = struct {1668pub const NodeAsmInput = struct {
1694 base: Node,1669 base: Node,
1695 symbolic_name: &NodeIdentifier,1670 symbolic_name: &Node,
1696 constraint: &NodeStringLiteral,1671 constraint: &Node,
1697 expr: &Node,1672 expr: &Node,
16981673
1699 pub fn iterate(self: &NodeAsmInput, index: usize) ?&Node {1674 pub fn iterate(self: &NodeAsmInput, index: usize) ?&Node {
1700 var i = index;1675 var i = index;
17011676
1702 if (i < 1) return &self.symbolic_name.base;1677 if (i < 1) return self.symbolic_name;
1703 i -= 1;1678 i -= 1;
17041679
1705 if (i < 1) return &self.constraint.base;1680 if (i < 1) return self.constraint;
1706 i -= 1;1681 i -= 1;
17071682
1708 if (i < 1) return self.expr;1683 if (i < 1) return self.expr;
...@@ -1723,12 +1698,12 @@ pub const NodeAsmInput = struct {...@@ -1723,12 +1698,12 @@ pub const NodeAsmInput = struct {
1723pub const NodeAsm = struct {1698pub const NodeAsm = struct {
1724 base: Node,1699 base: Node,
1725 asm_token: Token,1700 asm_token: Token,
1726 is_volatile: bool,1701 volatile_token: ?Token,
1727 template: Token,1702 template: &Node,
1728 //tokens: ArrayList(AsmToken),1703 //tokens: ArrayList(AsmToken),
1729 outputs: ArrayList(&NodeAsmOutput),1704 outputs: ArrayList(&NodeAsmOutput),
1730 inputs: ArrayList(&NodeAsmInput),1705 inputs: ArrayList(&NodeAsmInput),
1731 cloppers: ArrayList(&NodeStringLiteral),1706 cloppers: ArrayList(&Node),
1732 rparen: Token,1707 rparen: Token,
17331708
1734 pub fn iterate(self: &NodeAsm, index: usize) ?&Node {1709 pub fn iterate(self: &NodeAsm, index: usize) ?&Node {
...@@ -1740,7 +1715,7 @@ pub const NodeAsm = struct {...@@ -1740,7 +1715,7 @@ pub const NodeAsm = struct {
1740 if (i < self.inputs.len) return &self.inputs.at(index).base;1715 if (i < self.inputs.len) return &self.inputs.at(index).base;
1741 i -= self.inputs.len;1716 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);
1744 i -= self.cloppers.len;1719 i -= self.cloppers.len;
17451720
1746 return null;1721 return null;
std/zig/parser.zig+2462-2246
...@@ -55,33 +55,33 @@ pub const Parser = struct {...@@ -55,33 +55,33 @@ pub const Parser = struct {
55 const TopLevelDeclCtx = struct {55 const TopLevelDeclCtx = struct {
56 decls: &ArrayList(&ast.Node),56 decls: &ArrayList(&ast.Node),
57 visib_token: ?Token,57 visib_token: ?Token,
58 extern_token: ?Token,58 extern_export_inline_token: ?Token,
59 lib_name: ?&ast.Node,59 lib_name: ?&ast.Node,
60 };60 };
6161
62 const ContainerExternCtx = struct {62 const VarDeclCtx = struct {
63 dest_ptr: DestPtr,63 mut_token: Token,
64 ltoken: Token,64 visib_token: ?Token,
65 layout: ast.NodeContainerDecl.Layout,65 comptime_token: ?Token,
66 extern_export_token: ?Token,
67 lib_name: ?&ast.Node,
68 list: &ArrayList(&ast.Node),
66 };69 };
6770
68 const DestPtr = union(enum) {71 const TopLevelExternOrFieldCtx = struct {
69 Field: &&ast.Node,72 visib_token: Token,
70 NullableField: &?&ast.Node,73 container_decl: &ast.NodeContainerDecl,
74 };
7175
72 pub fn store(self: &const DestPtr, value: &ast.Node) void {76 const ExternTypeCtx = struct {
73 switch (*self) {77 opt_ctx: OptionalCtx,
74 DestPtr.Field => |ptr| *ptr = value,78 extern_token: Token,
75 DestPtr.NullableField => |ptr| *ptr = value,79 };
76 }
77 }
7880
79 pub fn get(self: &const DestPtr) &ast.Node {81 const ContainerKindCtx = struct {
80 switch (*self) {82 opt_ctx: OptionalCtx,
81 DestPtr.Field => |ptr| return *ptr,83 ltoken: Token,
82 DestPtr.NullableField => |ptr| return ??*ptr,84 layout: ast.NodeContainerDecl.Layout,
83 }
84 }
85 };85 };
8686
87 const ExpectTokenSave = struct {87 const ExpectTokenSave = struct {
...@@ -89,13 +89,9 @@ pub const Parser = struct {...@@ -89,13 +89,9 @@ pub const Parser = struct {
89 ptr: &Token,89 ptr: &Token,
90 };90 };
9191
92 const RevertState = struct {92 const OptionalTokenSave = struct {
93 parser: Parser,93 id: Token.Id,
94 tokenizer: Tokenizer,94 ptr: &?Token,
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,
99 };95 };
10096
101 const ExprListCtx = struct {97 const ExprListCtx = struct {
...@@ -104,11 +100,6 @@ pub const Parser = struct {...@@ -104,11 +100,6 @@ pub const Parser = struct {
104 ptr: &Token,100 ptr: &Token,
105 };101 };
106102
107 const ElseCtx = struct {
108 payload: ?DestPtr,
109 body: DestPtr,
110 };
111
112 fn ListSave(comptime T: type) type {103 fn ListSave(comptime T: type) type {
113 return struct {104 return struct {
114 list: &ArrayList(T),105 list: &ArrayList(T),
...@@ -116,117 +107,196 @@ pub const Parser = struct {...@@ -116,117 +107,196 @@ pub const Parser = struct {
116 };107 };
117 }108 }
118109
110 const MaybeLabeledExpressionCtx = struct {
111 label: Token,
112 opt_ctx: OptionalCtx,
113 };
114
119 const LabelCtx = struct {115 const LabelCtx = struct {
120 label: ?Token,116 label: ?Token,
121 dest_ptr: DestPtr,117 opt_ctx: OptionalCtx,
122 };118 };
123119
124 const InlineCtx = struct {120 const InlineCtx = struct {
125 label: ?Token,121 label: ?Token,
126 inline_token: ?Token,122 inline_token: ?Token,
127 dest_ptr: DestPtr,123 opt_ctx: OptionalCtx,
128 };124 };
129125
130 const LoopCtx = struct {126 const LoopCtx = struct {
131 label: ?Token,127 label: ?Token,
132 inline_token: ?Token,128 inline_token: ?Token,
133 loop_token: Token,129 loop_token: Token,
134 dest_ptr: DestPtr,130 opt_ctx: OptionalCtx,
135 };131 };
136132
137 const AsyncEndCtx = struct {133 const AsyncEndCtx = struct {
138 dest_ptr: DestPtr,134 ctx: OptionalCtx,
139 attribute: &ast.NodeAsyncAttribute,135 attribute: &ast.NodeAsyncAttribute,
140 };136 };
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
142 const State = union(enum) {185 const State = union(enum) {
143 TopLevel,186 TopLevel,
144 TopLevelExtern: TopLevelDeclCtx,187 TopLevelExtern: TopLevelDeclCtx,
188 TopLevelLibname: TopLevelDeclCtx,
145 TopLevelDecl: TopLevelDeclCtx,189 TopLevelDecl: TopLevelDeclCtx,
146 ContainerExtern: ContainerExternCtx,190 TopLevelExternOrField: TopLevelExternOrFieldCtx,
191
192 ContainerKind: ContainerKindCtx,
193 ContainerInitArgStart: &ast.NodeContainerDecl,
194 ContainerInitArg: &ast.NodeContainerDecl,
147 ContainerDecl: &ast.NodeContainerDecl,195 ContainerDecl: &ast.NodeContainerDecl,
148 SliceOrArrayAccess: &ast.NodeSuffixOp,196
149 AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo,197 VarDecl: VarDeclCtx,
150 VarDecl: &ast.NodeVarDecl,
151 VarDeclAlign: &ast.NodeVarDecl,198 VarDeclAlign: &ast.NodeVarDecl,
152 VarDeclEq: &ast.NodeVarDecl,199 VarDeclEq: &ast.NodeVarDecl,
153 IfToken: @TagType(Token.Id),200
154 IfTokenSave: ExpectTokenSave,201 FnDef: &ast.NodeFnProto,
155 ExpectToken: @TagType(Token.Id),
156 ExpectTokenSave: ExpectTokenSave,
157 FnProto: &ast.NodeFnProto,202 FnProto: &ast.NodeFnProto,
158 FnProtoAlign: &ast.NodeFnProto,203 FnProtoAlign: &ast.NodeFnProto,
159 FnProtoReturnType: &ast.NodeFnProto,204 FnProtoReturnType: &ast.NodeFnProto,
205
160 ParamDecl: &ast.NodeFnProto,206 ParamDecl: &ast.NodeFnProto,
161 ParamDeclComma,207 ParamDeclAliasOrComptime: &ast.NodeParamDecl,
162 FnDef: &ast.NodeFnProto,208 ParamDeclName: &ast.NodeParamDecl,
209 ParamDeclEnd: ParamDeclEndCtx,
210 ParamDeclComma: &ast.NodeFnProto,
211
212 MaybeLabeledExpression: MaybeLabeledExpressionCtx,
163 LabeledExpression: LabelCtx,213 LabeledExpression: LabelCtx,
164 Inline: InlineCtx,214 Inline: InlineCtx,
165 While: LoopCtx,215 While: LoopCtx,
216 WhileContinueExpr: &?&ast.Node,
166 For: LoopCtx,217 For: LoopCtx,
167 Block: &ast.NodeBlock,
168 Else: &?&ast.NodeElse,218 Else: &?&ast.NodeElse,
169 WhileContinueExpr: &?&ast.Node,219
220 Block: &ast.NodeBlock,
170 Statement: &ast.NodeBlock,221 Statement: &ast.NodeBlock,
171 Semicolon: &const &const ast.Node,222 ComptimeStatement: ComptimeStatementCtx,
223 Semicolon: &&ast.Node,
224
172 AsmOutputItems: &ArrayList(&ast.NodeAsmOutput),225 AsmOutputItems: &ArrayList(&ast.NodeAsmOutput),
226 AsmOutputReturnOrType: &ast.NodeAsmOutput,
173 AsmInputItems: &ArrayList(&ast.NodeAsmInput),227 AsmInputItems: &ArrayList(&ast.NodeAsmInput),
174 AsmClopperItems: &ArrayList(&ast.NodeStringLiteral),228 AsmClopperItems: &ArrayList(&ast.Node),
229
175 ExprListItemOrEnd: ExprListCtx,230 ExprListItemOrEnd: ExprListCtx,
176 ExprListCommaOrEnd: ExprListCtx,231 ExprListCommaOrEnd: ExprListCtx,
177 FieldInitListItemOrEnd: ListSave(&ast.NodeFieldInitializer),232 FieldInitListItemOrEnd: ListSave(&ast.NodeFieldInitializer),
178 FieldInitListCommaOrEnd: ListSave(&ast.NodeFieldInitializer),233 FieldInitListCommaOrEnd: ListSave(&ast.NodeFieldInitializer),
179 FieldListCommaOrEnd: &ast.NodeContainerDecl,234 FieldListCommaOrEnd: &ast.NodeContainerDecl,
235 IdentifierListItemOrEnd: ListSave(&ast.Node),
236 IdentifierListCommaOrEnd: ListSave(&ast.Node),
180 SwitchCaseOrEnd: ListSave(&ast.NodeSwitchCase),237 SwitchCaseOrEnd: ListSave(&ast.NodeSwitchCase),
181 SuspendBody: &ast.NodeSuspend,
182 AsyncEnd: AsyncEndCtx,
183 Payload: &?&ast.NodePayload,
184 PointerPayload: &?&ast.NodePointerPayload,
185 PointerIndexPayload: &?&ast.NodePointerIndexPayload,
186 SwitchCaseCommaOrEnd: ListSave(&ast.NodeSwitchCase),238 SwitchCaseCommaOrEnd: ListSave(&ast.NodeSwitchCase),
239 SwitchCaseFirstItem: &ArrayList(&ast.Node),
187 SwitchCaseItem: &ArrayList(&ast.Node),240 SwitchCaseItem: &ArrayList(&ast.Node),
188 SwitchCaseItemCommaOrEnd: &ArrayList(&ast.Node),241 SwitchCaseItemCommaOrEnd: &ArrayList(&ast.Node),
189242
190 /// A state that can be appended before any other State. If an error occures,243 SuspendBody: &ast.NodeSuspend,
191 /// the parser will first try looking for the closest optional state. If an244 AsyncAllocator: &ast.NodeAsyncAttribute,
192 /// optional state is found, the parser will revert to the state it was in245 AsyncEnd: AsyncEndCtx,
193 /// when the optional was added. This will polute the arena allocator with246
194 /// "leaked" nodes. TODO: Figure out if it's nessesary to handle leaked nodes.247 ExternType: ExternTypeCtx,
195 Optional: RevertState,248 SliceOrArrayAccess: &ast.NodeSuffixOp,
196249 SliceOrArrayType: &ast.NodePrefixOp,
197 Expression: DestPtr,250 AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo,
198 RangeExpressionBegin: DestPtr,251
199 RangeExpressionEnd: DestPtr,252 Payload: OptionalCtx,
200 AssignmentExpressionBegin: DestPtr,253 PointerPayload: OptionalCtx,
201 AssignmentExpressionEnd: DestPtr,254 PointerIndexPayload: OptionalCtx,
202 UnwrapExpressionBegin: DestPtr,255
203 UnwrapExpressionEnd: DestPtr,256 Expression: OptionalCtx,
204 BoolOrExpressionBegin: DestPtr,257 RangeExpressionBegin: OptionalCtx,
205 BoolOrExpressionEnd: DestPtr,258 RangeExpressionEnd: OptionalCtx,
206 BoolAndExpressionBegin: DestPtr,259 AssignmentExpressionBegin: OptionalCtx,
207 BoolAndExpressionEnd: DestPtr,260 AssignmentExpressionEnd: OptionalCtx,
208 ComparisonExpressionBegin: DestPtr,261 UnwrapExpressionBegin: OptionalCtx,
209 ComparisonExpressionEnd: DestPtr,262 UnwrapExpressionEnd: OptionalCtx,
210 BinaryOrExpressionBegin: DestPtr,263 BoolOrExpressionBegin: OptionalCtx,
211 BinaryOrExpressionEnd: DestPtr,264 BoolOrExpressionEnd: OptionalCtx,
212 BinaryXorExpressionBegin: DestPtr,265 BoolAndExpressionBegin: OptionalCtx,
213 BinaryXorExpressionEnd: DestPtr,266 BoolAndExpressionEnd: OptionalCtx,
214 BinaryAndExpressionBegin: DestPtr,267 ComparisonExpressionBegin: OptionalCtx,
215 BinaryAndExpressionEnd: DestPtr,268 ComparisonExpressionEnd: OptionalCtx,
216 BitShiftExpressionBegin: DestPtr,269 BinaryOrExpressionBegin: OptionalCtx,
217 BitShiftExpressionEnd: DestPtr,270 BinaryOrExpressionEnd: OptionalCtx,
218 AdditionExpressionBegin: DestPtr,271 BinaryXorExpressionBegin: OptionalCtx,
219 AdditionExpressionEnd: DestPtr,272 BinaryXorExpressionEnd: OptionalCtx,
220 MultiplyExpressionBegin: DestPtr,273 BinaryAndExpressionBegin: OptionalCtx,
221 MultiplyExpressionEnd: DestPtr,274 BinaryAndExpressionEnd: OptionalCtx,
222 CurlySuffixExpressionBegin: DestPtr,275 BitShiftExpressionBegin: OptionalCtx,
223 CurlySuffixExpressionEnd: DestPtr,276 BitShiftExpressionEnd: OptionalCtx,
224 TypeExprBegin: DestPtr,277 AdditionExpressionBegin: OptionalCtx,
225 TypeExprEnd: DestPtr,278 AdditionExpressionEnd: OptionalCtx,
226 PrefixOpExpression: DestPtr,279 MultiplyExpressionBegin: OptionalCtx,
227 SuffixOpExpressionBegin: DestPtr,280 MultiplyExpressionEnd: OptionalCtx,
228 SuffixOpExpressionEnd: DestPtr,281 CurlySuffixExpressionBegin: OptionalCtx,
229 PrimaryExpression: DestPtr,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,
230 };300 };
231301
232 /// Returns an AST tree, allocated with the parser's allocator.302 /// Returns an AST tree, allocated with the parser's allocator.
...@@ -240,7 +310,14 @@ pub const Parser = struct {...@@ -240,7 +310,14 @@ pub const Parser = struct {
240 errdefer arena_allocator.deinit();310 errdefer arena_allocator.deinit();
241311
242 const arena = &arena_allocator.allocator;312 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
245 try stack.append(State.TopLevel);322 try stack.append(State.TopLevel);
246323
...@@ -259,8 +336,7 @@ pub const Parser = struct {...@@ -259,8 +336,7 @@ pub const Parser = struct {
259336
260 // look for line comments337 // look for line comments
261 while (true) {338 while (true) {
262 const token = self.getNextToken();339 if (self.eatToken(Token.Id.LineComment)) |line_comment| {
263 if (token.id == Token.Id.LineComment) {
264 const node = blk: {340 const node = blk: {
265 if (self.pending_line_comment_node) |comment_node| {341 if (self.pending_line_comment_node) |comment_node| {
266 break :blk comment_node;342 break :blk comment_node;
...@@ -277,10 +353,9 @@ pub const Parser = struct {...@@ -277,10 +353,9 @@ pub const Parser = struct {
277 break :blk comment_node;353 break :blk comment_node;
278 }354 }
279 };355 };
280 try node.lines.append(token);356 try node.lines.append(line_comment);
281 continue;357 continue;
282 }358 }
283 self.putBackToken(token);
284 break;359 break;
285 }360 }
286361
...@@ -294,41 +369,74 @@ pub const Parser = struct {...@@ -294,41 +369,74 @@ pub const Parser = struct {
294 Token.Id.Keyword_test => {369 Token.Id.Keyword_test => {
295 stack.append(State.TopLevel) catch unreachable;370 stack.append(State.TopLevel) catch unreachable;
296371
297 const name_token = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue;372 const block = try self.createNode(arena, ast.NodeBlock,
298 const lbrace = (try self.eatToken(&stack, Token.Id.LBrace)) ?? continue;373 ast.NodeBlock {
299374 .base = undefined,
300 const name = try self.createStringLiteral(arena, name_token);375 .label = null,
301 const block = try self.createBlock(arena, (?Token)(null), token);376 .lbrace = undefined,
302 const test_decl = try self.createAttachTestDecl(arena, &root_node.decls, token, &name.base, block);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 );
303 stack.append(State { .Block = block }) catch unreachable;389 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 } });
304 continue;397 continue;
305 },398 },
306 Token.Id.Eof => {399 Token.Id.Eof => {
307 root_node.eof_token = token;400 root_node.eof_token = token;
308 return Tree {.root_node = root_node, .arena_allocator = arena_allocator};401 return Tree {.root_node = root_node, .arena_allocator = arena_allocator};
309 },402 },
310 Token.Id.Keyword_pub, Token.Id.Keyword_export => {403 Token.Id.Keyword_pub => {
311 stack.append(State.TopLevel) catch unreachable;404 stack.append(State.TopLevel) catch unreachable;
312 try stack.append(State {405 try stack.append(State {
313 .TopLevelExtern = TopLevelDeclCtx {406 .TopLevelExtern = TopLevelDeclCtx {
314 .decls = &root_node.decls,407 .decls = &root_node.decls,
315 .visib_token = token,408 .visib_token = token,
316 .extern_token = null,409 .extern_export_inline_token = null,
317 .lib_name = null,410 .lib_name = null,
318 }411 }
319 });412 });
320 continue;413 continue;
321 },414 },
322 Token.Id.Keyword_comptime => {415 Token.Id.Keyword_comptime => {
323 const node = try arena.create(ast.NodeComptime);416 const block = try self.createNode(arena, ast.NodeBlock,
324 *node = ast.NodeComptime {417 ast.NodeBlock {
325 .base = self.initNode(ast.Node.Id.Comptime),418 .base = undefined,
326 .comptime_token = token,419 .label = null,
327 .expr = undefined,420 .lbrace = undefined,
328 };421 .statements = ArrayList(&ast.Node).init(arena),
329 try root_node.decls.append(&node.base);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 );
330 stack.append(State.TopLevel) catch unreachable;432 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 });
332 continue;440 continue;
333 },441 },
334 else => {442 else => {
...@@ -338,7 +446,7 @@ pub const Parser = struct {...@@ -338,7 +446,7 @@ pub const Parser = struct {
338 .TopLevelExtern = TopLevelDeclCtx {446 .TopLevelExtern = TopLevelDeclCtx {
339 .decls = &root_node.decls,447 .decls = &root_node.decls,
340 .visib_token = null,448 .visib_token = null,
341 .extern_token = null,449 .extern_export_inline_token = null,
342 .lib_name = null,450 .lib_name = null,
343 }451 }
344 });452 });
...@@ -349,43 +457,24 @@ pub const Parser = struct {...@@ -349,43 +457,24 @@ pub const Parser = struct {
349 State.TopLevelExtern => |ctx| {457 State.TopLevelExtern => |ctx| {
350 const token = self.getNextToken();458 const token = self.getNextToken();
351 switch (token.id) {459 switch (token.id) {
352 Token.Id.Keyword_use => {460 Token.Id.Keyword_export, Token.Id.Keyword_inline => {
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
362 stack.append(State {461 stack.append(State {
363 .ExpectTokenSave = ExpectTokenSave {462 .TopLevelDecl = TopLevelDeclCtx {
364 .id = Token.Id.Semicolon,463 .decls = ctx.decls,
365 .ptr = &node.semicolon_token,464 .visib_token = ctx.visib_token,
366 }465 .extern_export_inline_token = token,
466 .lib_name = null,
467 },
367 }) catch unreachable;468 }) catch unreachable;
368 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
369 continue;469 continue;
370 },470 },
371 Token.Id.Keyword_extern => {471 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
383 stack.append(State {472 stack.append(State {
384 .TopLevelDecl = TopLevelDeclCtx {473 .TopLevelLibname = TopLevelDeclCtx {
385 .decls = ctx.decls,474 .decls = ctx.decls,
386 .visib_token = ctx.visib_token,475 .visib_token = ctx.visib_token,
387 .extern_token = token,476 .extern_export_inline_token = token,
388 .lib_name = lib_name,477 .lib_name = null,
389 },478 },
390 }) catch unreachable;479 }) catch unreachable;
391 continue;480 continue;
...@@ -397,258 +486,302 @@ pub const Parser = struct {...@@ -397,258 +486,302 @@ pub const Parser = struct {
397 }486 }
398 }487 }
399 },488 },
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 },
400 State.TopLevelDecl => |ctx| {508 State.TopLevelDecl => |ctx| {
401 const token = self.getNextToken();509 const token = self.getNextToken();
402 switch (token.id) {510 switch (token.id) {
403 Token.Id.Keyword_var, Token.Id.Keyword_const => {511 Token.Id.Keyword_use => {
404 // TODO shouldn't need these casts512 if (ctx.extern_export_inline_token != null) {
405 const var_decl_node = try self.createAttachVarDecl(arena, ctx.decls, ctx.visib_token,513 return self.parseError(token, "Invalid token {}", @tagName((??ctx.extern_export_inline_token).id));
406 token, (?Token)(null), ctx.extern_token, ctx.lib_name);514 }
407 stack.append(State { .VarDecl = var_decl_node }) catch unreachable;515
408 continue;516 const node = try self.createAttachNode(arena, ctx.decls, ast.NodeUse,
409 },517 ast.NodeUse {
410 Token.Id.Keyword_fn => {518 .base = undefined,
411 // TODO shouldn't need these casts519 .visib_token = ctx.visib_token,
412 const fn_proto = try self.createAttachFnProto(arena, ctx.decls, token,520 .expr = undefined,
413 ctx.extern_token, ctx.lib_name, (?Token)(null), ctx.visib_token, (?Token)(null));521 .semicolon_token = undefined,
414 stack.append(State { .FnDef = fn_proto }) catch unreachable;522 }
415 try stack.append(State { .FnProto = fn_proto });523 );
416 continue;524 stack.append(State {
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 {
425 .ExpectTokenSave = ExpectTokenSave {525 .ExpectTokenSave = ExpectTokenSave {
426 .id = Token.Id.Keyword_fn,526 .id = Token.Id.Semicolon,
427 .ptr = &fn_proto.fn_token,527 .ptr = &node.semicolon_token,
428 }528 }
429 });529 }) catch unreachable;
530 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
430 continue;531 continue;
431 },532 },
432 Token.Id.Keyword_async => {533 Token.Id.Keyword_var, Token.Id.Keyword_const => {
433 // TODO shouldn't need this cast534 if (ctx.extern_export_inline_token) |extern_export_inline_token| {
434 const fn_proto = try self.createAttachFnProto(arena, ctx.decls, Token(undefined),535 if (extern_export_inline_token.id == Token.Id.Keyword_inline) {
435 ctx.extern_token, ctx.lib_name, (?Token)(null), (?Token)(null), (?Token)(null));536 return self.parseError(token, "Invalid token {}", @tagName(extern_export_inline_token.id));
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,
452 }537 }
453 });
454
455 const langle_bracket = self.getNextToken();
456 if (langle_bracket.id != Token.Id.AngleBracketLeft) {
457 self.putBackToken(langle_bracket);
458 continue;
459 }538 }
460539
461 async_node.rangle_bracket = Token(undefined);540 stack.append(State {
462 try stack.append(State {541 .VarDecl = VarDeclCtx {
463 .ExpectTokenSave = ExpectTokenSave {542 .visib_token = ctx.visib_token,
464 .id = Token.Id.AngleBracketRight,543 .lib_name = ctx.lib_name,
465 .ptr = &??async_node.rangle_bracket,544 .comptime_token = null,
545 .extern_export_token = ctx.extern_export_inline_token,
546 .mut_token = token,
547 .list = ctx.decls
466 }548 }
467 });549 }) catch unreachable;
468 try stack.append(State { .TypeExprBegin = DestPtr { .NullableField = &async_node.allocator_type } });
469 continue;550 continue;
470 },551 },
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 },
471 else => {612 else => {
472 try self.parseError(&stack, token, "expected variable declaration or function, found {}", @tagName(token.id));613 return self.parseError(token, "expected variable declaration or function, found {}", @tagName(token.id));
473 continue;
474 },614 },
475 }615 }
476 },616 },
477 State.VarDecl => |var_decl| {617 State.TopLevelExternOrField => |ctx| {
478 stack.append(State { .VarDeclAlign = var_decl }) catch unreachable;618 if (self.eatToken(Token.Id.Identifier)) |identifier| {
479 try stack.append(State { .TypeExprBegin = DestPtr {.NullableField = &var_decl.type_node} });619 std.debug.assert(ctx.container_decl.kind == ast.NodeContainerDecl.Kind.Struct);
480 try stack.append(State { .IfToken = Token.Id.Colon });620 const node = try self.createAttachNode(arena, &ctx.container_decl.fields_and_decls, ast.NodeStructField,
481 try stack.append(State {621 ast.NodeStructField {
482 .ExpectTokenSave = ExpectTokenSave {622 .base = undefined,
483 .id = Token.Id.Identifier,623 .visib_token = ctx.visib_token,
484 .ptr = &var_decl.name_token,624 .name_token = identifier,
485 }625 .type_expr = undefined,
486 });626 }
487 continue;627 );
488 },
489 State.VarDeclAlign => |var_decl| {
490 stack.append(State { .VarDeclEq = var_decl }) catch unreachable;
491628
492 const next_token = self.getNextToken();629 stack.append(State { .FieldListCommaOrEnd = ctx.container_decl }) catch unreachable;
493 if (next_token.id == Token.Id.Keyword_align) {630 try stack.append(State { .Expression = OptionalCtx { .Required = &node.type_expr } });
494 try stack.append(State { .ExpectToken = Token.Id.RParen });631 try stack.append(State { .ExpectToken = Token.Id.Colon });
495 try stack.append(State { .Expression = DestPtr{.NullableField = &var_decl.align_node} });
496 try stack.append(State { .ExpectToken = Token.Id.LParen });
497 continue;632 continue;
498 }633 }
499634
500 self.putBackToken(next_token);635 stack.append(State{ .ContainerDecl = ctx.container_decl }) catch unreachable;
501 continue;636 try stack.append(State {
502 },637 .TopLevelExtern = TopLevelDeclCtx {
503 State.VarDeclEq => |var_decl| {638 .decls = &ctx.container_decl.fields_and_decls,
504 const token = self.getNextToken();639 .visib_token = ctx.visib_token,
505 if (token.id == Token.Id.Equal) {640 .extern_export_inline_token = null,
506 var_decl.eq_token = token;641 .lib_name = null,
507 stack.append(State {642 }
508 .ExpectTokenSave = ExpectTokenSave {643 });
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));
523 continue;644 continue;
524 },645 },
525646
526 State.ContainerExtern => |ctx| {
527 const token = self.getNextToken();
528647
529 const node = try arena.create(ast.NodeContainerDecl);648 State.ContainerKind => |ctx| {
530 *node = ast.NodeContainerDecl {649 const token = self.getNextToken();
531 .base = self.initNode(ast.Node.Id.ContainerDecl),650 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeContainerDecl,
532 .ltoken = ctx.ltoken,651 ast.NodeContainerDecl {
533 .layout = ctx.layout,652 .base = undefined,
534 .kind = switch (token.id) {653 .ltoken = ctx.ltoken,
535 Token.Id.Keyword_struct => ast.NodeContainerDecl.Kind.Struct,654 .layout = ctx.layout,
536 Token.Id.Keyword_union => ast.NodeContainerDecl.Kind.Union,655 .kind = switch (token.id) {
537 Token.Id.Keyword_enum => ast.NodeContainerDecl.Kind.Enum,656 Token.Id.Keyword_struct => ast.NodeContainerDecl.Kind.Struct,
538 else => {657 Token.Id.Keyword_union => ast.NodeContainerDecl.Kind.Union,
539 try self.parseError(&stack, token, "expected {}, {} or {}, found {}",658 Token.Id.Keyword_enum => ast.NodeContainerDecl.Kind.Enum,
540 @tagName(Token.Id.Keyword_struct),659 else => {
541 @tagName(Token.Id.Keyword_union),660 return self.parseError(token, "expected {}, {} or {}, found {}",
542 @tagName(Token.Id.Keyword_enum),661 @tagName(Token.Id.Keyword_struct),
543 @tagName(token.id));662 @tagName(Token.Id.Keyword_union),
544 continue;663 @tagName(Token.Id.Keyword_enum),
664 @tagName(token.id));
665 },
545 },666 },
546 },667 .init_arg_expr = ast.NodeContainerDecl.InitArg.None,
547 .init_arg_expr = undefined,668 .fields_and_decls = ArrayList(&ast.Node).init(arena),
548 .fields_and_decls = ArrayList(&ast.Node).init(arena),669 .rbrace_token = undefined,
549 .rbrace_token = undefined,670 }
550 };671 );
551 ctx.dest_ptr.store(&node.base);
552672
553 stack.append(State { .ContainerDecl = node }) catch unreachable;673 stack.append(State { .ContainerDecl = node }) catch unreachable;
554 try stack.append(State { .ExpectToken = Token.Id.LBrace });674 try stack.append(State { .ExpectToken = Token.Id.LBrace });
675 try stack.append(State { .ContainerInitArgStart = node });
676 continue;
677 },
555678
556 const lparen = self.getNextToken();679 State.ContainerInitArgStart => |container_decl| {
557 if (lparen.id != Token.Id.LParen) {680 if (self.eatToken(Token.Id.LParen) == null) {
558 self.putBackToken(lparen);
559 node.init_arg_expr = ast.NodeContainerDecl.InitArg.None;
560 continue;681 continue;
561 }682 }
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| {
565 const init_arg_token = self.getNextToken();690 const init_arg_token = self.getNextToken();
566 switch (init_arg_token.id) {691 switch (init_arg_token.id) {
567 Token.Id.Keyword_enum => {692 Token.Id.Keyword_enum => {
568 node.init_arg_expr = ast.NodeContainerDecl.InitArg.Enum;693 container_decl.init_arg_expr = ast.NodeContainerDecl.InitArg.Enum;
569 },694 },
570 else => {695 else => {
571 self.putBackToken(init_arg_token);696 self.putBackToken(init_arg_token);
572 node.init_arg_expr = ast.NodeContainerDecl.InitArg { .Type = undefined };697 container_decl.init_arg_expr = ast.NodeContainerDecl.InitArg { .Type = undefined };
573 try stack.append(State {698 stack.append(State { .Expression = OptionalCtx { .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;
574 .Expression = DestPtr {
575 .Field = &node.init_arg_expr.Type
576 }
577 });
578 },699 },
579 }700 }
580 continue;701 continue;
581 },702 },
582
583 State.ContainerDecl => |container_decl| {703 State.ContainerDecl => |container_decl| {
584 const token = self.getNextToken();704 const token = self.getNextToken();
585
586 switch (token.id) {705 switch (token.id) {
587 Token.Id.Identifier => {706 Token.Id.Identifier => {
588 switch (container_decl.kind) {707 switch (container_decl.kind) {
589 ast.NodeContainerDecl.Kind.Struct => {708 ast.NodeContainerDecl.Kind.Struct => {
590 const node = try arena.create(ast.NodeStructField);709 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeStructField,
591 *node = ast.NodeStructField {710 ast.NodeStructField {
592 .base = self.initNode(ast.Node.Id.StructField),711 .base = undefined,
593 .name_token = token,712 .visib_token = null,
594 .type_expr = undefined,713 .name_token = token,
595 };714 .type_expr = undefined,
596 try container_decl.fields_and_decls.append(&node.base);715 }
716 );
597717
598 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;718 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 } });
600 try stack.append(State { .ExpectToken = Token.Id.Colon });720 try stack.append(State { .ExpectToken = Token.Id.Colon });
601 continue;721 continue;
602 },722 },
603 ast.NodeContainerDecl.Kind.Union => {723 ast.NodeContainerDecl.Kind.Union => {
604 const node = try arena.create(ast.NodeUnionTag);724 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeUnionTag,
605 *node = ast.NodeUnionTag {725 ast.NodeUnionTag {
606 .base = self.initNode(ast.Node.Id.UnionTag),726 .base = undefined,
607 .name_token = token,727 .name_token = token,
608 .type_expr = null,728 .type_expr = null,
609 };729 }
610 try container_decl.fields_and_decls.append(&node.base);730 );
611731
612 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;732 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
613733 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &node.type_expr } });
614 const next = self.getNextToken();734 try stack.append(State { .IfToken = Token.Id.Colon });
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 } });
621 continue;735 continue;
622 },736 },
623 ast.NodeContainerDecl.Kind.Enum => {737 ast.NodeContainerDecl.Kind.Enum => {
624 const node = try arena.create(ast.NodeEnumTag);738 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeEnumTag,
625 *node = ast.NodeEnumTag {739 ast.NodeEnumTag {
626 .base = self.initNode(ast.Node.Id.EnumTag),740 .base = undefined,
627 .name_token = token,741 .name_token = token,
628 .value = null,742 .value = null,
629 };743 }
630 try container_decl.fields_and_decls.append(&node.base);744 );
631745
632 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;746 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
633747 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &node.value } });
634 const next = self.getNextToken();748 try stack.append(State { .IfToken = Token.Id.Equal });
635 if (next.id != Token.Id.Equal) {749 continue;
636 self.putBackToken(next);750 },
637 continue;751 }
638 }752 },
639753 Token.Id.Keyword_pub => {
640 try stack.append(State { .Expression = DestPtr { .NullableField = &node.value } });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 });
641 continue;762 continue;
642 },763 },
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 }
643 }776 }
644 },777 },
645 Token.Id.Keyword_pub, Token.Id.Keyword_export => {778 Token.Id.Keyword_export => {
646 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;779 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
647 try stack.append(State {780 try stack.append(State {
648 .TopLevelExtern = TopLevelDeclCtx {781 .TopLevelExtern = TopLevelDeclCtx {
649 .decls = &container_decl.fields_and_decls,782 .decls = &container_decl.fields_and_decls,
650 .visib_token = token,783 .visib_token = token,
651 .extern_token = null,784 .extern_export_inline_token = null,
652 .lib_name = null,785 .lib_name = null,
653 }786 }
654 });787 });
...@@ -665,7 +798,7 @@ pub const Parser = struct {...@@ -665,7 +798,7 @@ pub const Parser = struct {
665 .TopLevelExtern = TopLevelDeclCtx {798 .TopLevelExtern = TopLevelDeclCtx {
666 .decls = &container_decl.fields_and_decls,799 .decls = &container_decl.fields_and_decls,
667 .visib_token = null,800 .visib_token = null,
668 .extern_token = null,801 .extern_export_inline_token = null,
669 .lib_name = null,802 .lib_name = null,
670 }803 }
671 });804 });
...@@ -674,161 +807,251 @@ pub const Parser = struct {...@@ -674,161 +807,251 @@ pub const Parser = struct {
674 }807 }
675 },808 },
676809
677 State.ExpectToken => |token_id| {
678 _ = (try self.eatToken(&stack, token_id)) ?? continue;
679 continue;
680 },
681810
682 State.ExpectTokenSave => |expect_token_save| {811 State.VarDecl => |ctx| {
683 *expect_token_save.ptr = (try self.eatToken(&stack, expect_token_save.id)) ?? continue;812 const var_decl = try self.createAttachNode(arena, ctx.list, ast.NodeVarDecl,
684 continue;813 ast.NodeVarDecl {
685 },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| {830 stack.append(State { .VarDeclAlign = var_decl }) catch unreachable;
688 const token = self.getNextToken();831 try stack.append(State { .TypeExprBegin = OptionalCtx { .RequiredNull = &var_decl.type_node} });
689 if (@TagType(Token.Id)(token.id) != token_id) {832 try stack.append(State { .IfToken = Token.Id.Colon });
690 self.putBackToken(token);833 try stack.append(State {
691 _ = stack.pop();834 .ExpectTokenSave = ExpectTokenSave {
692 continue;835 .id = Token.Id.Identifier,
693 }836 .ptr = &var_decl.name_token,
837 }
838 });
694 continue;839 continue;
695 },840 },
841 State.VarDeclAlign => |var_decl| {
842 stack.append(State { .VarDeclEq = var_decl }) catch unreachable;
696843
697 State.IfTokenSave => |if_token_save| {844 const next_token = self.getNextToken();
698 const token = self.getNextToken();845 if (next_token.id == Token.Id.Keyword_align) {
699 if (@TagType(Token.Id)(token.id) != if_token_save.id) {846 try stack.append(State { .ExpectToken = Token.Id.RParen });
700 self.putBackToken(token);847 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.align_node} });
701 _ = stack.pop();848 try stack.append(State { .ExpectToken = Token.Id.LParen });
702 continue;849 continue;
703 }850 }
704851
705 *if_token_save.ptr = token;852 self.putBackToken(next_token);
706 continue;853 continue;
707 },854 },
708855 State.VarDeclEq => |var_decl| {
709 State.Optional => { },
710
711 State.Expression => |dest_ptr| {
712 const token = self.getNextToken();856 const token = self.getNextToken();
713 switch (token.id) {857 switch (token.id) {
714 Token.Id.Keyword_try => {858 Token.Id.Equal => {
715 const node = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp.Try);859 var_decl.eq_token = token;
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
725 stack.append(State {860 stack.append(State {
726 .Optional = RevertState {861 .ExpectTokenSave = ExpectTokenSave {
727 .parser = *self,862 .id = Token.Id.Semicolon,
728 .tokenizer = *self.tokenizer,863 .ptr = &var_decl.semicolon_token,
729 .ptr = &node.rhs,864 },
730 }
731 }) catch unreachable;865 }) catch unreachable;
732 try stack.append(State { .Expression = DestPtr { .NullableField = &node.rhs } });866 try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.init_node } });
733 continue;867 continue;
734 },868 },
735 Token.Id.Keyword_break => {869 Token.Id.Semicolon => {
736 const label = blk: {870 var_decl.semicolon_token = token;
737 const colon = self.getNextToken();871 continue;
738 if (colon.id != Token.Id.Colon) {872 },
739 self.putBackToken(colon);873 else => {
740 break :blk null;874 return self.parseError(token, "expected '=' or ';', found {}", @tagName(token.id));
741 }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,880 State.FnDef => |fn_proto| {
747 ast.NodeControlFlowExpression.Kind {881 const token = self.getNextToken();
748 .Break = label,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,
749 }891 }
750 );892 );
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 };
753 stack.append(State {928 stack.append(State {
754 .Optional = RevertState {929 .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.InferErrorSet },
755 .parser = *self,
756 .tokenizer = *self.tokenizer,
757 .ptr = &node.rhs,
758 }
759 }) catch unreachable;930 }) catch unreachable;
760 try stack.append(State { .Expression = DestPtr { .NullableField = &node.rhs } });
761 continue;931 continue;
762 },932 },
763 Token.Id.Keyword_continue => {933 else => {
764 const label = blk: {934 // TODO: this is a special case. Remove this when #760 is fixed
765 const colon = self.getNextToken();935 if (token.id == Token.Id.Keyword_error) {
766 if (colon.id != Token.Id.Colon) {936 if (self.isPeekToken(Token.Id.LBrace)) {
767 self.putBackToken(colon);937 fn_proto.return_type = ast.NodeFnProto.ReturnType {
768 break :blk null;938 .Explicit = &(try self.createLiteral(arena, ast.NodeErrorType, token)).base
939 };
940 continue;
769 }941 }
942 }
770943
771 break :blk (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;944 self.putBackToken(token);
772 };945 fn_proto.return_type = ast.NodeFnProto.ReturnType { .Explicit = undefined };
773946 stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &fn_proto.return_type.Explicit }, }) catch unreachable;
774 const node = try self.createControlFlowExpr(arena, token,
775 ast.NodeControlFlowExpression.Kind {
776 .Continue = label,
777 }
778 );
779 dest_ptr.store(&node.base);
780 continue;947 continue;
781 },948 },
782 Token.Id.Keyword_cancel => {949 }
783 const cancel_node = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp.Cancel);950 },
784 dest_ptr.store(&cancel_node.base);951
785 stack.append(State { .Expression = DestPtr { .Field = &cancel_node.rhs } }) catch unreachable;952
786 },953 State.ParamDecl => |fn_proto| {
787 Token.Id.Keyword_resume => {954 if (self.eatToken(Token.Id.RParen)) |_| {
788 const resume_node = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp.Resume);955 continue;
789 dest_ptr.store(&resume_node.base);956 }
790 stack.append(State { .Expression = DestPtr { .Field = &resume_node.rhs } }) catch unreachable;957 const param_decl = try self.createAttachNode(arena, &fn_proto.params, ast.NodeParamDecl,
791 },958 ast.NodeParamDecl {
792 Token.Id.Keyword_suspend => {959 .base = undefined,
793 const node = try arena.create(ast.NodeSuspend);960 .comptime_token = null,
794 *node = ast.NodeSuspend {961 .noalias_token = null,
795 .base = self.initNode(ast.Node.Id.Suspend),962 .name_token = null,
796 .suspend_token = token,963 .type_node = undefined,
797 .payload = null,964 .var_args_token = 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;
804 },965 },
805 Token.Id.Keyword_if => {966 );
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);
816967
817 stack.append(State { .Else = &node.@"else" }) catch unreachable;968 stack.append(State {
818 try stack.append(State { .Expression = DestPtr { .Field = &node.body } });969 .ParamDeclEnd = ParamDeclEndCtx {
819 try stack.append(State { .PointerPayload = &node.payload });970 .param_decl = param_decl,
820 try stack.append(State { .ExpectToken = Token.Id.RParen });971 .fn_proto = fn_proto,
821 try stack.append(State { .Expression = DestPtr { .Field = &node.condition } });972 }
822 try stack.append(State { .ExpectToken = Token.Id.LParen });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;
823 continue;1046 continue;
824 },1047 },
825 Token.Id.Keyword_while => {1048 Token.Id.Keyword_while => {
826 stack.append(State {1049 stack.append(State {
827 .While = LoopCtx {1050 .While = LoopCtx {
828 .label = null,1051 .label = ctx.label,
829 .inline_token = null,1052 .inline_token = null,
830 .loop_token = token,1053 .loop_token = token,
831 .dest_ptr = dest_ptr,1054 .opt_ctx = ctx.opt_ctx.toRequired(),
832 }1055 }
833 }) catch unreachable;1056 }) catch unreachable;
834 continue;1057 continue;
...@@ -836,1670 +1059,1693 @@ pub const Parser = struct {...@@ -836,1670 +1059,1693 @@ pub const Parser = struct {
836 Token.Id.Keyword_for => {1059 Token.Id.Keyword_for => {
837 stack.append(State {1060 stack.append(State {
838 .For = LoopCtx {1061 .For = LoopCtx {
839 .label = null,1062 .label = ctx.label,
840 .inline_token = null,1063 .inline_token = null,
841 .loop_token = token,1064 .loop_token = token,
842 .dest_ptr = dest_ptr,1065 .opt_ctx = ctx.opt_ctx.toRequired(),
843 }1066 }
844 }) catch unreachable;1067 }) catch unreachable;
845 continue;1068 continue;
846 },1069 },
847 Token.Id.Keyword_switch => {1070 Token.Id.Keyword_inline => {
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
858 stack.append(State {1071 stack.append(State {
859 .SwitchCaseOrEnd = ListSave(&ast.NodeSwitchCase) {1072 .Inline = InlineCtx {
860 .list = &node.cases,1073 .label = ctx.label,
861 .ptr = &node.rbrace,1074 .inline_token = token,
862 },1075 .opt_ctx = ctx.opt_ctx.toRequired(),
1076 }
863 }) catch unreachable;1077 }) 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 } });
878 continue;1078 continue;
879 },1079 },
880 Token.Id.LBrace => {1080 else => {
881 const block = try self.createBlock(arena, (?Token)(null), token);1081 if (ctx.opt_ctx != OptionalCtx.Optional) {
882 dest_ptr.store(&block.base);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;
885 continue;1113 continue;
886 },1114 },
887 else => {1115 else => {
1116 if (ctx.opt_ctx != OptionalCtx.Optional) {
1117 return self.parseError(token, "expected 'while' or 'for', found {}", @tagName(token.id));
1118 }
1119
888 self.putBackToken(token);1120 self.putBackToken(token);
889 stack.append(State { .UnwrapExpressionBegin = dest_ptr }) catch unreachable;
890 continue;1121 continue;
891 }1122 },
892 }1123 }
893 },1124 },
8941125 State.While => |ctx| {
895 State.RangeExpressionBegin => |dest_ptr| {1126 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeWhile,
896 stack.append(State { .RangeExpressionEnd = dest_ptr }) catch unreachable;1127 ast.NodeWhile {
897 try stack.append(State { .Expression = dest_ptr });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 });
898 continue;1147 continue;
899 },1148 },
9001149 State.WhileContinueExpr => |dest| {
901 State.RangeExpressionEnd => |dest_ptr| {1150 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
902 const token = self.getNextToken();1151 try stack.append(State { .AssignmentExpressionBegin = OptionalCtx { .RequiredNull = dest } });
903 if (token.id == Token.Id.Ellipsis3) {1152 try stack.append(State { .ExpectToken = Token.Id.LParen });
904 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.Range);1153 continue;
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 }
914 },1154 },
9151155 State.For => |ctx| {
916 State.AssignmentExpressionBegin => |dest_ptr| {1156 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeFor,
917 stack.append(State { .AssignmentExpressionEnd = dest_ptr }) catch unreachable;1157 ast.NodeFor {
918 try stack.append(State { .Expression = dest_ptr });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 });
919 continue;1174 continue;
920 },1175 },
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| {1188 stack.append(State { .Expression = OptionalCtx { .Required = &node.body } }) catch unreachable;
923 const token = self.getNextToken();1189 try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } });
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 } });
931 continue;1190 continue;
932 } else {1191 } else {
933 self.putBackToken(token);
934 continue;1192 continue;
935 }1193 }
936 },1194 },
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| {
945 const token = self.getNextToken();1198 const token = self.getNextToken();
946 switch (token.id) {1199 switch (token.id) {
947 Token.Id.Keyword_catch => {1200 Token.Id.RBrace => {
948 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp { .Catch = null });1201 block.rbrace = token;
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 } });
964 continue;1202 continue;
965 },1203 },
966 else => {1204 else => {
967 self.putBackToken(token);1205 self.putBackToken(token);
1206 stack.append(State { .Block = block }) catch unreachable;
1207 try stack.append(State { .Statement = block });
968 continue;1208 continue;
969 },1209 },
970 }1210 }
971 },1211 },
9721212 State.Statement => |block| {
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| {
980 const token = self.getNextToken();1213 const token = self.getNextToken();
981 switch (token.id) {1214 switch (token.id) {
982 Token.Id.Keyword_or => {1215 Token.Id.Keyword_comptime => {
983 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BoolOr);1216 stack.append(State {
984 node.lhs = dest_ptr.get();1217 .ComptimeStatement = ComptimeStatementCtx {
985 dest_ptr.store(&node.base);1218 .comptime_token = token,
9861219 .block = block,
987 stack.append(State { .BoolOrExpressionEnd = dest_ptr }) catch unreachable;1220 }
988 try stack.append(State { .BoolAndExpressionBegin = DestPtr { .Field = &node.rhs } });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;
989 continue;1265 continue;
990 },1266 },
991 else => {1267 else => {
992 self.putBackToken(token);1268 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 } });
993 continue;1272 continue;
994 },1273 }
995 }1274 }
996 },1275 },
9971276 State.ComptimeStatement => |ctx| {
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| {
1005 const token = self.getNextToken();1277 const token = self.getNextToken();
1006 switch (token.id) {1278 switch (token.id) {
1007 Token.Id.Keyword_and => {1279 Token.Id.Keyword_var, Token.Id.Keyword_const => {
1008 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BoolAnd);1280 stack.append(State {
1009 node.lhs = dest_ptr.get();1281 .VarDecl = VarDeclCtx {
1010 dest_ptr.store(&node.base);1282 .visib_token = null,
10111283 .comptime_token = ctx.comptime_token,
1012 stack.append(State { .BoolAndExpressionEnd = dest_ptr }) catch unreachable;1284 .extern_export_token = null,
1013 try stack.append(State { .ComparisonExpressionBegin = DestPtr { .Field = &node.rhs } });1285 .lib_name = null,
1286 .mut_token = token,
1287 .list = &ctx.block.statements,
1288 }
1289 }) catch unreachable;
1014 continue;1290 continue;
1015 },1291 },
1016 else => {1292 else => {
1017 self.putBackToken(token);1293 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 } });
1018 continue;1298 continue;
1019 },1299 }
1020 }1300 }
1021 },1301 },
10221302 State.Semicolon => |node_ptr| {
1023 State.ComparisonExpressionBegin => |dest_ptr| {1303 const node = *node_ptr;
1024 stack.append(State { .ComparisonExpressionEnd = dest_ptr }) catch unreachable;1304 if (requireSemiColon(node)) {
1025 try stack.append(State { .BinaryOrExpressionBegin = dest_ptr });1305 stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable;
1306 continue;
1307 }
1026 continue;1308 continue;
1027 },1309 },
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;1312 State.AsmOutputItems => |items| {
1037 try stack.append(State { .BinaryOrExpressionBegin = DestPtr { .Field = &node.rhs } });1313 const lbracket = self.getNextToken();
1038 continue;1314 if (lbracket.id != Token.Id.LBracket) {
1039 } else {1315 self.putBackToken(lbracket);
1040 self.putBackToken(token);
1041 continue;1316 continue;
1042 }1317 }
1043 },
10441318
1045 State.BinaryOrExpressionBegin => |dest_ptr| {1319 const node = try self.createNode(arena, ast.NodeAsmOutput,
1046 stack.append(State { .BinaryOrExpressionEnd = dest_ptr }) catch unreachable;1320 ast.NodeAsmOutput {
1047 try stack.append(State { .BinaryXorExpressionBegin = dest_ptr });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 } });
1048 continue;1337 continue;
1049 },1338 },
10501339 State.AsmOutputReturnOrType => |node| {
1051 State.BinaryOrExpressionEnd => |dest_ptr| {
1052 const token = self.getNextToken();1340 const token = self.getNextToken();
1053 switch (token.id) {1341 switch (token.id) {
1054 Token.Id.Pipe => {1342 Token.Id.Identifier => {
1055 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BitOr);1343 node.kind = ast.NodeAsmOutput.Kind { .Variable = try self.createLiteral(arena, ast.NodeIdentifier, token) };
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 } });
1061 continue;1344 continue;
1062 },1345 },
1063 else => {1346 Token.Id.Arrow => {
1064 self.putBackToken(token);1347 node.kind = ast.NodeAsmOutput.Kind { .Return = undefined };
1348 try stack.append(State { .TypeExprBegin = OptionalCtx { .Required = &node.kind.Return } });
1065 continue;1349 continue;
1066 },1350 },
1351 else => {
1352 return self.parseError(token, "expected '->' or {}, found {}",
1353 @tagName(Token.Id.Identifier),
1354 @tagName(token.id));
1355 },
1067 }1356 }
1068 },1357 },
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| {1365 const node = try self.createNode(arena, ast.NodeAsmInput,
1071 stack.append(State { .BinaryXorExpressionEnd = dest_ptr }) catch unreachable;1366 ast.NodeAsmInput {
1072 try stack.append(State { .BinaryAndExpressionBegin = dest_ptr });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() } });
1073 continue;1389 continue;
1074 },1390 },
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;1393 State.ExprListItemOrEnd => |list_state| {
1085 try stack.append(State { .BinaryAndExpressionBegin = DestPtr { .Field = &node.rhs } });1394 if (self.eatToken(list_state.end)) |token| {
1086 continue;1395 *list_state.ptr = token;
1087 },1396 continue;
1088 else => {
1089 self.putBackToken(token);
1090 continue;
1091 },
1092 }1397 }
1093 },
10941398
1095 State.BinaryAndExpressionBegin => |dest_ptr| {1399 stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable;
1096 stack.append(State { .BinaryAndExpressionEnd = dest_ptr }) catch unreachable;1400 try stack.append(State { .Expression = OptionalCtx { .Required = try list_state.list.addOne() } });
1097 try stack.append(State { .BitShiftExpressionBegin = dest_ptr });
1098 continue;1401 continue;
1099 },1402 },
11001403 State.ExprListCommaOrEnd => |list_state| {
1101 State.BinaryAndExpressionEnd => |dest_ptr| {1404 if (try self.expectCommaOrEnd(list_state.end)) |end| {
1102 const token = self.getNextToken();1405 *list_state.ptr = end;
1103 switch (token.id) {1406 continue;
1104 Token.Id.Ampersand => {1407 } else {
1105 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.BitAnd);1408 stack.append(State { .ExprListItemOrEnd = list_state }) catch unreachable;
1106 node.lhs = dest_ptr.get();1409 continue;
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 },
1117 }1410 }
1118 },1411 },
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| {1428 stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
1121 stack.append(State { .BitShiftExpressionEnd = dest_ptr }) catch unreachable;1429 try stack.append(State { .Expression = OptionalCtx{ .Required = &node.expr } });
1122 try stack.append(State { .AdditionExpressionBegin = dest_ptr });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 });
1123 continue;1443 continue;
1124 },1444 },
11251445 State.FieldInitListCommaOrEnd => |list_state| {
1126 State.BitShiftExpressionEnd => |dest_ptr| {1446 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1127 const token = self.getNextToken();1447 *list_state.ptr = end;
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 } });
1135 continue;1448 continue;
1136 } else {1449 } 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;
1138 continue;1460 continue;
1139 }1461 }
1140 },1462 },
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| {1469 stack.append(State { .IdentifierListCommaOrEnd = list_state }) catch unreachable;
1143 stack.append(State { .AdditionExpressionEnd = dest_ptr }) catch unreachable;1470 try stack.append(State { .Identifier = OptionalCtx { .Required = try list_state.list.addOne() } });
1144 try stack.append(State { .MultiplyExpressionBegin = dest_ptr });
1145 continue;1471 continue;
1146 },1472 },
11471473 State.IdentifierListCommaOrEnd => |list_state| {
1148 State.AdditionExpressionEnd => |dest_ptr| {1474 if (try self.expectCommaOrEnd(Token.Id.RBrace)) |end| {
1149 const token = self.getNextToken();1475 *list_state.ptr = end;
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 } });
1157 continue;1476 continue;
1158 } else {1477 } else {
1159 self.putBackToken(token);1478 stack.append(State { .IdentifierListItemOrEnd = list_state }) catch unreachable;
1160 continue;1479 continue;
1161 }1480 }
1162 },1481 },
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| {1488 const node = try self.createNode(arena, ast.NodeSwitchCase,
1165 stack.append(State { .MultiplyExpressionEnd = dest_ptr }) catch unreachable;1489 ast.NodeSwitchCase {
1166 try stack.append(State { .CurlySuffixExpressionBegin = dest_ptr });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 });
1167 continue;1501 continue;
1168 },1502 },
11691503 State.SwitchCaseCommaOrEnd => |list_state| {
1170 State.MultiplyExpressionEnd => |dest_ptr| {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| {
1171 const token = self.getNextToken();1513 const token = self.getNextToken();
1172 if (tokenIdToMultiply(token.id)) |mult_id| {1514 if (token.id == Token.Id.Keyword_else) {
1173 const node = try self.createInfixOp(arena, token, mult_id);1515 const else_node = try self.createAttachNode(arena, case_items, ast.NodeSwitchElse,
1174 node.lhs = dest_ptr.get();1516 ast.NodeSwitchElse {
1175 dest_ptr.store(&node.base);1517 .base = undefined,
11761518 .token = token,
1177 stack.append(State { .MultiplyExpressionEnd = dest_ptr }) catch unreachable;1519 }
1178 try stack.append(State { .CurlySuffixExpressionBegin = DestPtr { .Field = &node.rhs } });1520 );
1521 try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
1179 continue;1522 continue;
1180 } else {1523 } else {
1181 self.putBackToken(token);1524 self.putBackToken(token);
1525 try stack.append(State { .SwitchCaseItem = case_items });
1182 continue;1526 continue;
1183 }1527 }
1184 },1528 },
11851529 State.SwitchCaseItem => |case_items| {
1186 State.CurlySuffixExpressionBegin => |dest_ptr| {1530 stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
1187 stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;1531 try stack.append(State { .RangeExpressionBegin = OptionalCtx { .Required = try case_items.addOne() } });
1188 try stack.append(State { .TypeExprBegin = dest_ptr });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 }
1189 continue;1537 continue;
1190 },1538 },
11911539
1192 State.CurlySuffixExpressionEnd => |dest_ptr| {1540
1193 const token = self.getNextToken();1541 State.SuspendBody => |suspend_node| {
1194 if (token.id != Token.Id.LBrace) {1542 if (suspend_node.payload != null) {
1195 self.putBackToken(token);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) {
1196 continue;1549 continue;
1197 }1550 }
11981551
1199 const next = self.getNextToken();1552 async_node.rangle_bracket = Token(undefined);
1200 switch (next.id) {1553 try stack.append(State {
1201 Token.Id.Period => {1554 .ExpectTokenSave = ExpectTokenSave {
1202 const node = try self.createSuffixOp(arena, ast.NodeSuffixOp.SuffixOp {1555 .id = Token.Id.AngleBracketRight,
1203 .StructInitializer = ArrayList(&ast.NodeFieldInitializer).init(arena),1556 .ptr = &??async_node.rangle_bracket,
1204 });1557 }
1205 node.lhs = dest_ptr.get();1558 });
1206 dest_ptr.store(&node.base);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;1565 switch (node.id) {
1209 try stack.append(State {1566 ast.Node.Id.FnProto => {
1210 .FieldInitListItemOrEnd = ListSave(&ast.NodeFieldInitializer) {1567 const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", node);
1211 .list = &node.op.StructInitializer,1568 fn_proto.async_attr = ctx.attribute;
1212 .ptr = &node.rtoken,
1213 }
1214 });
1215 self.putBackToken(next);
1216 continue;1569 continue;
1217 },1570 },
1218 else => {1571 ast.Node.Id.SuffixOp => {
1219 const node = try self.createSuffixOp(arena, ast.NodeSuffixOp.SuffixOp {1572 const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", node);
1220 .ArrayInitializer = ArrayList(&ast.Node).init(arena),1573 if (suffix_op.op == ast.NodeSuffixOp.SuffixOp.Call) {
1221 });1574 suffix_op.op.Call.async_attr = ctx.attribute;
1222 node.lhs = dest_ptr.get();1575 continue;
1223 dest_ptr.store(&node.base);1576 }
12241577
1225 stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;1578 return self.parseError(node.firstToken(), "expected {}, found {}.",
1226 try stack.append(State {1579 @tagName(ast.NodeSuffixOp.SuffixOp.Call),
1227 .ExprListItemOrEnd = ExprListCtx {1580 @tagName(suffix_op.op));
1228 .list = &node.op.ArrayInitializer,
1229 .end = Token.Id.RBrace,
1230 .ptr = &node.rtoken,
1231 }
1232 });
1233 self.putBackToken(next);
1234 continue;
1235 },1581 },
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 }
1236 }1588 }
1237 },1589 },
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| {1592 State.ExternType => |ctx| {
1246 const token = self.getNextToken();1593 if (self.eatToken(Token.Id.Keyword_fn)) |fn_token| {
1247 switch (token.id) {1594 const fn_proto = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeFnProto,
1248 Token.Id.Bang => {1595 ast.NodeFnProto {
1249 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.ErrorUnion);1596 .base = undefined,
1250 node.lhs = dest_ptr.get();1597 .visib_token = null,
1251 dest_ptr.store(&node.base);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;1615 stack.append(State {
1254 try stack.append(State { .PrefixOpExpression = DestPtr { .Field = &node.rhs } });1616 .ContainerKind = ContainerKindCtx {
1255 continue;1617 .opt_ctx = ctx.opt_ctx,
1256 },1618 .ltoken = ctx.extern_token,
1257 else => {1619 .layout = ast.NodeContainerDecl.Layout.Extern,
1258 self.putBackToken(token);
1259 continue;
1260 },1620 },
1261 }1621 }) catch unreachable;
1622 continue;
1262 },1623 },
12631624 State.SliceOrArrayAccess => |node| {
1264 State.PrefixOpExpression => |dest_ptr| {1625 var token = self.getNextToken();
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();
1284 switch (token.id) {1626 switch (token.id) {
1285 Token.Id.Keyword_async => {1627 Token.Id.Ellipsis2 => {
1286 const async_node = try arena.create(ast.NodeAsyncAttribute);1628 const start = node.op.ArrayAccess;
1287 *async_node = ast.NodeAsyncAttribute {1629 node.op = ast.NodeSuffixOp.SuffixOp {
1288 .base = self.initNode(ast.Node.Id.AsyncAttribute),1630 .Slice = ast.NodeSuffixOp.SliceRange {
1289 .async_token = token,1631 .start = start,
1290 .allocator_type = null,1632 .end = null,
1291 .rangle_bracket = null,1633 }
1292 };1634 };
12931635
1294 stack.append(State {1636 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 {
1311 .ExpectTokenSave = ExpectTokenSave {1637 .ExpectTokenSave = ExpectTokenSave {
1312 .id = Token.Id.AngleBracketRight,1638 .id = Token.Id.RBracket,
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,
1346 .ptr = &node.rtoken,1639 .ptr = &node.rtoken,
1347 }1640 }
1348 });1641 }) catch unreachable;
1349 continue;1642 try stack.append(State { .Expression = OptionalCtx { .Optional = &node.op.Slice.end } });
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 }});
1367 continue;1643 continue;
1368 },1644 },
1369 Token.Id.Period => {1645 Token.Id.RBracket => {
1370 const node = try self.createInfixOp(arena, token, ast.NodeInfixOp.InfixOp.Period);1646 node.rtoken = token;
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 }});
1376 continue;1647 continue;
1377 },1648 },
1378 else => {1649 else => {
1379 self.putBackToken(token);1650 return self.parseError(token, "expected ']' or '..', found {}", @tagName(token.id));
1380 continue;1651 }
1381 },
1382 }1652 }
1383 },1653 },
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| {1670 node.op = ast.NodePrefixOp.PrefixOp { .ArrayType = undefined };
1386 const token = self.getNextToken();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();
1387 switch (token.id) {1678 switch (token.id) {
1388 Token.Id.IntegerLiteral => {1679 Token.Id.Keyword_align => {
1389 dest_ptr.store(&(try self.createIntegerLiteral(arena, token)).base);1680 stack.append(state) catch unreachable;
1390 continue;1681 if (addr_of_info.align_expr != null) {
1391 },1682 return self.parseError(token, "multiple align qualifiers");
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);
1474 }1683 }
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 });
1475 continue;1687 continue;
1476 },1688 },
1477 Token.Id.LParen => {1689 Token.Id.Keyword_const => {
1478 const node = try arena.create(ast.NodeGroupedExpression);1690 stack.append(state) catch unreachable;
1479 *node = ast.NodeGroupedExpression {1691 if (addr_of_info.const_token != null) {
1480 .base = self.initNode(ast.Node.Id.GroupedExpression),1692 return self.parseError(token, "duplicate qualifier: const");
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 }
1602 }1693 }
1694 addr_of_info.const_token = token;
1603 continue;1695 continue;
1604 },1696 },
1605 Token.Id.Keyword_packed => {1697 Token.Id.Keyword_volatile => {
1606 stack.append(State {1698 stack.append(state) catch unreachable;
1607 .ContainerExtern = ContainerExternCtx {1699 if (addr_of_info.volatile_token != null) {
1608 .dest_ptr = dest_ptr,1700 return self.parseError(token, "duplicate qualifier: volatile");
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;
1650 }1701 }
16511702 addr_of_info.volatile_token = token;
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;
1725 continue;1703 continue;
1726 },1704 },
1727 else => {1705 else => {
1728 try self.parseError(&stack, token, "expected primary expression, found {}", @tagName(token.id));1706 self.putBackToken(token);
1729 continue;1707 continue;
1730 }1708 },
1731 }1709 }
1732 },1710 },
17331711
1734 State.SliceOrArrayAccess => |node| {
1735 var token = self.getNextToken();
17361712
1737 switch (token.id) {1713 State.Payload => |opt_ctx| {
1738 Token.Id.Ellipsis2 => {1714 const token = self.getNextToken();
1739 const start = node.op.ArrayAccess;1715 if (token.id != Token.Id.Pipe) {
1740 node.op = ast.NodeSuffixOp.SuffixOp {1716 if (opt_ctx != OptionalCtx.Optional) {
1741 .Slice = ast.NodeSuffixOp.SliceRange {1717 return self.parseError(token, "expected {}, found {}.",
1742 .start = start,1718 @tagName(Token.Id.Pipe),
1743 .end = undefined,1719 @tagName(token.id));
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;
1769 }1720 }
1770 }
1771 },
17721721
17731722 self.putBackToken(token);
1774 State.AsmOutputItems => |items| {
1775 const lbracket = self.getNextToken();
1776 if (lbracket.id != Token.Id.LBracket) {
1777 self.putBackToken(lbracket);
1778 continue;1723 continue;
1779 }1724 }
17801725
1781 stack.append(State { .AsmOutputItems = items }) catch unreachable;1726 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePayload,
1782 try stack.append(State { .IfToken = Token.Id.Comma });1727 ast.NodePayload {
17831728 .base = undefined,
1784 const symbolic_name = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;1729 .lpipe = token,
1785 _ = (try self.eatToken(&stack, Token.Id.RBracket)) ?? continue;1730 .error_symbol = undefined,
1786 const constraint = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue;1731 .rpipe = undefined
17871732 }
1788 _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue;1733 );
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);
17991734
1800 const symbol_or_arrow = self.getNextToken();1735 stack.append(State {
1801 switch (symbol_or_arrow.id) {1736 .ExpectTokenSave = ExpectTokenSave {
1802 Token.Id.Identifier => {1737 .id = Token.Id.Pipe,
1803 node.kind = ast.NodeAsmOutput.Kind { .Variable = try self.createIdentifier(arena, symbol_or_arrow) };1738 .ptr = &node.rpipe,
1804 },1739 }
1805 Token.Id.Arrow => {1740 }) catch unreachable;
1806 node.kind = ast.NodeAsmOutput.Kind { .Return = undefined };1741 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.error_symbol } });
1807 try stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.kind.Return } });1742 continue;
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 }
1816 },1743 },
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| {1753 self.putBackToken(token);
1819 const lbracket = self.getNextToken();
1820 if (lbracket.id != Token.Id.LBracket) {
1821 self.putBackToken(lbracket);
1822 continue;1754 continue;
1823 }1755 }
18241756
1825 stack.append(State { .AsmInputItems = items }) catch unreachable;1757 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePointerPayload,
1826 try stack.append(State { .IfToken = Token.Id.Comma });1758 ast.NodePointerPayload {
18271759 .base = undefined,
1828 const symbolic_name = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;1760 .lpipe = token,
1829 _ = (try self.eatToken(&stack, Token.Id.RBracket)) ?? continue;1761 .ptr_token = null,
1830 const constraint = (try self.eatToken(&stack, Token.Id.StringLiteral)) ?? continue;1762 .value_symbol = undefined,
18311763 .rpipe = undefined
1832 _ = (try self.eatToken(&stack, Token.Id.LParen)) ?? continue;1764 }
1833 try stack.append(State { .ExpectToken = Token.Id.RParen });1765 );
18341766
1835 const node = try arena.create(ast.NodeAsmInput);1767 stack.append(State {
1836 *node = ast.NodeAsmInput {1768 .ExpectTokenSave = ExpectTokenSave {
1837 .base = self.initNode(ast.Node.Id.AsmInput),1769 .id = Token.Id.Pipe,
1838 .symbolic_name = try self.createIdentifier(arena, symbolic_name),1770 .ptr = &node.rpipe,
1839 .constraint = try self.createStringLiteral(arena, constraint),1771 }
1840 .expr = undefined,1772 }) catch unreachable;
1841 };1773 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.value_symbol } });
1842 try items.append(node);1774 try stack.append(State {
1843 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });1775 .OptionalTokenSave = OptionalTokenSave {
1776 .id = Token.Id.Asterisk,
1777 .ptr = &node.ptr_token,
1778 }
1779 });
1780 continue;
1844 },1781 },
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| {1791 self.putBackToken(token);
1847 const string = self.getNextToken();
1848 if (string.id != Token.Id.StringLiteral) {
1849 self.putBackToken(string);
1850 continue;1792 continue;
1851 }1793 }
18521794
1853 try items.append(try self.createStringLiteral(arena, string));1795 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodePointerIndexPayload,
1854 stack.append(State { .AsmClopperItems = items }) catch unreachable;1796 ast.NodePointerIndexPayload {
1855 try stack.append(State { .IfToken = Token.Id.Comma });1797 .base = undefined,
1856 },1798 .lpipe = token,
18571799 .ptr_token = null,
1858 State.ExprListItemOrEnd => |list_state| {1800 .value_symbol = undefined,
1859 var token = self.getNextToken();1801 .index_symbol = null,
18601802 .rpipe = undefined
1861 const IdTag = @TagType(Token.Id);1803 }
1862 if (IdTag(list_state.end) == token.id) {1804 );
1863 *list_state.ptr = token;
1864 continue;
1865 }
18661805
1867 self.putBackToken(token);1806 stack.append(State {
1868 stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable;1807 .ExpectTokenSave = ExpectTokenSave {
1869 try stack.append(State { .Expression = DestPtr{ .Field = try list_state.list.addOne() } });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;
1870 },1822 },
18711823
1872 State.FieldInitListItemOrEnd => |list_state| {
1873 var token = self.getNextToken();
18741824
1875 if (token.id == Token.Id.RBrace){1825 State.Expression => |opt_ctx| {
1876 *list_state.ptr = token;1826 const token = self.getNextToken();
1877 continue;1827 switch (token.id) {
1878 }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);1840 switch (token.id) {
1883 *node = ast.NodeFieldInitializer {1841 Token.Id.Keyword_break => {
1884 .base = self.initNode(ast.Node.Id.FieldInitializer),1842 node.kind = ast.NodeControlFlowExpression.Kind { .Break = null };
1885 .period_token = undefined,1843 try stack.append(State { .Identifier = OptionalCtx { .RequiredNull = &node.kind.Break } });
1886 .name_token = undefined,1844 try stack.append(State { .IfToken = Token.Id.Colon });
1887 .expr = undefined,1845 },
1888 };1846 Token.Id.Keyword_continue => {
1889 try list_state.list.append(node);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;1873 stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable;
1892 try stack.append(State { .Expression = DestPtr{.Field = &node.expr} });1874 continue;
1893 try stack.append(State { .ExpectToken = Token.Id.Equal });1875 },
1894 try stack.append(State {1876 else => {
1895 .ExpectTokenSave = ExpectTokenSave {1877 if (!try self.parseBlockExpr(&stack, arena, opt_ctx, token)) {
1896 .id = Token.Id.Identifier,1878 self.putBackToken(token);
1897 .ptr = &node.name_token,1879 stack.append(State { .UnwrapExpressionBegin = opt_ctx }) catch unreachable;
1898 }1880 }
1899 });1881 continue;
1900 try stack.append(State {
1901 .ExpectTokenSave = ExpectTokenSave {
1902 .id = Token.Id.Period,
1903 .ptr = &node.period_token,
1904 }1882 }
1905 });1883 }
1906 },1884 },
19071885 State.RangeExpressionBegin => |opt_ctx| {
1908 State.SwitchCaseOrEnd => |list_state| {1886 stack.append(State { .RangeExpressionEnd = opt_ctx }) catch unreachable;
1909 var token = self.getNextToken();1887 try stack.append(State { .Expression = opt_ctx });
19101888 continue;
1911 if (token.id == Token.Id.RBrace){1889 },
1912 *list_state.ptr = token;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;
1913 continue;1904 continue;
1914 }1905 }
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);1916 const token = self.getNextToken();
1919 *node = ast.NodeSwitchCase {1917 if (tokenIdToAssignment(token.id)) |ass_id| {
1920 .base = self.initNode(ast.Node.Id.SwitchCase),1918 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
1921 .items = ArrayList(&ast.Node).init(arena),1919 ast.NodeInfixOp {
1922 .payload = null,1920 .base = undefined,
1923 .expr = undefined,1921 .lhs = lhs,
1924 };1922 .op_token = token,
1925 try list_state.list.append(node);1923 .op = ass_id,
1926 stack.append(State { .SwitchCaseCommaOrEnd = list_state }) catch unreachable;1924 .rhs = undefined,
1927 try stack.append(State { .Expression = DestPtr{ .Field = &node.expr } });1925 }
1928 try stack.append(State { .PointerPayload = &node.payload });1926 );
19291927 stack.append(State { .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1930 const maybe_else = self.getNextToken();1928 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
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 });
1939 continue;1929 continue;
1940 } else {1930 } else {
1941 self.putBackToken(maybe_else);1931 self.putBackToken(token);
1942 try stack.append(State { .SwitchCaseItem = &node.items });
1943 continue;1932 continue;
1944 }1933 }
1945 },1934 },
19461935
1947 State.SwitchCaseItem => |case_items| {1936 State.UnwrapExpressionBegin => |opt_ctx| {
1948 stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;1937 stack.append(State { .UnwrapExpressionEnd = opt_ctx }) catch unreachable;
1949 try stack.append(State { .RangeExpressionBegin = DestPtr{ .Field = try case_items.addOne() } });1938 try stack.append(State { .BoolOrExpressionBegin = opt_ctx });
1950 },
1951
1952 State.ExprListCommaOrEnd => |list_state| {
1953 try self.commaOrEnd(&stack, list_state.end, list_state.ptr, State { .ExprListItemOrEnd = list_state });
1954 continue;1939 continue;
1955 },1940 },
19561941
1957 State.FieldInitListCommaOrEnd => |list_state| {1942 State.UnwrapExpressionEnd => |opt_ctx| {
1958 try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .FieldInitListItemOrEnd = list_state });1943 const lhs = opt_ctx.get() ?? continue;
1959 continue;
1960 },
19611944
1962 State.FieldListCommaOrEnd => |container_decl| {1945 const token = self.getNextToken();
1963 try self.commaOrEnd(&stack, Token.Id.RBrace, &container_decl.rbrace_token,1946 if (tokenIdToUnwrapExpr(token.id)) |unwrap_id| {
1964 State { .ContainerDecl = container_decl });1947 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
1965 continue;1948 ast.NodeInfixOp {
1966 },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| {1957 stack.append(State { .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
1969 try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .SwitchCaseOrEnd = list_state });1958 try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } });
1970 continue;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 }
1971 },1968 },
19721969
1973 State.SwitchCaseItemCommaOrEnd => |case_items| {1970 State.BoolOrExpressionBegin => |opt_ctx| {
1974 try self.commaOrEnd(&stack, Token.Id.EqualAngleBracketRight, null, State { .SwitchCaseItem = case_items });1971 stack.append(State { .BoolOrExpressionEnd = opt_ctx }) catch unreachable;
1972 try stack.append(State { .BoolAndExpressionBegin = opt_ctx });
1975 continue;1973 continue;
1976 },1974 },
19771975
1978 State.Else => |dest| {1976 State.BoolOrExpressionEnd => |opt_ctx| {
1979 const else_token = self.getNextToken();1977 const lhs = opt_ctx.get() ?? continue;
1980 if (else_token.id != Token.Id.Keyword_else) {1978
1981 self.putBackToken(else_token);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 } });
1982 continue;1991 continue;
1983 }1992 }
1993 },
19841994
1985 const node = try arena.create(ast.NodeElse);1995 State.BoolAndExpressionBegin => |opt_ctx| {
1986 *node = ast.NodeElse {1996 stack.append(State { .BoolAndExpressionEnd = opt_ctx }) catch unreachable;
1987 .base = self.initNode(ast.Node.Id.Else),1997 try stack.append(State { .ComparisonExpressionBegin = opt_ctx });
1988 .else_token = else_token,1998 continue;
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 });
1996 },1999 },
19972000
1998 State.WhileContinueExpr => |dest| {2001 State.BoolAndExpressionEnd => |opt_ctx| {
1999 const colon = self.getNextToken();2002 const lhs = opt_ctx.get() ?? continue;
2000 if (colon.id != Token.Id.Colon) {2003
2001 self.putBackToken(colon);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 } });
2002 continue;2016 continue;
2003 }2017 }
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 } });
2008 },2018 },
20092019
2010 State.SuspendBody => |suspend_node| {2020 State.ComparisonExpressionBegin => |opt_ctx| {
2011 if (suspend_node.payload != null) {2021 stack.append(State { .ComparisonExpressionEnd = opt_ctx }) catch unreachable;
2012 try stack.append(State { .AssignmentExpressionBegin = DestPtr { .NullableField = &suspend_node.body } });2022 try stack.append(State { .BinaryOrExpressionBegin = opt_ctx });
2013 }
2014 continue;2023 continue;
2015 },2024 },
20162025
2017 State.AsyncEnd => |ctx| {2026 State.ComparisonExpressionEnd => |opt_ctx| {
2018 const node = ctx.dest_ptr.get();2027 const lhs = opt_ctx.get() ?? continue;
20192028
2020 switch (node.id) {2029 const token = self.getNextToken();
2021 ast.Node.Id.FnProto => {2030 if (tokenIdToComparison(token.id)) |comp_id| {
2022 const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", node);2031 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2023 fn_proto.async_attr = ctx.attribute;2032 ast.NodeInfixOp {
2024 },2033 .base = undefined,
2025 ast.Node.Id.SuffixOp => {2034 .lhs = lhs,
2026 const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", node);2035 .op_token = token,
2027 if (suffix_op.op == ast.NodeSuffixOp.SuffixOp.Call) {2036 .op = comp_id,
2028 suffix_op.op.Call.async_attr = ctx.attribute;2037 .rhs = undefined,
2029 continue;
2030 }2038 }
20312039 );
2032 try self.parseError(&stack, node.firstToken(), "expected call or fn proto, found {}.",2040 stack.append(State { .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2033 @tagName(suffix_op.op));2041 try stack.append(State { .BinaryOrExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2034 continue;2042 continue;
2035 },2043 } else {
2036 else => {2044 self.putBackToken(token);
2037 try self.parseError(&stack, node.firstToken(), "expected call or fn proto, found {}.",2045 continue;
2038 @tagName(node.id));
2039 continue;
2040 }
2041 }2046 }
2042 },2047 },
20432048
2044 State.Payload => |dest| {2049 State.BinaryOrExpressionBegin => |opt_ctx| {
2045 const lpipe = self.getNextToken();2050 stack.append(State { .BinaryOrExpressionEnd = opt_ctx }) catch unreachable;
2046 if (lpipe.id != Token.Id.Pipe) {2051 try stack.append(State { .BinaryXorExpressionBegin = opt_ctx });
2047 self.putBackToken(lpipe);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 } });
2048 continue;2070 continue;
2049 }2071 }
2072 },
20502073
2051 const error_symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;2074 State.BinaryXorExpressionBegin => |opt_ctx| {
2052 const rpipe = (try self.eatToken(&stack, Token.Id.Pipe)) ?? continue;2075 stack.append(State { .BinaryXorExpressionEnd = opt_ctx }) catch unreachable;
2053 const node = try arena.create(ast.NodePayload);2076 try stack.append(State { .BinaryAndExpressionBegin = opt_ctx });
2054 *node = ast.NodePayload {2077 continue;
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;
2061 },2078 },
20622079
2063 State.PointerPayload => |dest| {2080 State.BinaryXorExpressionEnd => |opt_ctx| {
2064 const lpipe = self.getNextToken();2081 const lhs = opt_ctx.get() ?? continue;
2065 if (lpipe.id != Token.Id.Pipe) {2082
2066 self.putBackToken(lpipe);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 } });
2067 continue;2095 continue;
2068 }2096 }
2097 },
20692098
2070 const is_ptr = blk: {2099 State.BinaryAndExpressionBegin => |opt_ctx| {
2071 const asterik = self.getNextToken();2100 stack.append(State { .BinaryAndExpressionEnd = opt_ctx }) catch unreachable;
2072 if (asterik.id == Token.Id.Asterisk) {2101 try stack.append(State { .BitShiftExpressionBegin = opt_ctx });
2073 break :blk true;2102 continue;
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;
2091 },2103 },
20922104
2093 State.PointerIndexPayload => |dest| {2105 State.BinaryAndExpressionEnd => |opt_ctx| {
2094 const lpipe = self.getNextToken();2106 const lhs = opt_ctx.get() ?? continue;
2095 if (lpipe.id != Token.Id.Pipe) {2107
2096 self.putBackToken(lpipe);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 } });
2097 continue;2120 continue;
2098 }2121 }
2122 },
20992123
2100 const is_ptr = blk: {2124 State.BitShiftExpressionBegin => |opt_ctx| {
2101 const asterik = self.getNextToken();2125 stack.append(State { .BitShiftExpressionEnd = opt_ctx }) catch unreachable;
2102 if (asterik.id == Token.Id.Asterisk) {2126 try stack.append(State { .AdditionExpressionBegin = opt_ctx });
2103 break :blk true;2127 continue;
2104 } else {2128 },
2105 self.putBackToken(asterik);
2106 break :blk false;
2107 }
2108 };
21092129
2110 const value_symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;2130 State.BitShiftExpressionEnd => |opt_ctx| {
2111 const index_symbol = blk: {2131 const lhs = opt_ctx.get() ?? continue;
2112 const comma = self.getNextToken();
2113 if (comma.id != Token.Id.Comma) {
2114 self.putBackToken(comma);
2115 break :blk null;
2116 }
21172132
2118 const symbol = (try self.eatToken(&stack, Token.Id.Identifier)) ?? continue;2133 const token = self.getNextToken();
2119 break :blk try self.createIdentifier(arena, symbol);2134 if (tokenIdToBitShift(token.id)) |bitshift_id| {
2120 };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;2153 State.AdditionExpressionBegin => |opt_ctx| {
2123 const node = try arena.create(ast.NodePointerIndexPayload);2154 stack.append(State { .AdditionExpressionEnd = opt_ctx }) catch unreachable;
2124 *node = ast.NodePointerIndexPayload {2155 try stack.append(State { .MultiplyExpressionBegin = opt_ctx });
2125 .base = self.initNode(ast.Node.Id.PointerIndexPayload),2156 continue;
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;
2133 },2157 },
21342158
2135 State.AddrOfModifiers => |addr_of_info| {2159 State.AdditionExpressionEnd => |opt_ctx| {
2136 var token = self.getNextToken();2160 const lhs = opt_ctx.get() ?? continue;
2137 switch (token.id) {2161
2138 Token.Id.Keyword_align => {2162 const token = self.getNextToken();
2139 stack.append(state) catch unreachable;2163 if (tokenIdToAddition(token.id)) |add_id| {
2140 if (addr_of_info.align_expr != null) {2164 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
2141 try self.parseError(&stack, token, "multiple align qualifiers");2165 ast.NodeInfixOp {
2142 continue;2166 .base = undefined,
2143 }2167 .lhs = lhs,
2144 try stack.append(State { .ExpectToken = Token.Id.RParen });2168 .op_token = token,
2145 try stack.append(State { .Expression = DestPtr{.NullableField = &addr_of_info.align_expr} });2169 .op = add_id,
2146 try stack.append(State { .ExpectToken = Token.Id.LParen });2170 .rhs = undefined,
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;
2163 }2171 }
2164 addr_of_info.volatile_token = token;2172 );
2165 continue;2173 stack.append(State { .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2166 },2174 try stack.append(State { .MultiplyExpressionBegin = OptionalCtx { .Required = &node.rhs } });
2167 else => {2175 continue;
2168 self.putBackToken(token);2176 } else {
2169 continue;2177 self.putBackToken(token);
2170 },2178 continue;
2171 }2179 }
2172 },2180 },
21732181
2174 State.FnProto => |fn_proto| {2182 State.MultiplyExpressionBegin => |opt_ctx| {
2175 stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable;2183 stack.append(State { .MultiplyExpressionEnd = opt_ctx }) catch unreachable;
2176 try stack.append(State { .ParamDecl = fn_proto });2184 try stack.append(State { .CurlySuffixExpressionBegin = opt_ctx });
2177 try stack.append(State { .ExpectToken = Token.Id.LParen });2185 continue;
2186 },
21782187
2179 const next_token = self.getNextToken();2188 State.MultiplyExpressionEnd => |opt_ctx| {
2180 if (next_token.id == Token.Id.Identifier) {2189 const lhs = opt_ctx.get() ?? continue;
2181 fn_proto.name_token = next_token;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);
2182 continue;2207 continue;
2183 }2208 }
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 });
2185 continue;2215 continue;
2186 },2216 },
21872217
2188 State.FnProtoAlign => |fn_proto| {2218 State.CurlySuffixExpressionEnd => |opt_ctx| {
2189 const token = self.getNextToken();2219 const lhs = opt_ctx.get() ?? continue;
2190 if (token.id == Token.Id.Keyword_align) {2220
2191 @panic("TODO fn proto align");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;
2192 }2241 }
2193 self.putBackToken(token);2242
2194 stack.append(State {2243 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeSuffixOp,
2195 .FnProtoReturnType = fn_proto,2244 ast.NodeSuffixOp {
2196 }) catch unreachable;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 });
2197 continue;2262 continue;
2198 },2263 },
21992264
2200 State.FnProtoReturnType => |fn_proto| {2265 State.TypeExprBegin => |opt_ctx| {
2201 const token = self.getNextToken();2266 stack.append(State { .TypeExprEnd = opt_ctx }) catch unreachable;
2202 switch (token.id) {2267 try stack.append(State { .PrefixOpExpression = opt_ctx });
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 }
2220 continue;2268 continue;
2221 },2269 },
22222270
2223 State.ParamDecl => |fn_proto| {2271 State.TypeExprEnd => |opt_ctx| {
2224 var token = self.getNextToken();2272 const lhs = opt_ctx.get() ?? continue;
2225 if (token.id == Token.Id.RParen) {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 } });
2226 continue;2286 continue;
2227 }2287 }
2228 const param_decl = try self.createAttachParamDecl(arena, &fn_proto.params);2288 },
2229 if (token.id == Token.Id.Keyword_comptime) {2289
2230 param_decl.comptime_token = token;2290 State.PrefixOpExpression => |opt_ctx| {
2231 token = self.getNextToken();2291 const token = self.getNextToken();
2232 } else if (token.id == Token.Id.Keyword_noalias) {2292 if (tokenIdToPrefixOp(token.id)) |prefix_id| {
2233 param_decl.noalias_token = token;2293 var node = try self.createToCtxNode(arena, opt_ctx, ast.NodePrefixOp,
2234 token = self.getNextToken();2294 ast.NodePrefixOp {
2235 }2295 .base = undefined,
2236 if (token.id == Token.Id.Identifier) {2296 .op_token = token,
2237 const next_token = self.getNextToken();2297 .op = prefix_id,
2238 if (next_token.id == Token.Id.Colon) {2298 .rhs = undefined,
2239 param_decl.name_token = token;2299 }
2240 token = self.getNextToken();2300 );
2241 } else {2301
2242 self.putBackToken(next_token);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 });
2243 }2319 }
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;
2248 continue;2320 continue;
2249 } else {2321 } else {
2250 self.putBackToken(token);2322 self.putBackToken(token);
2323 stack.append(State { .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;
2324 continue;
2251 }2325 }
2326 },
22522327
2253 stack.append(State { .ParamDecl = fn_proto }) catch unreachable;2328 State.SuffixOpExpressionBegin => |opt_ctx| {
2254 try stack.append(State.ParamDeclComma);2329 if (self.eatToken(Token.Id.Keyword_async)) |async_token| {
2255 try stack.append(State {2330 const async_node = try self.createNode(arena, ast.NodeAsyncAttribute,
2256 .TypeExprBegin = DestPtr {.Field = &param_decl.type_node}2331 ast.NodeAsyncAttribute {
2257 });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 });
2258 continue;2352 continue;
2259 },2353 },
22602354
2261 State.ParamDeclComma => {2355 State.SuffixOpExpressionEnd => |opt_ctx| {
2356 const lhs = opt_ctx.get() ?? continue;
2357
2262 const token = self.getNextToken();2358 const token = self.getNextToken();
2263 switch (token.id) {2359 switch (token.id) {
2264 Token.Id.RParen => {2360 Token.Id.LParen => {
2265 _ = stack.pop(); // pop off the ParamDecl2361 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 });
2266 continue;2382 continue;
2267 },2383 },
2268 Token.Id.Comma => continue,2384 Token.Id.LBracket => {
2269 else => {2385 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeSuffixOp,
2270 try self.parseError(&stack, token, "expected ',' or ')', found {}", @tagName(token.id));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 }});
2271 continue;2398 continue;
2272 },2399 },
2273 }2400 Token.Id.Period => {
2274 },2401 const node = try self.createToCtxNode(arena, opt_ctx, ast.NodeInfixOp,
22752402 ast.NodeInfixOp {
2276 State.FnDef => |fn_proto| {2403 .base = undefined,
2277 const token = self.getNextToken();2404 .lhs = lhs,
2278 switch(token.id) {2405 .op_token = token,
2279 Token.Id.LBrace => {2406 .op = ast.NodeInfixOp.InfixOp.Period,
2280 const block = try self.createBlock(arena, (?Token)(null), token);2407 .rhs = undefined,
2281 fn_proto.body_node = &block.base;2408 }
2282 stack.append(State { .Block = block }) catch unreachable;2409 );
2410 stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2411 try stack.append(State { .Identifier = OptionalCtx { .Required = &node.rhs } });
2283 continue;2412 continue;
2284 },2413 },
2285 Token.Id.Semicolon => continue,
2286 else => {2414 else => {
2287 try self.parseError(&stack, token, "expected ';' or '{{', found {}", @tagName(token.id));2415 self.putBackToken(token);
2288 continue;2416 continue;
2289 },2417 },
2290 }2418 }
2291 },2419 },
22922420
2293 State.LabeledExpression => |ctx| {2421 State.PrimaryExpression => |opt_ctx| {
2294 const token = self.getNextToken();2422 const token = self.getNextToken();
2295 switch (token.id) {2423 switch (token.id) {
2296 Token.Id.LBrace => {2424 Token.Id.IntegerLiteral => {
2297 const block = try self.createBlock(arena, (?Token)(ctx.label), token);2425 _ = try self.createToCtxLiteral(arena, opt_ctx, ast.NodeStringLiteral, token);
2298 ctx.dest_ptr.store(&block.base);
2299
2300 stack.append(State { .Block = block }) catch unreachable;
2301 continue;2426 continue;
2302 },2427 },
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 );
2304 stack.append(State {2473 stack.append(State {
2305 .While = LoopCtx {2474 .ExpectTokenSave = ExpectTokenSave {
2306 .label = ctx.label,2475 .id = Token.Id.RParen,
2307 .inline_token = null,2476 .ptr = &node.rparen,
2308 .loop_token = token,
2309 .dest_ptr = ctx.dest_ptr,
2310 }2477 }
2311 }) catch unreachable;2478 }) catch unreachable;
2479 try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } });
2312 continue;2480 continue;
2313 },2481 },
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 );
2315 stack.append(State {2491 stack.append(State {
2316 .For = LoopCtx {2492 .ExprListItemOrEnd = ExprListCtx {
2317 .label = ctx.label,2493 .list = &node.params,
2318 .inline_token = null,2494 .end = Token.Id.RParen,
2319 .loop_token = token,2495 .ptr = &node.rparen_token,
2320 .dest_ptr = ctx.dest_ptr,
2321 }2496 }
2322 }) catch unreachable;2497 }) catch unreachable;
2498 try stack.append(State { .ExpectToken = Token.Id.LParen, });
2323 continue;2499 continue;
2324 },2500 },
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 => {
2326 stack.append(State {2514 stack.append(State {
2327 .Inline = InlineCtx {2515 .ErrorTypeOrSetDecl = ErrorTypeOrSetDeclCtx {
2328 .label = ctx.label,2516 .error_token = token,
2329 .inline_token = token,2517 .opt_ctx = opt_ctx
2330 .dest_ptr = ctx.dest_ptr,
2331 }2518 }
2332 }) catch unreachable;2519 }) catch unreachable;
2333 continue;2520 continue;
2334 },2521 },
2335 else => {2522 Token.Id.Keyword_packed => {
2336 try self.parseError(&stack, token, "expected 'while', 'for', 'inline' or '{{', found {}", @tagName(token.id));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;
2337 continue;2530 continue;
2338 },2531 },
2339 }2532 Token.Id.Keyword_extern => {
2340 },
2341
2342 State.Inline => |ctx| {
2343 const token = self.getNextToken();
2344 switch (token.id) {
2345 Token.Id.Keyword_while => {
2346 stack.append(State {2533 stack.append(State {
2347 .While = LoopCtx {2534 .ExternType = ExternTypeCtx {
2348 .inline_token = ctx.inline_token,2535 .opt_ctx = opt_ctx,
2349 .label = ctx.label,2536 .extern_token = token,
2350 .loop_token = token,2537 },
2351 .dest_ptr = ctx.dest_ptr,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
2352 }2557 }
2353 }) catch unreachable;2558 }) catch unreachable;
2354 continue;2559 continue;
2355 },2560 },
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 );
2357 stack.append(State {2623 stack.append(State {
2358 .For = LoopCtx {2624 .ExpectTokenSave = ExpectTokenSave {
2359 .inline_token = ctx.inline_token,2625 .id = Token.Id.RParen,
2360 .label = ctx.label,2626 .ptr = &node.rparen,
2361 .loop_token = token,2627 }
2362 .dest_ptr = ctx.dest_ptr,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,
2363 }2650 }
2364 }) catch unreachable;2651 }) catch unreachable;
2365 continue;2652 continue;
2366 },2653 },
2367 else => {2654 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 }
2369 continue;2661 continue;
2370 },2662 }
2371 }2663 }
2372 },2664 },
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;2667 State.ErrorTypeOrSetDecl => |ctx| {
2390 try stack.append(State { .Expression = DestPtr { .Field = &node.body } });2668 if (self.eatToken(Token.Id.LBrace) == null) {
2391 try stack.append(State { .WhileContinueExpr = &node.continue_expr });2669 _ = try self.createToCtxLiteral(arena, ctx.opt_ctx, ast.NodeErrorType, ctx.error_token);
2392 try stack.append(State { .PointerPayload = &node.payload });2670 continue;
2393 try stack.append(State { .ExpectToken = Token.Id.RParen });2671 }
2394 try stack.append(State { .Expression = DestPtr { .Field = &node.condition } });
2395 try stack.append(State { .ExpectToken = Token.Id.LParen });
2396 },
23972672
2398 State.For => |ctx| {2673 const node = try self.createToCtxNode(arena, ctx.opt_ctx, ast.NodeErrorSetDecl,
2399 const node = try arena.create(ast.NodeFor);2674 ast.NodeErrorSetDecl {
2400 *node = ast.NodeFor {2675 .base = undefined,
2401 .base = self.initNode(ast.Node.Id.For),2676 .error_token = ctx.error_token,
2402 .label = ctx.label,2677 .decls = ArrayList(&ast.Node).init(arena),
2403 .inline_token = ctx.inline_token,2678 .rbrace_token = undefined,
2404 .for_token = ctx.loop_token,2679 }
2405 .array_expr = undefined,2680 );
2406 .payload = null,
2407 .body = undefined,
2408 .@"else" = null,
2409 };
2410 ctx.dest_ptr.store(&node.base);
24112681
2412 stack.append(State { .Else = &node.@"else" }) catch unreachable;2682 stack.append(State {
2413 try stack.append(State { .Expression = DestPtr { .Field = &node.body } });2683 .IdentifierListItemOrEnd = ListSave(&ast.Node) {
2414 try stack.append(State { .PointerIndexPayload = &node.payload });2684 .list = &node.decls,
2415 try stack.append(State { .ExpectToken = Token.Id.RParen });2685 .ptr = &node.rbrace_token,
2416 try stack.append(State { .Expression = DestPtr { .Field = &node.array_expr } });2686 }
2417 try stack.append(State { .ExpectToken = Token.Id.LParen });2687 }) catch unreachable;
2688 continue;
2418 },2689 },
24192690 State.StringLiteral => |opt_ctx| {
2420 State.Block => |block| {
2421 const token = self.getNextToken();2691 const token = self.getNextToken();
2422 switch (token.id) {2692 opt_ctx.store(
2423 Token.Id.RBrace => {2693 (try self.parseStringLiteral(arena, token)) ?? {
2424 block.rbrace = token;
2425 continue;
2426 },
2427 else => {
2428 self.putBackToken(token);2694 self.putBackToken(token);
2429 stack.append(State { .Block = block }) catch unreachable;2695 if (opt_ctx != OptionalCtx.Optional) {
2430 try stack.append(State { .Statement = block });2696 return self.parseError(token, "expected primary expression, found {}", @tagName(token.id));
2697 }
2698
2431 continue;2699 continue;
2432 },2700 }
2433 }2701 );
2434 },2702 },
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| {2709 if (opt_ctx != OptionalCtx.Optional) {
2437 const next = self.getNextToken();2710 const token = self.getNextToken();
2438 switch (next.id) {2711 return self.parseError(token, "expected identifier, found {}", @tagName(token.id));
2439 Token.Id.Keyword_comptime => {2712 }
2440 const mut_token = self.getNextToken();2713 },
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);
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;2716 State.ExpectToken => |token_id| {
2484 continue;2717 _ = try self.expectToken(token_id);
2485 },2718 continue;
2486 else => {2719 },
2487 self.putBackToken(next);2720 State.ExpectTokenSave => |expect_token_save| {
2488 const statememt = try block.statements.addOne();2721 *expect_token_save.ptr = try self.expectToken(expect_token_save.id);
2489 stack.append(State { .Semicolon = statememt }) catch unreachable;2722 continue;
2490 try stack.append(State { .AssignmentExpressionBegin = DestPtr{.Field = statememt } });2723 },
2491 continue;2724 State.IfToken => |token_id| {
2492 }2725 if (self.eatToken(token_id)) |_| {
2726 continue;
2493 }2727 }
24942728
2729 _ = stack.pop();
2730 continue;
2495 },2731 },
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| {2738 _ = stack.pop();
2498 const node = *node_ptr;2739 continue;
2499 if (requireSemiColon(node)) {2740 },
2500 _ = (try self.eatToken(&stack, Token.Id.Semicolon)) ?? continue;2741 State.OptionalTokenSave => |optional_token_save| {
2742 if (self.eatToken(optional_token_save.id)) |token| {
2743 *optional_token_save.ptr = token;
2744 continue;
2501 }2745 }
2502 }2746
2747 continue;
2748 },
2503 }2749 }
2504 }2750 }
2505 }2751 }
...@@ -2530,7 +2776,7 @@ pub const Parser = struct {...@@ -2530,7 +2776,7 @@ pub const Parser = struct {
2530 continue;2776 continue;
2531 }2777 }
25322778
2533 n = while_node.body;2779 return while_node.body.id != ast.Node.Id.Block;
2534 },2780 },
2535 ast.Node.Id.For => {2781 ast.Node.Id.For => {
2536 const for_node = @fieldParentPtr(ast.NodeFor, "base", n);2782 const for_node = @fieldParentPtr(ast.NodeFor, "base", n);
...@@ -2539,7 +2785,7 @@ pub const Parser = struct {...@@ -2539,7 +2785,7 @@ pub const Parser = struct {
2539 continue;2785 continue;
2540 }2786 }
25412787
2542 n = for_node.body;2788 return for_node.body.id != ast.Node.Id.Block;
2543 },2789 },
2544 ast.Node.Id.If => {2790 ast.Node.Id.If => {
2545 const if_node = @fieldParentPtr(ast.NodeIf, "base", n);2791 const if_node = @fieldParentPtr(ast.NodeIf, "base", n);
...@@ -2548,25 +2794,25 @@ pub const Parser = struct {...@@ -2548,25 +2794,25 @@ pub const Parser = struct {
2548 continue;2794 continue;
2549 }2795 }
25502796
2551 n = if_node.body;2797 return if_node.body.id != ast.Node.Id.Block;
2552 },2798 },
2553 ast.Node.Id.Else => {2799 ast.Node.Id.Else => {
2554 const else_node = @fieldParentPtr(ast.NodeElse, "base", n);2800 const else_node = @fieldParentPtr(ast.NodeElse, "base", n);
2555 n = else_node.body;2801 n = else_node.body;
2802 continue;
2556 },2803 },
2557 ast.Node.Id.Defer => {2804 ast.Node.Id.Defer => {
2558 const defer_node = @fieldParentPtr(ast.NodeDefer, "base", n);2805 const defer_node = @fieldParentPtr(ast.NodeDefer, "base", n);
2559 n = defer_node.expr;2806 return defer_node.expr.id != ast.Node.Id.Block;
2560 },2807 },
2561 ast.Node.Id.Comptime => {2808 ast.Node.Id.Comptime => {
2562 const comptime_node = @fieldParentPtr(ast.NodeComptime, "base", n);2809 const comptime_node = @fieldParentPtr(ast.NodeComptime, "base", n);
2563 n = comptime_node.expr;2810 return comptime_node.expr.id != ast.Node.Id.Block;
2564 },2811 },
2565 ast.Node.Id.Suspend => {2812 ast.Node.Id.Suspend => {
2566 const suspend_node = @fieldParentPtr(ast.NodeSuspend, "base", n);2813 const suspend_node = @fieldParentPtr(ast.NodeSuspend, "base", n);
2567 if (suspend_node.body) |body| {2814 if (suspend_node.body) |body| {
2568 n = body;2815 return body.id != ast.Node.Id.Block;
2569 continue;
2570 }2816 }
25712817
2572 return true;2818 return true;
...@@ -2576,22 +2822,158 @@ pub const Parser = struct {...@@ -2576,22 +2822,158 @@ pub const Parser = struct {
2576 }2822 }
2577 }2823 }
25782824
2579 fn commaOrEnd(self: &Parser, stack: &ArrayList(State), end: &const Token.Id, maybe_ptr: ?&Token, state_after_comma: &const State) !void {2825 fn parseStringLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !?&ast.Node {
2580 var token = self.getNextToken();
2581 switch (token.id) {2826 switch (token.id) {
2582 Token.Id.Comma => {2827 Token.Id.StringLiteral => {
2583 stack.append(state_after_comma) catch unreachable;2828 return &(try self.createLiteral(arena, ast.NodeStringLiteral, token)).base;
2584 },2829 },
2585 else => {2830 Token.Id.MultilineStringLiteralLine => {
2586 const IdTag = @TagType(Token.Id);2831 const node = try self.createNode(arena, ast.NodeMultilineStringLiteral,
2587 if (IdTag(*end) == token.id) {2832 ast.NodeMultilineStringLiteral {
2588 if (maybe_ptr) |ptr| {2833 .base = undefined,
2589 *ptr = token;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,
2590 }2956 }
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;
2592 }2974 }
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));
2595 },2977 },
2596 }2978 }
2597 }2979 }
...@@ -2600,84 +2982,82 @@ pub const Parser = struct {...@@ -2600,84 +2982,82 @@ pub const Parser = struct {
2600 // TODO: We have to cast all cases because of this:2982 // TODO: We have to cast all cases because of this:
2601 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'2983 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
2602 return switch (*id) {2984 return switch (*id) {
2603 Token.Id.AmpersandEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitAnd),2985 Token.Id.AmpersandEqual => ast.NodeInfixOp.InfixOp { .AssignBitAnd = void{} },
2604 Token.Id.AngleBracketAngleBracketLeftEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitShiftLeft),2986 Token.Id.AngleBracketAngleBracketLeftEqual => ast.NodeInfixOp.InfixOp { .AssignBitShiftLeft = void{} },
2605 Token.Id.AngleBracketAngleBracketRightEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitShiftRight),2987 Token.Id.AngleBracketAngleBracketRightEqual => ast.NodeInfixOp.InfixOp { .AssignBitShiftRight = void{} },
2606 Token.Id.AsteriskEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignTimes),2988 Token.Id.AsteriskEqual => ast.NodeInfixOp.InfixOp { .AssignTimes = void{} },
2607 Token.Id.AsteriskPercentEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignTimesWarp),2989 Token.Id.AsteriskPercentEqual => ast.NodeInfixOp.InfixOp { .AssignTimesWarp = void{} },
2608 Token.Id.CaretEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitXor),2990 Token.Id.CaretEqual => ast.NodeInfixOp.InfixOp { .AssignBitXor = void{} },
2609 Token.Id.Equal => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Assign),2991 Token.Id.Equal => ast.NodeInfixOp.InfixOp { .Assign = void{} },
2610 Token.Id.MinusEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignMinus),2992 Token.Id.MinusEqual => ast.NodeInfixOp.InfixOp { .AssignMinus = void{} },
2611 Token.Id.MinusPercentEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignMinusWrap),2993 Token.Id.MinusPercentEqual => ast.NodeInfixOp.InfixOp { .AssignMinusWrap = void{} },
2612 Token.Id.PercentEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignMod),2994 Token.Id.PercentEqual => ast.NodeInfixOp.InfixOp { .AssignMod = void{} },
2613 Token.Id.PipeEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignBitOr),2995 Token.Id.PipeEqual => ast.NodeInfixOp.InfixOp { .AssignBitOr = void{} },
2614 Token.Id.PlusEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignPlus),2996 Token.Id.PlusEqual => ast.NodeInfixOp.InfixOp { .AssignPlus = void{} },
2615 Token.Id.PlusPercentEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignPlusWrap),2997 Token.Id.PlusPercentEqual => ast.NodeInfixOp.InfixOp { .AssignPlusWrap = void{} },
2616 Token.Id.SlashEqual => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.AssignDiv),2998 Token.Id.SlashEqual => ast.NodeInfixOp.InfixOp { .AssignDiv = void{} },
2617 else => null,2999 else => null,
2618 };3000 };
2619 }3001 }
26203002
2621 fn tokenIdToComparison(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {3003 fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
2622 // TODO: We have to cast all cases because of this:3004 return switch (id) {
2623 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'3005 Token.Id.Keyword_catch => ast.NodeInfixOp.InfixOp { .Catch = null },
2624 return switch (*id) {3006 Token.Id.QuestionMarkQuestionMark => ast.NodeInfixOp.InfixOp { .UnwrapMaybe = void{} },
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),
2631 else => null,3007 else => null,
2632 };3008 };
2633 }3009 }
26343010
2635 fn tokenIdToBitShift(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {3011 fn tokenIdToComparison(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
2636 // TODO: We have to cast all cases because of this:3012 return switch (id) {
2637 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'3013 Token.Id.BangEqual => ast.NodeInfixOp.InfixOp { .BangEqual = void{} },
2638 return switch (*id) {3014 Token.Id.EqualEqual => ast.NodeInfixOp.InfixOp { .EqualEqual = void{} },
2639 Token.Id.AngleBracketAngleBracketLeft => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.BitShiftLeft),3015 Token.Id.AngleBracketLeft => ast.NodeInfixOp.InfixOp { .LessThan = void{} },
2640 Token.Id.AngleBracketAngleBracketRight => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.BitShiftRight),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{} },
2641 else => null,3019 else => null,
2642 };3020 };
2643 }3021 }
26443022
2645 fn tokenIdToAddition(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {3023 fn tokenIdToBitShift(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
2646 // TODO: We have to cast all cases because of this:3024 return switch (id) {
2647 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'3025 Token.Id.AngleBracketAngleBracketLeft => ast.NodeInfixOp.InfixOp { .BitShiftLeft = void{} },
2648 return switch (*id) {3026 Token.Id.AngleBracketAngleBracketRight => ast.NodeInfixOp.InfixOp { .BitShiftRight = void{} },
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),
2654 else => null,3027 else => null,
2655 };3028 };
2656 }3029 }
26573030
2658 fn tokenIdToMultiply(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {3031 fn tokenIdToAddition(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
2659 // TODO: We have to cast all cases because of this:3032 return switch (id) {
2660 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'3033 Token.Id.Minus => ast.NodeInfixOp.InfixOp { .Sub = void{} },
2661 return switch (*id) {3034 Token.Id.MinusPercent => ast.NodeInfixOp.InfixOp { .SubWrap = void{} },
2662 Token.Id.Slash => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Div),3035 Token.Id.Plus => ast.NodeInfixOp.InfixOp { .Add = void{} },
2663 Token.Id.Asterisk => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.Mult),3036 Token.Id.PlusPercent => ast.NodeInfixOp.InfixOp { .AddWrap = void{} },
2664 Token.Id.AsteriskAsterisk => (ast.NodeInfixOp.InfixOp)(ast.NodeInfixOp.InfixOp.ArrayMult),3037 Token.Id.PlusPlus => ast.NodeInfixOp.InfixOp { .ArrayCat = void{} },
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),
2668 else => null,3038 else => null,
2669 };3039 };
2670 }3040 }
26713041
2672 fn tokenIdToPrefixOp(id: &const Token.Id) ?ast.NodePrefixOp.PrefixOp {3042 fn tokenIdToMultiply(id: @TagType(Token.Id)) ?ast.NodeInfixOp.InfixOp {
2673 // TODO: We have to cast all cases because of this:3043 return switch (id) {
2674 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'3044 Token.Id.Slash => ast.NodeInfixOp.InfixOp { .Div = void{} },
2675 return switch (*id) {3045 Token.Id.Asterisk => ast.NodeInfixOp.InfixOp { .Mult = void{} },
2676 Token.Id.Bang => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.BoolNot),3046 Token.Id.AsteriskAsterisk => ast.NodeInfixOp.InfixOp { .ArrayMult = void{} },
2677 Token.Id.Tilde => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.BitNot),3047 Token.Id.AsteriskPercent => ast.NodeInfixOp.InfixOp { .MultWrap = void{} },
2678 Token.Id.Minus => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.Negation),3048 Token.Id.Percent => ast.NodeInfixOp.InfixOp { .Mod = void{} },
2679 Token.Id.MinusPercent => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.NegationWrap),3049 Token.Id.PipePipe => ast.NodeInfixOp.InfixOp { .MergeErrorSets = void{} },
2680 Token.Id.Asterisk => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.Deref),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{} },
2681 Token.Id.Ampersand => ast.NodePrefixOp.PrefixOp {3061 Token.Id.Ampersand => ast.NodePrefixOp.PrefixOp {
2682 .AddrOf = ast.NodePrefixOp.AddrOfInfo {3062 .AddrOf = ast.NodePrefixOp.AddrOfInfo {
2683 .align_expr = null,3063 .align_expr = null,
...@@ -2687,307 +3067,93 @@ pub const Parser = struct {...@@ -2687,307 +3067,93 @@ pub const Parser = struct {
2687 .volatile_token = null,3067 .volatile_token = null,
2688 },3068 },
2689 },3069 },
2690 Token.Id.QuestionMark => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.MaybeType),3070 Token.Id.QuestionMark => ast.NodePrefixOp.PrefixOp { .MaybeType = void{} },
2691 Token.Id.QuestionMarkQuestionMark => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.UnwrapMaybe),3071 Token.Id.QuestionMarkQuestionMark => ast.NodePrefixOp.PrefixOp { .UnwrapMaybe = void{} },
2692 Token.Id.Keyword_await => (ast.NodePrefixOp.PrefixOp)(ast.NodePrefixOp.PrefixOp.Await),3072 Token.Id.Keyword_await => ast.NodePrefixOp.PrefixOp { .Await = void{} },
3073 Token.Id.Keyword_try => ast.NodePrefixOp.PrefixOp { .Try = void{ } },
2693 else => null,3074 else => null,
2694 };3075 };
2695 }3076 }
26963077
2697 fn initNode(self: &Parser, id: ast.Node.Id) ast.Node {3078 fn createNode(self: &Parser, arena: &mem.Allocator, comptime T: type, init_to: &const T) !&T {
2698 if (self.pending_line_comment_node) |comment_node| {3079 const node = try arena.create(T);
2699 self.pending_line_comment_node = null;3080 *node = *init_to;
2700 return ast.Node {.id = id, .comment = comment_node};3081 node.base = blk: {
2701 }3082 const id = ast.Node.typeToId(T);
2702 return ast.Node {.id = id, .comment = null };3083 if (self.pending_line_comment_node) |comment_node| {
2703 }3084 self.pending_line_comment_node = null;
27043085 break :blk ast.Node {.id = id, .comment = comment_node};
2705 fn createRoot(self: &Parser, arena: &mem.Allocator) !&ast.NodeRoot {3086 }
2706 const node = try arena.create(ast.NodeRoot);3087 break :blk ast.Node {.id = id, .comment = null };
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,
2882 };3088 };
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 };
2893 return node;3090 return node;
2894 }3091 }
28953092
2896 fn createUndefined(self: &Parser, arena: &mem.Allocator, token: &const Token) !&ast.NodeUndefinedLiteral {3093 fn createAttachNode(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node), comptime T: type, init_to: &const T) !&T {
2897 const node = try arena.create(ast.NodeUndefinedLiteral);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 };
2903 return node;3097 return node;
2904 }3098 }
29053099
2906 fn createAttachIdentifier(self: &Parser, arena: &mem.Allocator, dest_ptr: &const DestPtr, name_token: &const Token) !&ast.NodeIdentifier {3100 fn createToCtxNode(self: &Parser, arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, init_to: &const T) !&T {
2907 const node = try self.createIdentifier(arena, name_token);3101 const node = try self.createNode(arena, T, init_to);
2908 try dest_ptr.store(&node.base);3102 opt_ctx.store(&node.base);
2909 return node;
2910 }
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);
2915 return node;3104 return node;
2916 }3105 }
29173106
2918 fn createAttachFnProto(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node), fn_token: &const Token,3107 fn createLiteral(self: &Parser, arena: &mem.Allocator, comptime T: type, token: &const Token) !&T {
2919 extern_token: &const ?Token, lib_name: ?&ast.Node, cc_token: &const ?Token, visib_token: &const ?Token,3108 return self.createNode(arena, T,
2920 inline_token: &const ?Token) !&ast.NodeFnProto3109 T {
2921 {3110 .base = undefined,
2922 const node = try self.createFnProto(arena, fn_token, extern_token, lib_name, cc_token, visib_token, inline_token);3111 .token = *token,
2923 try list.append(&node.base);3112 }
2924 return node;3113 );
2925 }3114 }
29263115
2927 fn createAttachVarDecl(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node),3116 fn createToCtxLiteral(self: &Parser, arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, token: &const Token) !&T {
2928 visib_token: &const ?Token, mut_token: &const Token, comptime_token: &const ?Token,3117 const node = try self.createLiteral(arena, T, token);
2929 extern_token: &const ?Token, lib_name: ?&ast.Node) !&ast.NodeVarDecl3118 opt_ctx.store(&node.base);
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 }
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);
2941 return node;3120 return node;
2942 }3121 }
29433122
2944 fn parseError(self: &Parser, stack: &ArrayList(State), token: &const Token, comptime fmt: []const u8, args: ...) !void {3123 fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) (error{ParseError}) {
2945 // Before reporting an error. We pop the stack to see if our state was optional3124 const loc = self.tokenizer.getTokenLocation(0, token);
2946 self.revertIfOptional(stack) catch {3125 warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args);
2947 const loc = self.tokenizer.getTokenLocation(0, token);3126 warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]);
2948 warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args);3127 {
2949 warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]);3128 var i: usize = 0;
2950 {3129 while (i < loc.column) : (i += 1) {
2951 var i: usize = 0;3130 warn(" ");
2952 while (i < loc.column) : (i += 1) {
2953 warn(" ");
2954 }
2955 }3131 }
2956 {3132 }
2957 const caret_count = token.end - token.start;3133 {
2958 var i: usize = 0;3134 const caret_count = token.end - token.start;
2959 while (i < caret_count) : (i += 1) {3135 var i: usize = 0;
2960 warn("~");3136 while (i < caret_count) : (i += 1) {
2961 }3137 warn("~");
2962 }3138 }
2963 warn("\n");3139 }
2964 return error.ParseError;3140 warn("\n");
2965 };3141 return error.ParseError;
2966 }3142 }
29673143
2968 fn eatToken(self: &Parser, stack: &ArrayList(State), id: @TagType(Token.Id)) !?Token {3144 fn expectToken(self: &Parser, id: @TagType(Token.Id)) !Token {
2969 const token = self.getNextToken();3145 const token = self.getNextToken();
2970 if (token.id != id) {3146 if (token.id != id) {
2971 try self.parseError(stack, token, "expected {}, found {}", @tagName(id), @tagName(token.id));3147 return self.parseError(token, "expected {}, found {}", @tagName(id), @tagName(token.id));
2972 return null;
2973 }3148 }
2974 return token;3149 return token;
2975 }3150 }
29763151
2977 fn revertIfOptional(self: &Parser, stack: &ArrayList(State)) !void {3152 fn eatToken(self: &Parser, id: @TagType(Token.Id)) ?Token {
2978 while (stack.popOrNull()) |state| {3153 if (self.isPeekToken(id)) {
2979 switch (state) {3154 return self.getNextToken();
2980 State.Optional => |revert| {
2981 *self = revert.parser;
2982 *self.tokenizer = revert.tokenizer;
2983 *revert.ptr = null;
2984 return;
2985 },
2986 else => { }
2987 }
2988 }3155 }
29893156 return null;
2990 return error.NoOptionalStateFound;
2991 }3157 }
29923158
2993 fn putBackToken(self: &Parser, token: &const Token) void {3159 fn putBackToken(self: &Parser, token: &const Token) void {
...@@ -3006,6 +3172,12 @@ pub const Parser = struct {...@@ -3006,6 +3172,12 @@ pub const Parser = struct {
3006 }3172 }
3007 }3173 }
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
3009 const RenderAstFrame = struct {3181 const RenderAstFrame = struct {
3010 node: &ast.Node,3182 node: &ast.Node,
3011 indent: usize,3183 indent: usize,
...@@ -3040,7 +3212,6 @@ pub const Parser = struct {...@@ -3040,7 +3212,6 @@ pub const Parser = struct {
30403212
3041 const RenderState = union(enum) {3213 const RenderState = union(enum) {
3042 TopLevelDecl: &ast.Node,3214 TopLevelDecl: &ast.Node,
3043 FnProtoRParen: &ast.NodeFnProto,
3044 ParamDecl: &ast.Node,3215 ParamDecl: &ast.Node,
3045 Text: []const u8,3216 Text: []const u8,
3046 Expression: &ast.Node,3217 Expression: &ast.Node,
...@@ -3118,6 +3289,9 @@ pub const Parser = struct {...@@ -3118,6 +3289,9 @@ pub const Parser = struct {
3118 },3289 },
3119 ast.Node.Id.StructField => {3290 ast.Node.Id.StructField => {
3120 const field = @fieldParentPtr(ast.NodeStructField, "base", decl);3291 const field = @fieldParentPtr(ast.NodeStructField, "base", decl);
3292 if (field.visib_token) |visib_token| {
3293 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
3294 }
3121 try stream.print("{}: ", self.tokenizer.getTokenSlice(field.name_token));3295 try stream.print("{}: ", self.tokenizer.getTokenSlice(field.name_token));
3122 try stack.append(RenderState { .Expression = field.type_expr});3296 try stack.append(RenderState { .Expression = field.type_expr});
3123 },3297 },
...@@ -3179,13 +3353,13 @@ pub const Parser = struct {...@@ -3179,13 +3353,13 @@ pub const Parser = struct {
3179 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(comptime_token) });3353 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(comptime_token) });
3180 }3354 }
31813355
3182 if (var_decl.extern_token) |extern_token| {3356 if (var_decl.extern_export_token) |extern_export_token| {
3183 if (var_decl.lib_name != null) {3357 if (var_decl.lib_name != null) {
3184 try stack.append(RenderState { .Text = " " });3358 try stack.append(RenderState { .Text = " " });
3185 try stack.append(RenderState { .Expression = ??var_decl.lib_name });3359 try stack.append(RenderState { .Expression = ??var_decl.lib_name });
3186 }3360 }
3187 try stack.append(RenderState { .Text = " " });3361 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) });
3189 }3363 }
31903364
3191 if (var_decl.visib_token) |visib_token| {3365 if (var_decl.visib_token) |visib_token| {
...@@ -3217,7 +3391,7 @@ pub const Parser = struct {...@@ -3217,7 +3391,7 @@ pub const Parser = struct {
3217 RenderState.Expression => |base| switch (base.id) {3391 RenderState.Expression => |base| switch (base.id) {
3218 ast.Node.Id.Identifier => {3392 ast.Node.Id.Identifier => {
3219 const identifier = @fieldParentPtr(ast.NodeIdentifier, "base", base);3393 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));
3221 },3395 },
3222 ast.Node.Id.Block => {3396 ast.Node.Id.Block => {
3223 const block = @fieldParentPtr(ast.NodeBlock, "base", base);3397 const block = @fieldParentPtr(ast.NodeBlock, "base", base);
...@@ -3285,7 +3459,7 @@ pub const Parser = struct {...@@ -3285,7 +3459,7 @@ pub const Parser = struct {
3285 }3459 }
32863460
3287 if (suspend_node.payload) |payload| {3461 if (suspend_node.payload) |payload| {
3288 try stack.append(RenderState { .Expression = &payload.base });3462 try stack.append(RenderState { .Expression = payload });
3289 try stack.append(RenderState { .Text = " " });3463 try stack.append(RenderState { .Text = " " });
3290 }3464 }
3291 },3465 },
...@@ -3296,7 +3470,7 @@ pub const Parser = struct {...@@ -3296,7 +3470,7 @@ pub const Parser = struct {
3296 if (prefix_op_node.op == ast.NodeInfixOp.InfixOp.Catch) {3470 if (prefix_op_node.op == ast.NodeInfixOp.InfixOp.Catch) {
3297 if (prefix_op_node.op.Catch) |payload| {3471 if (prefix_op_node.op.Catch) |payload| {
3298 try stack.append(RenderState { .Text = " " });3472 try stack.append(RenderState { .Text = " " });
3299 try stack.append(RenderState { .Expression = &payload.base });3473 try stack.append(RenderState { .Expression = payload });
3300 }3474 }
3301 try stack.append(RenderState { .Text = " catch " });3475 try stack.append(RenderState { .Text = " catch " });
3302 } else {3476 } else {
...@@ -3440,50 +3614,70 @@ pub const Parser = struct {...@@ -3440,50 +3614,70 @@ pub const Parser = struct {
3440 try stack.append(RenderState { .Expression = suffix_op.lhs });3614 try stack.append(RenderState { .Expression = suffix_op.lhs });
3441 },3615 },
3442 ast.NodeSuffixOp.SuffixOp.StructInitializer => |field_inits| {3616 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 });
3444 var i = field_inits.len;3625 var i = field_inits.len;
3445 while (i != 0) {3626 while (i != 0) {
3446 i -= 1;3627 i -= 1;
3447 const field_init = field_inits.at(i);3628 const field_init = field_inits.at(i);
3629 try stack.append(RenderState { .Text = ",\n" });
3448 try stack.append(RenderState { .FieldInitializer = field_init });3630 try stack.append(RenderState { .FieldInitializer = field_init });
3449 try stack.append(RenderState { .Text = " " });3631 try stack.append(RenderState.PrintIndent);
3450 if (i != 0) {
3451 try stack.append(RenderState { .Text = "," });
3452 }
3453 }3632 }
3454 try stack.append(RenderState { .Text = "{"});3633 try stack.append(RenderState { .Indent = indent + indent_delta });
3634 try stack.append(RenderState { .Text = " {\n"});
3455 try stack.append(RenderState { .Expression = suffix_op.lhs });3635 try stack.append(RenderState { .Expression = suffix_op.lhs });
3456 },3636 },
3457 ast.NodeSuffixOp.SuffixOp.ArrayInitializer => |exprs| {3637 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 });
3459 var i = exprs.len;3646 var i = exprs.len;
3460 while (i != 0) {3647 while (i != 0) {
3461 i -= 1;3648 i -= 1;
3462 const expr = exprs.at(i);3649 const expr = exprs.at(i);
3650 try stack.append(RenderState { .Text = ",\n" });
3463 try stack.append(RenderState { .Expression = expr });3651 try stack.append(RenderState { .Expression = expr });
3464 try stack.append(RenderState { .Text = " " });3652 try stack.append(RenderState.PrintIndent);
3465 if (i != 0) {
3466 try stack.append(RenderState { .Text = "," });
3467 }
3468 }3653 }
3469 try stack.append(RenderState { .Text = "{"});3654 try stack.append(RenderState { .Indent = indent + indent_delta });
3655 try stack.append(RenderState { .Text = " {\n"});
3470 try stack.append(RenderState { .Expression = suffix_op.lhs });3656 try stack.append(RenderState { .Expression = suffix_op.lhs });
3471 },3657 },
3472 }3658 }
3473 },3659 },
3474 ast.Node.Id.ControlFlowExpression => {3660 ast.Node.Id.ControlFlowExpression => {
3475 const flow_expr = @fieldParentPtr(ast.NodeControlFlowExpression, "base", base);3661 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
3476 switch (flow_expr.kind) {3668 switch (flow_expr.kind) {
3477 ast.NodeControlFlowExpression.Kind.Break => |maybe_blk_token| {3669 ast.NodeControlFlowExpression.Kind.Break => |maybe_label| {
3478 try stream.print("break");3670 try stream.print("break");
3479 if (maybe_blk_token) |blk_token| {3671 if (maybe_label) |label| {
3480 try stream.print(" :{}", self.tokenizer.getTokenSlice(blk_token));3672 try stream.print(" :");
3673 try stack.append(RenderState { .Expression = label });
3481 }3674 }
3482 },3675 },
3483 ast.NodeControlFlowExpression.Kind.Continue => |maybe_blk_token| {3676 ast.NodeControlFlowExpression.Kind.Continue => |maybe_label| {
3484 try stream.print("continue");3677 try stream.print("continue");
3485 if (maybe_blk_token) |blk_token| {3678 if (maybe_label) |label| {
3486 try stream.print(" :{}", self.tokenizer.getTokenSlice(blk_token));3679 try stream.print(" :");
3680 try stack.append(RenderState { .Expression = label });
3487 }3681 }
3488 },3682 },
3489 ast.NodeControlFlowExpression.Kind.Return => {3683 ast.NodeControlFlowExpression.Kind.Return => {
...@@ -3491,25 +3685,20 @@ pub const Parser = struct {...@@ -3491,25 +3685,20 @@ pub const Parser = struct {
3491 },3685 },
34923686
3493 }3687 }
3494
3495 if (flow_expr.rhs) |rhs| {
3496 try stream.print(" ");
3497 try stack.append(RenderState { .Expression = rhs });
3498 }
3499 },3688 },
3500 ast.Node.Id.Payload => {3689 ast.Node.Id.Payload => {
3501 const payload = @fieldParentPtr(ast.NodePayload, "base", base);3690 const payload = @fieldParentPtr(ast.NodePayload, "base", base);
3502 try stack.append(RenderState { .Text = "|"});3691 try stack.append(RenderState { .Text = "|"});
3503 try stack.append(RenderState { .Expression = &payload.error_symbol.base });3692 try stack.append(RenderState { .Expression = payload.error_symbol });
3504 try stack.append(RenderState { .Text = "|"});3693 try stack.append(RenderState { .Text = "|"});
3505 },3694 },
3506 ast.Node.Id.PointerPayload => {3695 ast.Node.Id.PointerPayload => {
3507 const payload = @fieldParentPtr(ast.NodePointerPayload, "base", base);3696 const payload = @fieldParentPtr(ast.NodePointerPayload, "base", base);
3508 try stack.append(RenderState { .Text = "|"});3697 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) {3700 if (payload.ptr_token) |ptr_token| {
3512 try stack.append(RenderState { .Text = "*"});3701 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(ptr_token) });
3513 }3702 }
35143703
3515 try stack.append(RenderState { .Text = "|"});3704 try stack.append(RenderState { .Text = "|"});
...@@ -3519,14 +3708,14 @@ pub const Parser = struct {...@@ -3519,14 +3708,14 @@ pub const Parser = struct {
3519 try stack.append(RenderState { .Text = "|"});3708 try stack.append(RenderState { .Text = "|"});
35203709
3521 if (payload.index_symbol) |index_symbol| {3710 if (payload.index_symbol) |index_symbol| {
3522 try stack.append(RenderState { .Expression = &index_symbol.base });3711 try stack.append(RenderState { .Expression = index_symbol });
3523 try stack.append(RenderState { .Text = ", "});3712 try stack.append(RenderState { .Text = ", "});
3524 }3713 }
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) {3717 if (payload.ptr_token) |ptr_token| {
3529 try stack.append(RenderState { .Text = "*"});3718 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(ptr_token) });
3530 }3719 }
35313720
3532 try stack.append(RenderState { .Text = "|"});3721 try stack.append(RenderState { .Text = "|"});
...@@ -3607,6 +3796,14 @@ pub const Parser = struct {...@@ -3607,6 +3796,14 @@ pub const Parser = struct {
3607 while (i != 0) {3796 while (i != 0) {
3608 i -= 1;3797 i -= 1;
3609 const node = fields_and_decls[i];3798 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 }
3610 try stack.append(RenderState { .TopLevelDecl = node});3807 try stack.append(RenderState { .TopLevelDecl = node});
3611 try stack.append(RenderState.PrintIndent);3808 try stack.append(RenderState.PrintIndent);
3612 try stack.append(RenderState {3809 try stack.append(RenderState {
...@@ -3621,18 +3818,6 @@ pub const Parser = struct {...@@ -3621,18 +3818,6 @@ pub const Parser = struct {
3621 break :blk "\n";3818 break :blk "\n";
3622 },3819 },
3623 });3820 });
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 }
3636 }3821 }
3637 try stack.append(RenderState { .Indent = indent + indent_delta});3822 try stack.append(RenderState { .Indent = indent + indent_delta});
3638 try stack.append(RenderState { .Text = "{"});3823 try stack.append(RenderState { .Text = "{"});
...@@ -3661,7 +3846,8 @@ pub const Parser = struct {...@@ -3661,7 +3846,8 @@ pub const Parser = struct {
3661 while (i != 0) {3846 while (i != 0) {
3662 i -= 1;3847 i -= 1;
3663 const node = decls[i];3848 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 });
3665 try stack.append(RenderState.PrintIndent);3851 try stack.append(RenderState.PrintIndent);
3666 try stack.append(RenderState {3852 try stack.append(RenderState {
3667 .Text = blk: {3853 .Text = blk: {
...@@ -3675,10 +3861,6 @@ pub const Parser = struct {...@@ -3675,10 +3861,6 @@ pub const Parser = struct {
3675 break :blk "\n";3861 break :blk "\n";
3676 },3862 },
3677 });3863 });
3678
3679 if (i != 0) {
3680 try stack.append(RenderState { .Text = "," });
3681 }
3682 }3864 }
3683 try stack.append(RenderState { .Indent = indent + indent_delta});3865 try stack.append(RenderState { .Indent = indent + indent_delta});
3684 try stack.append(RenderState { .Text = "{"});3866 try stack.append(RenderState { .Text = "{"});
...@@ -3726,8 +3908,10 @@ pub const Parser = struct {...@@ -3726,8 +3908,10 @@ pub const Parser = struct {
3726 },3908 },
3727 }3909 }
37283910
3729 if (fn_proto.align_expr != null) {3911 if (fn_proto.align_expr) |align_expr| {
3730 @panic("TODO");3912 try stack.append(RenderState { .Text = ") " });
3913 try stack.append(RenderState { .Expression = align_expr});
3914 try stack.append(RenderState { .Text = "align(" });
3731 }3915 }
37323916
3733 try stack.append(RenderState { .Text = ") " });3917 try stack.append(RenderState { .Text = ") " });
...@@ -3763,9 +3947,9 @@ pub const Parser = struct {...@@ -3763,9 +3947,9 @@ pub const Parser = struct {
3763 try stack.append(RenderState { .Text = " " });3947 try stack.append(RenderState { .Text = " " });
3764 try stack.append(RenderState { .Expression = lib_name });3948 try stack.append(RenderState { .Expression = lib_name });
3765 }3949 }
3766 if (fn_proto.extern_token) |extern_token| {3950 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
3767 try stack.append(RenderState { .Text = " " });3951 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) });
3769 }3953 }
37703954
3771 if (fn_proto.visib_token) |visib_token| {3955 if (fn_proto.visib_token) |visib_token| {
...@@ -3789,6 +3973,7 @@ pub const Parser = struct {...@@ -3789,6 +3973,7 @@ pub const Parser = struct {
3789 while (i != 0) {3973 while (i != 0) {
3790 i -= 1;3974 i -= 1;
3791 const node = cases[i];3975 const node = cases[i];
3976 try stack.append(RenderState { .Text = ","});
3792 try stack.append(RenderState { .Expression = &node.base});3977 try stack.append(RenderState { .Expression = &node.base});
3793 try stack.append(RenderState.PrintIndent);3978 try stack.append(RenderState.PrintIndent);
3794 try stack.append(RenderState {3979 try stack.append(RenderState {
...@@ -3803,10 +3988,6 @@ pub const Parser = struct {...@@ -3803,10 +3988,6 @@ pub const Parser = struct {
3803 break :blk "\n";3988 break :blk "\n";
3804 },3989 },
3805 });3990 });
3806
3807 if (i != 0) {
3808 try stack.append(RenderState { .Text = "," });
3809 }
3810 }3991 }
3811 try stack.append(RenderState { .Indent = indent + indent_delta});3992 try stack.append(RenderState { .Indent = indent + indent_delta});
3812 try stack.append(RenderState { .Text = ") {"});3993 try stack.append(RenderState { .Text = ") {"});
...@@ -3818,7 +3999,7 @@ pub const Parser = struct {...@@ -3818,7 +3999,7 @@ pub const Parser = struct {
3818 try stack.append(RenderState { .Expression = switch_case.expr });3999 try stack.append(RenderState { .Expression = switch_case.expr });
3819 if (switch_case.payload) |payload| {4000 if (switch_case.payload) |payload| {
3820 try stack.append(RenderState { .Text = " " });4001 try stack.append(RenderState { .Text = " " });
3821 try stack.append(RenderState { .Expression = &payload.base });4002 try stack.append(RenderState { .Expression = payload });
3822 }4003 }
3823 try stack.append(RenderState { .Text = " => "});4004 try stack.append(RenderState { .Text = " => "});
38244005
...@@ -3829,7 +4010,8 @@ pub const Parser = struct {...@@ -3829,7 +4010,8 @@ pub const Parser = struct {
3829 try stack.append(RenderState { .Expression = items[i] });4010 try stack.append(RenderState { .Expression = items[i] });
38304011
3831 if (i != 0) {4012 if (i != 0) {
3832 try stack.append(RenderState { .Text = ", " });4013 try stack.append(RenderState.PrintIndent);
4014 try stack.append(RenderState { .Text = ",\n" });
3833 }4015 }
3834 }4016 }
3835 },4017 },
...@@ -3859,7 +4041,7 @@ pub const Parser = struct {...@@ -3859,7 +4041,7 @@ pub const Parser = struct {
38594041
3860 if (else_node.payload) |payload| {4042 if (else_node.payload) |payload| {
3861 try stack.append(RenderState { .Text = " " });4043 try stack.append(RenderState { .Text = " " });
3862 try stack.append(RenderState { .Expression = &payload.base });4044 try stack.append(RenderState { .Expression = payload });
3863 }4045 }
3864 },4046 },
3865 ast.Node.Id.While => {4047 ast.Node.Id.While => {
...@@ -3904,7 +4086,7 @@ pub const Parser = struct {...@@ -3904,7 +4086,7 @@ pub const Parser = struct {
3904 }4086 }
39054087
3906 if (while_node.payload) |payload| {4088 if (while_node.payload) |payload| {
3907 try stack.append(RenderState { .Expression = &payload.base });4089 try stack.append(RenderState { .Expression = payload });
3908 try stack.append(RenderState { .Text = " " });4090 try stack.append(RenderState { .Text = " " });
3909 }4091 }
39104092
...@@ -3947,7 +4129,7 @@ pub const Parser = struct {...@@ -3947,7 +4129,7 @@ pub const Parser = struct {
3947 }4129 }
39484130
3949 if (for_node.payload) |payload| {4131 if (for_node.payload) |payload| {
3950 try stack.append(RenderState { .Expression = &payload.base });4132 try stack.append(RenderState { .Expression = payload });
3951 try stack.append(RenderState { .Text = " " });4133 try stack.append(RenderState { .Text = " " });
3952 }4134 }
39534135
...@@ -3980,7 +4162,7 @@ pub const Parser = struct {...@@ -3980,7 +4162,7 @@ pub const Parser = struct {
39804162
3981 if (@"else".payload) |payload| {4163 if (@"else".payload) |payload| {
3982 try stack.append(RenderState { .Text = " " });4164 try stack.append(RenderState { .Text = " " });
3983 try stack.append(RenderState { .Expression = &payload.base });4165 try stack.append(RenderState { .Expression = payload });
3984 }4166 }
39854167
3986 try stack.append(RenderState { .Text = " " });4168 try stack.append(RenderState { .Text = " " });
...@@ -3994,7 +4176,7 @@ pub const Parser = struct {...@@ -3994,7 +4176,7 @@ pub const Parser = struct {
3994 try stack.append(RenderState { .Text = " " });4176 try stack.append(RenderState { .Text = " " });
39954177
3996 if (if_node.payload) |payload| {4178 if (if_node.payload) |payload| {
3997 try stack.append(RenderState { .Expression = &payload.base });4179 try stack.append(RenderState { .Expression = payload });
3998 try stack.append(RenderState { .Text = " " });4180 try stack.append(RenderState { .Text = " " });
3999 }4181 }
40004182
...@@ -4006,12 +4188,10 @@ pub const Parser = struct {...@@ -4006,12 +4188,10 @@ pub const Parser = struct {
4006 const asm_node = @fieldParentPtr(ast.NodeAsm, "base", base);4188 const asm_node = @fieldParentPtr(ast.NodeAsm, "base", base);
4007 try stream.print("{} ", self.tokenizer.getTokenSlice(asm_node.asm_token));4189 try stream.print("{} ", self.tokenizer.getTokenSlice(asm_node.asm_token));
40084190
4009 if (asm_node.is_volatile) {4191 if (asm_node.volatile_token) |volatile_token| {
4010 try stream.write("volatile ");4192 try stream.print("{} ", self.tokenizer.getTokenSlice(volatile_token));
4011 }4193 }
40124194
4013 try stream.print("({}", self.tokenizer.getTokenSlice(asm_node.template));
4014
4015 try stack.append(RenderState { .Indent = indent });4195 try stack.append(RenderState { .Indent = indent });
4016 try stack.append(RenderState { .Text = ")" });4196 try stack.append(RenderState { .Text = ")" });
4017 {4197 {
...@@ -4019,7 +4199,7 @@ pub const Parser = struct {...@@ -4019,7 +4199,7 @@ pub const Parser = struct {
4019 var i = cloppers.len;4199 var i = cloppers.len;
4020 while (i != 0) {4200 while (i != 0) {
4021 i -= 1;4201 i -= 1;
4022 try stack.append(RenderState { .Expression = &cloppers[i].base });4202 try stack.append(RenderState { .Expression = cloppers[i] });
40234203
4024 if (i != 0) {4204 if (i != 0) {
4025 try stack.append(RenderState { .Text = ", " });4205 try stack.append(RenderState { .Text = ", " });
...@@ -4088,6 +4268,8 @@ pub const Parser = struct {...@@ -4088,6 +4268,8 @@ pub const Parser = struct {
4088 try stack.append(RenderState.PrintIndent);4268 try stack.append(RenderState.PrintIndent);
4089 try stack.append(RenderState { .Indent = indent + indent_delta});4269 try stack.append(RenderState { .Indent = indent + indent_delta});
4090 try stack.append(RenderState { .Text = "\n" });4270 try stack.append(RenderState { .Text = "\n" });
4271 try stack.append(RenderState { .Expression = asm_node.template });
4272 try stack.append(RenderState { .Text = "(" });
4091 },4273 },
4092 ast.Node.Id.AsmInput => {4274 ast.Node.Id.AsmInput => {
4093 const asm_input = @fieldParentPtr(ast.NodeAsmInput, "base", base);4275 const asm_input = @fieldParentPtr(ast.NodeAsmInput, "base", base);
...@@ -4095,9 +4277,9 @@ pub const Parser = struct {...@@ -4095,9 +4277,9 @@ pub const Parser = struct {
4095 try stack.append(RenderState { .Text = ")"});4277 try stack.append(RenderState { .Text = ")"});
4096 try stack.append(RenderState { .Expression = asm_input.expr});4278 try stack.append(RenderState { .Expression = asm_input.expr});
4097 try stack.append(RenderState { .Text = " ("});4279 try stack.append(RenderState { .Text = " ("});
4098 try stack.append(RenderState { .Expression = &asm_input.constraint.base});4280 try stack.append(RenderState { .Expression = asm_input.constraint });
4099 try stack.append(RenderState { .Text = "] "});4281 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 });
4101 try stack.append(RenderState { .Text = "["});4283 try stack.append(RenderState { .Text = "["});
4102 },4284 },
4103 ast.Node.Id.AsmOutput => {4285 ast.Node.Id.AsmOutput => {
...@@ -4114,9 +4296,9 @@ pub const Parser = struct {...@@ -4114,9 +4296,9 @@ pub const Parser = struct {
4114 },4296 },
4115 }4297 }
4116 try stack.append(RenderState { .Text = " ("});4298 try stack.append(RenderState { .Text = " ("});
4117 try stack.append(RenderState { .Expression = &asm_output.constraint.base});4299 try stack.append(RenderState { .Expression = asm_output.constraint });
4118 try stack.append(RenderState { .Text = "] "});4300 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 });
4120 try stack.append(RenderState { .Text = "["});4302 try stack.append(RenderState { .Text = "["});
4121 },4303 },
41224304
...@@ -4129,26 +4311,6 @@ pub const Parser = struct {...@@ -4129,26 +4311,6 @@ pub const Parser = struct {
4129 ast.Node.Id.TestDecl,4311 ast.Node.Id.TestDecl,
4130 ast.Node.Id.ParamDecl => unreachable,4312 ast.Node.Id.ParamDecl => unreachable,
4131 },4313 },
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 },
4152 RenderState.Statement => |base| {4314 RenderState.Statement => |base| {
4153 if (base.comment) |comment| {4315 if (base.comment) |comment| {
4154 for (comment.lines.toSliceConst()) |line_token| {4316 for (comment.lines.toSliceConst()) |line_token| {
...@@ -4441,10 +4603,10 @@ test "zig fmt: precedence" {...@@ -4441,10 +4603,10 @@ test "zig fmt: precedence" {
4441 \\ (a!b)();4603 \\ (a!b)();
4442 \\ !a!b;4604 \\ !a!b;
4443 \\ !(a!b);4605 \\ !(a!b);
4444 \\ !a{ };4606 \\ !a{};
4445 \\ !(a{ });4607 \\ !(a{});
4446 \\ a + b{ };4608 \\ a + b{};
4447 \\ (a + b){ };4609 \\ (a + b){};
4448 \\ a << b + c;4610 \\ a << b + c;
4449 \\ (a << b) + c;4611 \\ (a << b) + c;
4450 \\ a & b << c;4612 \\ a & b << c;
...@@ -4502,10 +4664,20 @@ test "zig fmt: var type" {...@@ -4502,10 +4664,20 @@ test "zig fmt: var type" {
4502 );4664 );
4503}4665}
45044666
4505test "zig fmt: extern function" {4667test "zig fmt: functions" {
4506 try testCanonical(4668 try testCanonical(
4507 \\extern fn puts(s: &const u8) c_int;4669 \\extern fn puts(s: &const u8) c_int;
4508 \\extern "c" fn puts(s: &const u8) c_int;4670 \\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;
4509 \\4681 \\
4510 );4682 );
4511}4683}
...@@ -4565,26 +4737,27 @@ test "zig fmt: struct declaration" {...@@ -4565,26 +4737,27 @@ test "zig fmt: struct declaration" {
4565 \\const S = struct {4737 \\const S = struct {
4566 \\ const Self = this;4738 \\ const Self = this;
4567 \\ f1: u8,4739 \\ f1: u8,
4740 \\ pub f3: u8,
4568 \\4741 \\
4569 \\ fn method(self: &Self) Self {4742 \\ fn method(self: &Self) Self {
4570 \\ return *self;4743 \\ return *self;
4571 \\ }4744 \\ }
4572 \\4745 \\
4573 \\ f2: u84746 \\ f2: u8,
4574 \\};4747 \\};
4575 \\4748 \\
4576 \\const Ps = packed struct {4749 \\const Ps = packed struct {
4577 \\ a: u8,4750 \\ a: u8,
4578 \\ b: u8,4751 \\ pub b: u8,
4579 \\4752 \\
4580 \\ c: u84753 \\ c: u8,
4581 \\};4754 \\};
4582 \\4755 \\
4583 \\const Es = extern struct {4756 \\const Es = extern struct {
4584 \\ a: u8,4757 \\ a: u8,
4585 \\ b: u8,4758 \\ pub b: u8,
4586 \\4759 \\
4587 \\ c: u84760 \\ c: u8,
4588 \\};4761 \\};
4589 \\4762 \\
4590 );4763 );
...@@ -4594,25 +4767,25 @@ test "zig fmt: enum declaration" {...@@ -4594,25 +4767,25 @@ test "zig fmt: enum declaration" {
4594 try testCanonical(4767 try testCanonical(
4595 \\const E = enum {4768 \\const E = enum {
4596 \\ Ok,4769 \\ Ok,
4597 \\ SomethingElse = 04770 \\ SomethingElse = 0,
4598 \\};4771 \\};
4599 \\4772 \\
4600 \\const E2 = enum(u8) {4773 \\const E2 = enum(u8) {
4601 \\ Ok,4774 \\ Ok,
4602 \\ SomethingElse = 255,4775 \\ SomethingElse = 255,
4603 \\ SomethingThird4776 \\ SomethingThird,
4604 \\};4777 \\};
4605 \\4778 \\
4606 \\const Ee = extern enum {4779 \\const Ee = extern enum {
4607 \\ Ok,4780 \\ Ok,
4608 \\ SomethingElse,4781 \\ SomethingElse,
4609 \\ SomethingThird4782 \\ SomethingThird,
4610 \\};4783 \\};
4611 \\4784 \\
4612 \\const Ep = packed enum {4785 \\const Ep = packed enum {
4613 \\ Ok,4786 \\ Ok,
4614 \\ SomethingElse,4787 \\ SomethingElse,
4615 \\ SomethingThird4788 \\ SomethingThird,
4616 \\};4789 \\};
4617 \\4790 \\
4618 );4791 );
...@@ -4624,35 +4797,35 @@ test "zig fmt: union declaration" {...@@ -4624,35 +4797,35 @@ test "zig fmt: union declaration" {
4624 \\ Int: u8,4797 \\ Int: u8,
4625 \\ Float: f32,4798 \\ Float: f32,
4626 \\ None,4799 \\ None,
4627 \\ Bool: bool4800 \\ Bool: bool,
4628 \\};4801 \\};
4629 \\4802 \\
4630 \\const Ue = union(enum) {4803 \\const Ue = union(enum) {
4631 \\ Int: u8,4804 \\ Int: u8,
4632 \\ Float: f32,4805 \\ Float: f32,
4633 \\ None,4806 \\ None,
4634 \\ Bool: bool4807 \\ Bool: bool,
4635 \\};4808 \\};
4636 \\4809 \\
4637 \\const E = enum {4810 \\const E = enum {
4638 \\ Int,4811 \\ Int,
4639 \\ Float,4812 \\ Float,
4640 \\ None,4813 \\ None,
4641 \\ Bool4814 \\ Bool,
4642 \\};4815 \\};
4643 \\4816 \\
4644 \\const Ue2 = union(E) {4817 \\const Ue2 = union(E) {
4645 \\ Int: u8,4818 \\ Int: u8,
4646 \\ Float: f32,4819 \\ Float: f32,
4647 \\ None,4820 \\ None,
4648 \\ Bool: bool4821 \\ Bool: bool,
4649 \\};4822 \\};
4650 \\4823 \\
4651 \\const Eu = extern union {4824 \\const Eu = extern union {
4652 \\ Int: u8,4825 \\ Int: u8,
4653 \\ Float: f32,4826 \\ Float: f32,
4654 \\ None,4827 \\ None,
4655 \\ Bool: bool4828 \\ Bool: bool,
4656 \\};4829 \\};
4657 \\4830 \\
4658 );4831 );
...@@ -4664,7 +4837,7 @@ test "zig fmt: error set declaration" {...@@ -4664,7 +4837,7 @@ test "zig fmt: error set declaration" {
4664 \\ A,4837 \\ A,
4665 \\ B,4838 \\ B,
4666 \\4839 \\
4667 \\ C4840 \\ C,
4668 \\};4841 \\};
4669 \\4842 \\
4670 );4843 );
...@@ -4673,9 +4846,15 @@ test "zig fmt: error set declaration" {...@@ -4673,9 +4846,15 @@ test "zig fmt: error set declaration" {
4673test "zig fmt: arrays" {4846test "zig fmt: arrays" {
4674 try testCanonical(4847 try testCanonical(
4675 \\test "test array" {4848 \\test "test array" {
4676 \\ const a: [2]u8 = [2]u8{ 1, 2 };4849 \\ const a: [2]u8 = [2]u8 {
4677 \\ const a: [2]u8 = []u8{ 1, 2 };4850 \\ 1,
4678 \\ const a: [0]u8 = []u8{ };4851 \\ 2,
4852 \\ };
4853 \\ const a: [2]u8 = []u8 {
4854 \\ 1,
4855 \\ 2,
4856 \\ };
4857 \\ const a: [0]u8 = []u8{};
4679 \\}4858 \\}
4680 \\4859 \\
4681 );4860 );
...@@ -4683,10 +4862,18 @@ test "zig fmt: arrays" {...@@ -4683,10 +4862,18 @@ test "zig fmt: arrays" {
46834862
4684test "zig fmt: container initializers" {4863test "zig fmt: container initializers" {
4685 try testCanonical(4864 try testCanonical(
4686 \\const a1 = []u8{ };4865 \\const a1 = []u8{};
4687 \\const a2 = []u8{ 1, 2, 3, 4 };4866 \\const a2 = []u8 {
4688 \\const s1 = S{ };4867 \\ 1,
4689 \\const s2 = S{ .a = 1, .b = 2 };4868 \\ 2,
4869 \\ 3,
4870 \\ 4,
4871 \\};
4872 \\const s1 = S{};
4873 \\const s2 = S {
4874 \\ .a = 1,
4875 \\ .b = 2,
4876 \\};
4690 \\4877 \\
4691 );4878 );
4692}4879}
...@@ -4730,30 +4917,34 @@ test "zig fmt: switch" {...@@ -4730,30 +4917,34 @@ test "zig fmt: switch" {
4730 \\ switch (0) {4917 \\ switch (0) {
4731 \\ 0 => {},4918 \\ 0 => {},
4732 \\ 1 => unreachable,4919 \\ 1 => unreachable,
4733 \\ 2, 3 => {},4920 \\ 2,
4921 \\ 3 => {},
4734 \\ 4 ... 7 => {},4922 \\ 4 ... 7 => {},
4735 \\ 1 + 4 * 3 + 22 => {},4923 \\ 1 + 4 * 3 + 22 => {},
4736 \\ else => {4924 \\ else => {
4737 \\ const a = 1;4925 \\ const a = 1;
4738 \\ const b = a;4926 \\ const b = a;
4739 \\ }4927 \\ },
4740 \\ }4928 \\ }
4741 \\4929 \\
4742 \\ const res = switch (0) {4930 \\ const res = switch (0) {
4743 \\ 0 => 0,4931 \\ 0 => 0,
4744 \\ 1 => 2,4932 \\ 1 => 2,
4745 \\ else => 44933 \\ 1 => a = 4,
4934 \\ else => 4,
4746 \\ };4935 \\ };
4747 \\4936 \\
4748 \\ const Union = union(enum) {4937 \\ const Union = union(enum) {
4749 \\ Int: i64,4938 \\ Int: i64,
4750 \\ Float: f644939 \\ Float: f64,
4751 \\ };4940 \\ };
4752 \\4941 \\
4753 \\ const u = Union{ .Int = 0 };4942 \\ const u = Union {
4943 \\ .Int = 0,
4944 \\ };
4754 \\ switch (u) {4945 \\ switch (u) {
4755 \\ Union.Int => |int| {},4946 \\ Union.Int => |int| {},
4756 \\ Union.Float => |*float| unreachable4947 \\ Union.Float => |*float| unreachable,
4757 \\ }4948 \\ }
4758 \\}4949 \\}
4759 \\4950 \\
...@@ -4829,7 +5020,11 @@ test "zig fmt: while" {...@@ -4829,7 +5020,11 @@ test "zig fmt: while" {
4829test "zig fmt: for" {5020test "zig fmt: for" {
4830 try testCanonical(5021 try testCanonical(
4831 \\test "for" {5022 \\test "for" {
4832 \\ const a = []u8{ 1, 2, 3 };5023 \\ const a = []u8 {
5024 \\ 1,
5025 \\ 2,
5026 \\ 3,
5027 \\ };
4833 \\ for (a) |v| {5028 \\ for (a) |v| {
4834 \\ continue;5029 \\ continue;
4835 \\ }5030 \\ }
...@@ -4887,6 +5082,7 @@ test "zig fmt: if" {...@@ -4887,6 +5082,7 @@ test "zig fmt: if" {
4887 \\ }5082 \\ }
4888 \\5083 \\
4889 \\ const is_world_broken = if (10 < 0) true else false;5084 \\ const is_world_broken = if (10 < 0) true else false;
5085 \\ const some_number = 1 + if (10 < 0) 2 else 3;
4890 \\5086 \\
4891 \\ const a: ?u8 = 10;5087 \\ const a: ?u8 = 10;
4892 \\ const b: ?u8 = null;5088 \\ const b: ?u8 = null;
...@@ -5000,6 +5196,7 @@ test "zig fmt: inline asm" {...@@ -5000,6 +5196,7 @@ test "zig fmt: inline asm" {
5000test "zig fmt: coroutines" {5196test "zig fmt: coroutines" {
5001 try testCanonical(5197 try testCanonical(
5002 \\async fn simpleAsyncFn() void {5198 \\async fn simpleAsyncFn() void {
5199 \\ const a = async a.b();
5003 \\ x += 1;5200 \\ x += 1;
5004 \\ suspend;5201 \\ suspend;
5005 \\ x += 1;5202 \\ x += 1;
...@@ -5047,3 +5244,22 @@ test "zig fmt: string identifier" {...@@ -5047,3 +5244,22 @@ test "zig fmt: string identifier" {
5047 \\5244 \\
5048 );5245 );
5049}5246}
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" {...@@ -94,3 +94,20 @@ test "inline function call" {
94}94}
9595
96fn add(a: i32, b: i32) i32 { return a + b; }96fn 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 @@...@@ -1,6 +1,15 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: &tests.CompileErrorContext) void {3pub 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
4 cases.add("wrong type passed to @panic",13 cases.add("wrong type passed to @panic",
5 \\export fn entry() void {14 \\export fn entry() void {
6 \\ var e = error.Foo;15 \\ var e = error.Foo;
...@@ -1723,7 +1732,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1723,7 +1732,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1723 \\}1732 \\}
1724 \\1733 \\
1725 \\export fn entry() usize { return @sizeOf(@typeOf(bar)); }1734 \\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
1728 cases.add("assign too big number to u16",1737 cases.add("assign too big number to u16",
1729 \\export fn foo() void {1738 \\export fn foo() void {