authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-13 19:11:36-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-15 10:48:15-07:00
logbde12930939c50fbfa344c3701a01885e6dd06d4
treee0dee4ad74167e03bd5ec10e587925741d183067
parent0f88ad8c72797b1bc8899e2eb1d1c1c07a39addf

CLI: remove the experimental --watch flag

The compiler REPL will move to an external process that communicates with the compiler over the binary protocol.

1 files changed, 9 insertions(+), 133 deletions(-)

src/main.zig+9-133
......@@ -365,7 +365,6 @@ const usage_build_generic =
365365 \\
366366 \\General Options:
367367 \\ -h, --help Print this help and exit
368 \\ --watch Enable compiler REPL
369368 \\ --color [auto|off|on] Enable or disable colored error messages
370369 \\ -femit-bin[=path] (default) Output machine code
371370 \\ -fno-emit-bin Do not output machine code
......@@ -700,7 +699,6 @@ fn buildOutputType(
700699 var formatted_panics: ?bool = null;
701700 var function_sections = false;
702701 var no_builtin = false;
703 var watch = false;
704702 var listen: Listen = .none;
705703 var debug_compile_errors = false;
706704 var verbose_link = (builtin.os.tag != .wasi or builtin.link_libc) and std.process.hasEnvVarConstant("ZIG_VERBOSE_LINK");
......@@ -1163,7 +1161,6 @@ fn buildOutputType(
11631161 const next_arg = args_iter.nextOrFatal();
11641162 if (mem.eql(u8, next_arg, "-")) {
11651163 listen = .stdio;
1166 watch = true;
11671164 } else {
11681165 if (build_options.omit_pkg_fetching_code) unreachable;
11691166 // example: --listen 127.0.0.1:9000
......@@ -1174,11 +1171,9 @@ fn buildOutputType(
11741171 fatal("invalid port number: '{s}': {s}", .{ port_text, @errorName(err) });
11751172 listen = .{ .ip4 = std.net.Ip4Address.parse(host, port) catch |err|
11761173 fatal("invalid host: '{s}': {s}", .{ host, @errorName(err) }) };
1177 watch = true;
11781174 }
11791175 } else if (mem.eql(u8, arg, "--listen=-")) {
11801176 listen = .stdio;
1181 watch = true;
11821177 } else if (mem.eql(u8, arg, "--debug-link-snapshot")) {
11831178 if (!build_options.enable_link_snapshots) {
11841179 std.log.warn("Zig was compiled without linker snapshots enabled (-Dlink-snapshot). --debug-link-snapshot has no effect.", .{});
......@@ -1207,8 +1202,6 @@ fn buildOutputType(
12071202 test_evented_io = true;
12081203 } else if (mem.eql(u8, arg, "--test-no-exec")) {
12091204 test_no_exec = true;
1210 } else if (mem.eql(u8, arg, "--watch")) {
1211 watch = true;
12121205 } else if (mem.eql(u8, arg, "-ftime-report")) {
12131206 time_report = true;
12141207 } else if (mem.eql(u8, arg, "-fstack-report")) {
......@@ -3355,7 +3348,7 @@ fn buildOutputType(
33553348 };
33563349
33573350 updateModule(gpa, comp, hook) catch |err| switch (err) {
3358 error.SemanticAnalyzeFail => if (!watch) process.exit(1),
3351 error.SemanticAnalyzeFail => if (listen == .none) process.exit(1),
33593352 else => |e| return e,
33603353 };
33613354 if (build_options.only_c) return cleanExit();
......@@ -3411,7 +3404,6 @@ fn buildOutputType(
34113404 self_exe_path.?,
34123405 arg_mode,
34133406 target_info,
3414 watch,
34153407 &comp_destroyed,
34163408 all_args,
34173409 runtime_args_start,
......@@ -3419,113 +3411,6 @@ fn buildOutputType(
34193411 );
34203412 }
34213413
3422 // TODO move this REPL implementation to the standard library / build
3423 // system and have it be a CLI abstraction layer on top of the real, actual
3424 // binary protocol of the compiler. Make it actually interface through the
3425 // server protocol. This way the REPL does not have any special powers that
3426 // an IDE couldn't also have.
3427
3428 const stdin = std.io.getStdIn().reader();
3429 const stderr = std.io.getStdErr().writer();
3430 var repl_buf: [1024]u8 = undefined;
3431
3432 const ReplCmd = enum {
3433 update,
3434 help,
3435 run,
3436 update_and_run,
3437 };
3438
3439 var last_cmd: ReplCmd = .help;
3440
3441 while (watch) {
3442 try stderr.print("(zig) ", .{});
3443 try comp.makeBinFileExecutable();
3444 if (stdin.readUntilDelimiterOrEof(&repl_buf, '\n') catch |err| {
3445 try stderr.print("\nUnable to parse command: {s}\n", .{@errorName(err)});
3446 continue;
3447 }) |line| {
3448 const actual_line = mem.trimRight(u8, line, "\r\n ");
3449 const cmd: ReplCmd = blk: {
3450 if (mem.eql(u8, actual_line, "update")) {
3451 break :blk .update;
3452 } else if (mem.eql(u8, actual_line, "exit")) {
3453 break;
3454 } else if (mem.eql(u8, actual_line, "help")) {
3455 break :blk .help;
3456 } else if (mem.eql(u8, actual_line, "run")) {
3457 break :blk .run;
3458 } else if (mem.eql(u8, actual_line, "update-and-run")) {
3459 break :blk .update_and_run;
3460 } else if (actual_line.len == 0) {
3461 break :blk last_cmd;
3462 } else {
3463 try stderr.print("unknown command: {s}\n", .{actual_line});
3464 continue;
3465 }
3466 };
3467 last_cmd = cmd;
3468 switch (cmd) {
3469 .update => {
3470 tracy.frameMark();
3471 if (output_mode == .Exe) {
3472 try comp.makeBinFileWritable();
3473 }
3474 updateModule(gpa, comp, hook) catch |err| switch (err) {
3475 error.SemanticAnalyzeFail => continue,
3476 else => |e| return e,
3477 };
3478 },
3479 .help => {
3480 try stderr.writeAll(repl_help);
3481 },
3482 .run => {
3483 tracy.frameMark();
3484 try runOrTest(
3485 comp,
3486 gpa,
3487 arena,
3488 test_exec_args.items,
3489 self_exe_path.?,
3490 arg_mode,
3491 target_info,
3492 watch,
3493 &comp_destroyed,
3494 all_args,
3495 runtime_args_start,
3496 link_libc,
3497 );
3498 },
3499 .update_and_run => {
3500 tracy.frameMark();
3501 if (output_mode == .Exe) {
3502 try comp.makeBinFileWritable();
3503 }
3504 updateModule(gpa, comp, hook) catch |err| switch (err) {
3505 error.SemanticAnalyzeFail => continue,
3506 else => |e| return e,
3507 };
3508 try comp.makeBinFileExecutable();
3509 try runOrTest(
3510 comp,
3511 gpa,
3512 arena,
3513 test_exec_args.items,
3514 self_exe_path.?,
3515 arg_mode,
3516 target_info,
3517 watch,
3518 &comp_destroyed,
3519 all_args,
3520 runtime_args_start,
3521 link_libc,
3522 );
3523 },
3524 }
3525 } else {
3526 break;
3527 }
3528 }
35293414 // Skip resource deallocation in release builds; let the OS do it.
35303415 return cleanExit();
35313416}
......@@ -3822,7 +3707,6 @@ fn runOrTest(
38223707 self_exe_path: []const u8,
38233708 arg_mode: ArgMode,
38243709 target_info: std.zig.system.NativeTargetInfo,
3825 watch: bool,
38263710 comp_destroyed: *bool,
38273711 all_args: []const []const u8,
38283712 runtime_args_start: ?usize,
......@@ -3853,7 +3737,7 @@ fn runOrTest(
38533737
38543738 // We do not execve for tests because if the test fails we want to print
38553739 // the error message and invocation below.
3856 if (std.process.can_execv and arg_mode == .run and !watch) {
3740 if (std.process.can_execv and arg_mode == .run) {
38573741 // execv releases the locks; no need to destroy the Compilation here.
38583742 const err = std.process.execve(gpa, argv.items, &env_map);
38593743 try warnAboutForeignBinaries(arena, arg_mode, target_info, link_libc);
......@@ -3866,12 +3750,10 @@ fn runOrTest(
38663750 child.stdout_behavior = .Inherit;
38673751 child.stderr_behavior = .Inherit;
38683752
3869 if (!watch) {
3870 // Here we release all the locks associated with the Compilation so
3871 // that whatever this child process wants to do won't deadlock.
3872 comp.destroy();
3873 comp_destroyed.* = true;
3874 }
3753 // Here we release all the locks associated with the Compilation so
3754 // that whatever this child process wants to do won't deadlock.
3755 comp.destroy();
3756 comp_destroyed.* = true;
38753757
38763758 const term = child.spawnAndWait() catch |err| {
38773759 try warnAboutForeignBinaries(arena, arg_mode, target_info, link_libc);
......@@ -3883,19 +3765,13 @@ fn runOrTest(
38833765 switch (term) {
38843766 .Exited => |code| {
38853767 if (code == 0) {
3886 if (!watch) return cleanExit();
3887 } else if (watch) {
3888 warn("process exited with code {d}", .{code});
3768 return cleanExit();
38893769 } else {
38903770 process.exit(code);
38913771 }
38923772 },
38933773 else => {
3894 if (watch) {
3895 warn("process aborted abnormally", .{});
3896 } else {
3897 process.exit(1);
3898 }
3774 process.exit(1);
38993775 },
39003776 }
39013777 },
......@@ -3903,7 +3779,7 @@ fn runOrTest(
39033779 switch (term) {
39043780 .Exited => |code| {
39053781 if (code == 0) {
3906 if (!watch) return cleanExit();
3782 return cleanExit();
39073783 } else {
39083784 const cmd = try std.mem.join(arena, " ", argv.items);
39093785 fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd });