authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-06-03 16:22:13-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-06-04 00:06:17-07:00
logb0c17a6becae820624da8cf41c880184ce0a104e
tree8b7bfaae92739fbd1b0d1ecd52f0ac73aa15f6f5
parent3391ad7a9091edec0b368b0e98e61ec02043e91b

CLI: update sub-command to use StaticStringMap

std.StaticStringMap: add initEnum method for when the tag name and the string to match are the same. In this case users should use getIndex to get the enum tag value.

2 files changed, 269 insertions(+), 142 deletions(-)

lib/std/static_string_map.zig+57
...@@ -100,6 +100,51 @@ pub fn StaticStringMapWithEql(...@@ -100,6 +100,51 @@ pub fn StaticStringMapWithEql(
100 }100 }
101 }101 }
102102
103 /// Returns a map backed by static, comptime allocated memory.
104 ///
105 /// `V` must be `void`. The enum's tag names will be used as the keys.
106 pub inline fn initEnum(comptime E: type) Self {
107 comptime {
108 var self: Self = .{};
109
110 const field_names = @typeInfo(E).@"enum".field_names;
111 if (field_names.len == 0) return self;
112
113 // Since the KVs are sorted, a linearly-growing bound will never
114 // be sufficient for extreme cases. So we grow proportional to
115 // N*log2(N).
116 @setEvalBranchQuota(10 * field_names.len * std.math.log2_int_ceil(usize, field_names.len));
117
118 var sorted_keys: [field_names.len][]const u8 = field_names[0..field_names.len].*;
119 var sorted_vals: [field_names.len]V = @splat({});
120
121 for (field_names) |field_name| {
122 self.min_len = @min(self.min_len, field_name.len);
123 self.max_len = @max(self.max_len, field_name.len);
124 }
125
126 mem.sortUnstableContext(0, sorted_keys.len, SortContext{
127 .keys = &sorted_keys,
128 .vals = &sorted_vals,
129 });
130
131 const final_keys = sorted_keys;
132 const final_vals = sorted_vals;
133 self.kvs = &.{
134 .keys = &final_keys,
135 .values = &final_vals,
136 .len = @intCast(field_names.len),
137 };
138
139 var len_indexes: [self.max_len + 1]u32 = undefined;
140 self.initLenIndexes(&len_indexes);
141 const final_len_indexes = len_indexes;
142 self.len_indexes = &final_len_indexes;
143 self.len_indexes_len = @intCast(len_indexes.len);
144 return self;
145 }
146 }
147
103 /// Returns a map backed by memory allocated with `allocator`.148 /// Returns a map backed by memory allocated with `allocator`.
104 ///149 ///
105 /// Handles `kvs_list` the same way as `initComptime()`.150 /// Handles `kvs_list` the same way as `initComptime()`.
...@@ -536,3 +581,15 @@ test "sorting kvs doesn't exceed eval branch quota" {...@@ -536,3 +581,15 @@ test "sorting kvs doesn't exceed eval branch quota" {
536 });581 });
537 try testing.expectEqual(1, TypeToByteSizeLUT.get("t1"));582 try testing.expectEqual(1, TypeToByteSizeLUT.get("t1"));
538}583}
584
585test "initEnum" {
586 const map = StaticStringMap(void).initEnum(TestEnum);
587 try testing.expect(map.has("A"));
588 try testing.expect(!map.has("a"));
589 try testing.expectEqual(0, map.getIndex("A"));
590 try testing.expectEqual(1, map.getIndex("B"));
591 try testing.expectEqual(2, map.getIndex("C"));
592 try testing.expectEqual(3, map.getIndex("D"));
593 try testing.expectEqual(4, map.getIndex("E"));
594 try testing.expectEqual(null, map.getIndex("F"));
595}
src/main.zig+212-142
...@@ -229,6 +229,57 @@ pub fn main(init: std.process.Init.Minimal) anyerror!void {...@@ -229,6 +229,57 @@ pub fn main(init: std.process.Init.Minimal) anyerror!void {
229 return mainArgs(gpa, arena, io, args, &environ_map);229 return mainArgs(gpa, arena, io, args, &environ_map);
230}230}
231231
232const cmd_map = std.StaticStringMap(void).initEnum(Cmd);
233
234const Cmd = enum {
235 @"build-exe",
236 @"build-lib",
237 @"build-obj",
238 @"test",
239 @"test-obj",
240 run,
241
242 dlltool,
243 ranlib,
244 lib,
245 ar,
246
247 build,
248
249 clang,
250 @"-cc1",
251 @"-cc1as",
252
253 @"ld.lld",
254 @"lld-link",
255 @"wasm-ld",
256
257 cc,
258 @"c++",
259 @"translate-c",
260 rc,
261 fmt,
262 objcopy,
263 objdump,
264 fetch,
265 libc,
266 std,
267 init,
268 targets,
269 version,
270 env,
271 reduce,
272 zen,
273 @"ast-check",
274
275 help,
276 @"-h",
277 @"--help",
278
279 changelist,
280 @"dump-zir",
281};
282
232fn mainArgs(283fn mainArgs(
233 gpa: Allocator,284 gpa: Allocator,
234 arena: Allocator,285 arena: Allocator,
...@@ -271,144 +322,169 @@ fn mainArgs(...@@ -271,144 +322,169 @@ fn mainArgs(
271322
272 const cmd = args[1];323 const cmd = args[1];
273 const cmd_args = args[2..];324 const cmd_args = args[2..];
274 if (mem.eql(u8, cmd, "build-exe")) {325 switch (@as(Cmd, @enumFromInt(cmd_map.getIndex(cmd) orelse {
275 dev.check(.build_exe_command);
276 return buildOutputType(gpa, arena, io, args, .{ .build = .Exe }, environ_map);
277 } else if (mem.eql(u8, cmd, "build-lib")) {
278 dev.check(.build_lib_command);
279 return buildOutputType(gpa, arena, io, args, .{ .build = .Lib }, environ_map);
280 } else if (mem.eql(u8, cmd, "build-obj")) {
281 dev.check(.build_obj_command);
282 return buildOutputType(gpa, arena, io, args, .{ .build = .Obj }, environ_map);
283 } else if (mem.eql(u8, cmd, "test")) {
284 dev.check(.test_command);
285 return buildOutputType(gpa, arena, io, args, .zig_test, environ_map);
286 } else if (mem.eql(u8, cmd, "test-obj")) {
287 dev.check(.test_command);
288 return buildOutputType(gpa, arena, io, args, .zig_test_obj, environ_map);
289 } else if (mem.eql(u8, cmd, "run")) {
290 dev.check(.run_command);
291 return buildOutputType(gpa, arena, io, args, .run, environ_map);
292 } else if (mem.eql(u8, cmd, "dlltool") or
293 mem.eql(u8, cmd, "ranlib") or
294 mem.eql(u8, cmd, "lib") or
295 mem.eql(u8, cmd, "ar"))
296 {
297 dev.check(.ar_command);
298 return process.exit(try llvmArMain(arena, args));
299 } else if (mem.eql(u8, cmd, "build")) {
300 dev.check(.build_command);
301 return cmdBuild(gpa, arena, io, cmd_args, environ_map);
302 } else if (mem.eql(u8, cmd, "clang") or
303 mem.eql(u8, cmd, "-cc1") or mem.eql(u8, cmd, "-cc1as"))
304 {
305 dev.check(.clang_command);
306 return process.exit(try clangMain(arena, args));
307 } else if (mem.eql(u8, cmd, "ld.lld") or
308 mem.eql(u8, cmd, "lld-link") or
309 mem.eql(u8, cmd, "wasm-ld"))
310 {
311 dev.check(.lld_linker);
312 return process.exit(try lldMain(arena, args, true));
313 } else if (mem.eql(u8, cmd, "cc")) {
314 dev.check(.cc_command);
315 return buildOutputType(gpa, arena, io, args, .cc, environ_map);
316 } else if (mem.eql(u8, cmd, "c++")) {
317 dev.check(.cc_command);
318 return buildOutputType(gpa, arena, io, args, .cpp, environ_map);
319 } else if (mem.eql(u8, cmd, "translate-c")) {
320 dev.check(.translate_c_command);
321 return buildOutputType(gpa, arena, io, args, .translate_c, environ_map);
322 } else if (mem.eql(u8, cmd, "rc")) {
323 const use_server = cmd_args.len > 0 and std.mem.eql(u8, cmd_args[0], "--zig-integration");
324 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
325 .cmd_name = "resinator",
326 .root_src_path = "resinator/main.zig",
327 .depend_on_aro = true,
328 .prepend_zig_lib_dir_path = true,
329 .server = use_server,
330 .color = Color.settingFromEnvironment(environ_map),
331 });
332 } else if (mem.eql(u8, cmd, "fmt")) {
333 dev.check(.fmt_command);
334 return @import("fmt.zig").run(gpa, arena, io, cmd_args);
335 } else if (mem.eql(u8, cmd, "objcopy")) {
336 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
337 .cmd_name = "objcopy",
338 .root_src_path = "objcopy.zig",
339 .color = Color.settingFromEnvironment(environ_map),
340 });
341 } else if (mem.eql(u8, cmd, "objdump")) {
342 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
343 .cmd_name = "objdump",
344 .root_src_path = "objdump.zig",
345 .color = Color.settingFromEnvironment(environ_map),
346 });
347 } else if (mem.eql(u8, cmd, "fetch")) {
348 return cmdFetch(gpa, arena, io, cmd_args, environ_map);
349 } else if (mem.eql(u8, cmd, "libc")) {
350 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
351 .cmd_name = "libc",
352 .root_src_path = "libc.zig",
353 .prepend_zig_lib_dir_path = true,
354 .color = Color.settingFromEnvironment(environ_map),
355 });
356 } else if (mem.eql(u8, cmd, "std")) {
357 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
358 .cmd_name = "std",
359 .root_src_path = "std-docs.zig",
360 .prepend_zig_lib_dir_path = true,
361 .prepend_zig_exe_path = true,
362 .prepend_global_cache_path = true,
363 .color = Color.settingFromEnvironment(environ_map),
364 });
365 } else if (mem.eql(u8, cmd, "init")) {
366 return cmdInit(gpa, arena, io, cmd_args);
367 } else if (mem.eql(u8, cmd, "targets")) {
368 dev.check(.targets_command);
369 const host = std.zig.resolveTargetQueryOrFatal(io, .{});
370 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
371 try @import("print_targets.zig").cmdTargets(arena, io, cmd_args, &stdout_writer.interface, &host);
372 return stdout_writer.interface.flush();
373 } else if (mem.eql(u8, cmd, "version")) {
374 dev.check(.version_command);
375 try Io.File.stdout().writeStreamingAll(io, build_options.version ++ "\n");
376 return;
377 } else if (mem.eql(u8, cmd, "env")) {
378 dev.check(.env_command);
379 const host = std.zig.resolveTargetQueryOrFatal(io, .{});
380 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
381 try @import("print_env.zig").cmdEnv(
382 arena,
383 io,
384 &stdout_writer.interface,
385 args,
386 preopens,
387 &host,
388 environ_map,
389 );
390 return stdout_writer.interface.flush();
391 } else if (mem.eql(u8, cmd, "reduce")) {
392 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
393 .cmd_name = "reduce",
394 .root_src_path = "reduce.zig",
395 .color = Color.settingFromEnvironment(environ_map),
396 });
397 } else if (mem.eql(u8, cmd, "zen")) {
398 dev.check(.zen_command);
399 return Io.File.stdout().writeStreamingAll(io, info_zen);
400 } else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) {
401 dev.check(.help_command);
402 return Io.File.stdout().writeStreamingAll(io, usage);
403 } else if (mem.eql(u8, cmd, "ast-check")) {
404 return cmdAstCheck(arena, io, cmd_args, environ_map);
405 } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "changelist")) {
406 return cmdChangelist(arena, io, cmd_args, environ_map);
407 } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "dump-zir")) {
408 return cmdDumpZir(arena, io, cmd_args);
409 } else {
410 std.log.info("{s}", .{usage});326 std.log.info("{s}", .{usage});
411 fatal("unknown command: {s}", .{args[1]});327 fatal("unknown command: {s}", .{args[1]});
328 }))) {
329 .@"build-exe" => {
330 dev.check(.build_exe_command);
331 return buildOutputType(gpa, arena, io, args, .{ .build = .Exe }, environ_map);
332 },
333 .@"build-lib" => {
334 dev.check(.build_lib_command);
335 return buildOutputType(gpa, arena, io, args, .{ .build = .Lib }, environ_map);
336 },
337 .@"build-obj" => {
338 dev.check(.build_obj_command);
339 return buildOutputType(gpa, arena, io, args, .{ .build = .Obj }, environ_map);
340 },
341 .@"test" => {
342 dev.check(.test_command);
343 return buildOutputType(gpa, arena, io, args, .zig_test, environ_map);
344 },
345 .@"test-obj" => {
346 dev.check(.test_command);
347 return buildOutputType(gpa, arena, io, args, .zig_test_obj, environ_map);
348 },
349 .run => {
350 dev.check(.run_command);
351 return buildOutputType(gpa, arena, io, args, .run, environ_map);
352 },
353 .dlltool, .ranlib, .lib, .ar => {
354 dev.check(.ar_command);
355 return process.exit(try llvmArMain(arena, args));
356 },
357 .build => {
358 dev.check(.build_command);
359 return cmdBuild(gpa, arena, io, cmd_args, environ_map);
360 },
361 .clang, .@"-cc1", .@"-cc1as" => {
362 dev.check(.clang_command);
363 return process.exit(try clangMain(arena, args));
364 },
365 .@"ld.lld", .@"lld-link", .@"wasm-ld" => {
366 dev.check(.lld_linker);
367 return process.exit(try lldMain(arena, args, true));
368 },
369 .cc => {
370 dev.check(.cc_command);
371 return buildOutputType(gpa, arena, io, args, .cc, environ_map);
372 },
373 .@"c++" => {
374 dev.check(.cc_command);
375 return buildOutputType(gpa, arena, io, args, .cpp, environ_map);
376 },
377 .@"translate-c" => {
378 dev.check(.translate_c_command);
379 return buildOutputType(gpa, arena, io, args, .translate_c, environ_map);
380 },
381 .rc => {
382 const use_server = cmd_args.len > 0 and std.mem.eql(u8, cmd_args[0], "--zig-integration");
383 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
384 .cmd_name = "resinator",
385 .root_src_path = "resinator/main.zig",
386 .depend_on_aro = true,
387 .prepend_zig_lib_dir_path = true,
388 .server = use_server,
389 .color = Color.settingFromEnvironment(environ_map),
390 });
391 },
392 .fmt => {
393 dev.check(.fmt_command);
394 return @import("fmt.zig").run(gpa, arena, io, cmd_args);
395 },
396 .objcopy => {
397 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
398 .cmd_name = "objcopy",
399 .root_src_path = "objcopy.zig",
400 .color = Color.settingFromEnvironment(environ_map),
401 });
402 },
403 .objdump => {
404 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
405 .cmd_name = "objdump",
406 .root_src_path = "objdump.zig",
407 .color = Color.settingFromEnvironment(environ_map),
408 });
409 },
410 .fetch => {
411 return cmdFetch(gpa, arena, io, cmd_args, environ_map);
412 },
413 .libc => {
414 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
415 .cmd_name = "libc",
416 .root_src_path = "libc.zig",
417 .prepend_zig_lib_dir_path = true,
418 .color = Color.settingFromEnvironment(environ_map),
419 });
420 },
421 .std => {
422 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
423 .cmd_name = "std",
424 .root_src_path = "std-docs.zig",
425 .prepend_zig_lib_dir_path = true,
426 .prepend_zig_exe_path = true,
427 .prepend_global_cache_path = true,
428 .color = Color.settingFromEnvironment(environ_map),
429 });
430 },
431 .init => {
432 return cmdInit(gpa, arena, io, cmd_args);
433 },
434 .targets => {
435 dev.check(.targets_command);
436 const host = std.zig.resolveTargetQueryOrFatal(io, .{});
437 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
438 try @import("print_targets.zig").cmdTargets(arena, io, cmd_args, &stdout_writer.interface, &host);
439 return stdout_writer.interface.flush();
440 },
441 .version => {
442 dev.check(.version_command);
443 try Io.File.stdout().writeStreamingAll(io, build_options.version ++ "\n");
444 return;
445 },
446 .env => {
447 dev.check(.env_command);
448 const host = std.zig.resolveTargetQueryOrFatal(io, .{});
449 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
450 try @import("print_env.zig").cmdEnv(
451 arena,
452 io,
453 &stdout_writer.interface,
454 args,
455 preopens,
456 &host,
457 environ_map,
458 );
459 return stdout_writer.interface.flush();
460 },
461 .reduce => {
462 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
463 .cmd_name = "reduce",
464 .root_src_path = "reduce.zig",
465 .color = Color.settingFromEnvironment(environ_map),
466 });
467 },
468 .zen => {
469 dev.check(.zen_command);
470 return Io.File.stdout().writeStreamingAll(io, info_zen);
471 },
472 .help, .@"-h", .@"--help" => {
473 dev.check(.help_command);
474 return Io.File.stdout().writeStreamingAll(io, usage);
475 },
476 .@"ast-check" => {
477 dev.check(.ast_check_command);
478 return cmdAstCheck(arena, io, cmd_args, environ_map);
479 },
480 .changelist => {
481 dev.check(.changelist_command);
482 return cmdChangelist(arena, io, cmd_args, environ_map);
483 },
484 .@"dump-zir" => {
485 dev.check(.dump_zir_command);
486 return cmdDumpZir(arena, io, cmd_args);
487 },
412 }488 }
413}489}
414490
...@@ -6537,8 +6613,6 @@ const usage_ast_check =...@@ -6537,8 +6613,6 @@ const usage_ast_check =
6537;6613;
65386614
6539fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map: *const std.process.Environ.Map) !void {6615fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map: *const std.process.Environ.Map) !void {
6540 dev.check(.ast_check_command);
6541
6542 const Zir = std.zig.Zir;6616 const Zir = std.zig.Zir;
65436617
6544 var color: Color = Color.settingFromEnvironment(environ_map);6618 var color: Color = Color.settingFromEnvironment(environ_map);
...@@ -6705,8 +6779,6 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:...@@ -6705,8 +6779,6 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:
67056779
6706/// This is only enabled for debug builds.6780/// This is only enabled for debug builds.
6707fn cmdDumpZir(arena: Allocator, io: Io, args: []const []const u8) !void {6781fn cmdDumpZir(arena: Allocator, io: Io, args: []const []const u8) !void {
6708 dev.check(.dump_zir_command);
6709
6710 const Zir = std.zig.Zir;6782 const Zir = std.zig.Zir;
67116783
6712 const cache_file = args[0];6784 const cache_file = args[0];
...@@ -6749,8 +6821,6 @@ fn cmdDumpZir(arena: Allocator, io: Io, args: []const []const u8) !void {...@@ -6749,8 +6821,6 @@ fn cmdDumpZir(arena: Allocator, io: Io, args: []const []const u8) !void {
67496821
6750/// This is only enabled for debug builds.6822/// This is only enabled for debug builds.
6751fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8, environ_map: *const std.process.Environ.Map) !void {6823fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8, environ_map: *const std.process.Environ.Map) !void {
6752 dev.check(.changelist_command);
6753
6754 const color: Color = Color.settingFromEnvironment(environ_map);6824 const color: Color = Color.settingFromEnvironment(environ_map);
6755 const Zir = std.zig.Zir;6825 const Zir = std.zig.Zir;
67566826