| ... | @@ -365,7 +365,6 @@ const usage_build_generic = | ... | @@ -365,7 +365,6 @@ const usage_build_generic = |
| 365 | \\ | 365 | \\ |
| 366 | \\General Options: | 366 | \\General Options: |
| 367 | \\ -h, --help Print this help and exit | 367 | \\ -h, --help Print this help and exit |
| 368 | \\ --watch Enable compiler REPL | | |
| 369 | \\ --color [auto|off|on] Enable or disable colored error messages | 368 | \\ --color [auto|off|on] Enable or disable colored error messages |
| 370 | \\ -femit-bin[=path] (default) Output machine code | 369 | \\ -femit-bin[=path] (default) Output machine code |
| 371 | \\ -fno-emit-bin Do not output machine code | 370 | \\ -fno-emit-bin Do not output machine code |
| ... | @@ -700,7 +699,6 @@ fn buildOutputType( | ... | @@ -700,7 +699,6 @@ fn buildOutputType( |
| 700 | var formatted_panics: ?bool = null; | 699 | var formatted_panics: ?bool = null; |
| 701 | var function_sections = false; | 700 | var function_sections = false; |
| 702 | var no_builtin = false; | 701 | var no_builtin = false; |
| 703 | var watch = false; | | |
| 704 | var listen: Listen = .none; | 702 | var listen: Listen = .none; |
| 705 | var debug_compile_errors = false; | 703 | var debug_compile_errors = false; |
| 706 | var verbose_link = (builtin.os.tag != .wasi or builtin.link_libc) and std.process.hasEnvVarConstant("ZIG_VERBOSE_LINK"); | 704 | var verbose_link = (builtin.os.tag != .wasi or builtin.link_libc) and std.process.hasEnvVarConstant("ZIG_VERBOSE_LINK"); |
| ... | @@ -1163,7 +1161,6 @@ fn buildOutputType( | ... | @@ -1163,7 +1161,6 @@ fn buildOutputType( |
| 1163 | const next_arg = args_iter.nextOrFatal(); | 1161 | const next_arg = args_iter.nextOrFatal(); |
| 1164 | if (mem.eql(u8, next_arg, "-")) { | 1162 | if (mem.eql(u8, next_arg, "-")) { |
| 1165 | listen = .stdio; | 1163 | listen = .stdio; |
| 1166 | watch = true; | | |
| 1167 | } else { | 1164 | } else { |
| 1168 | if (build_options.omit_pkg_fetching_code) unreachable; | 1165 | if (build_options.omit_pkg_fetching_code) unreachable; |
| 1169 | // example: --listen 127.0.0.1:9000 | 1166 | // example: --listen 127.0.0.1:9000 |
| ... | @@ -1174,11 +1171,9 @@ fn buildOutputType( | ... | @@ -1174,11 +1171,9 @@ fn buildOutputType( |
| 1174 | fatal("invalid port number: '{s}': {s}", .{ port_text, @errorName(err) }); | 1171 | fatal("invalid port number: '{s}': {s}", .{ port_text, @errorName(err) }); |
| 1175 | listen = .{ .ip4 = std.net.Ip4Address.parse(host, port) catch |err| | 1172 | listen = .{ .ip4 = std.net.Ip4Address.parse(host, port) catch |err| |
| 1176 | fatal("invalid host: '{s}': {s}", .{ host, @errorName(err) }) }; | 1173 | fatal("invalid host: '{s}': {s}", .{ host, @errorName(err) }) }; |
| 1177 | watch = true; | | |
| 1178 | } | 1174 | } |
| 1179 | } else if (mem.eql(u8, arg, "--listen=-")) { | 1175 | } else if (mem.eql(u8, arg, "--listen=-")) { |
| 1180 | listen = .stdio; | 1176 | listen = .stdio; |
| 1181 | watch = true; | | |
| 1182 | } else if (mem.eql(u8, arg, "--debug-link-snapshot")) { | 1177 | } else if (mem.eql(u8, arg, "--debug-link-snapshot")) { |
| 1183 | if (!build_options.enable_link_snapshots) { | 1178 | if (!build_options.enable_link_snapshots) { |
| 1184 | std.log.warn("Zig was compiled without linker snapshots enabled (-Dlink-snapshot). --debug-link-snapshot has no effect.", .{}); | 1179 | std.log.warn("Zig was compiled without linker snapshots enabled (-Dlink-snapshot). --debug-link-snapshot has no effect.", .{}); |
| ... | @@ -1207,8 +1202,6 @@ fn buildOutputType( | ... | @@ -1207,8 +1202,6 @@ fn buildOutputType( |
| 1207 | test_evented_io = true; | 1202 | test_evented_io = true; |
| 1208 | } else if (mem.eql(u8, arg, "--test-no-exec")) { | 1203 | } else if (mem.eql(u8, arg, "--test-no-exec")) { |
| 1209 | test_no_exec = true; | 1204 | test_no_exec = true; |
| 1210 | } else if (mem.eql(u8, arg, "--watch")) { | | |
| 1211 | watch = true; | | |
| 1212 | } else if (mem.eql(u8, arg, "-ftime-report")) { | 1205 | } else if (mem.eql(u8, arg, "-ftime-report")) { |
| 1213 | time_report = true; | 1206 | time_report = true; |
| 1214 | } else if (mem.eql(u8, arg, "-fstack-report")) { | 1207 | } else if (mem.eql(u8, arg, "-fstack-report")) { |
| ... | @@ -3355,7 +3348,7 @@ fn buildOutputType( | ... | @@ -3355,7 +3348,7 @@ fn buildOutputType( |
| 3355 | }; | 3348 | }; |
| 3356 | | 3349 | |
| 3357 | updateModule(gpa, comp, hook) catch |err| switch (err) { | 3350 | 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), |
| 3359 | else => |e| return e, | 3352 | else => |e| return e, |
| 3360 | }; | 3353 | }; |
| 3361 | if (build_options.only_c) return cleanExit(); | 3354 | if (build_options.only_c) return cleanExit(); |
| ... | @@ -3411,7 +3404,6 @@ fn buildOutputType( | ... | @@ -3411,7 +3404,6 @@ fn buildOutputType( |
| 3411 | self_exe_path.?, | 3404 | self_exe_path.?, |
| 3412 | arg_mode, | 3405 | arg_mode, |
| 3413 | target_info, | 3406 | target_info, |
| 3414 | watch, | | |
| 3415 | &comp_destroyed, | 3407 | &comp_destroyed, |
| 3416 | all_args, | 3408 | all_args, |
| 3417 | runtime_args_start, | 3409 | runtime_args_start, |
| ... | @@ -3419,113 +3411,6 @@ fn buildOutputType( | ... | @@ -3419,113 +3411,6 @@ fn buildOutputType( |
| 3419 | ); | 3411 | ); |
| 3420 | } | 3412 | } |
| 3421 | | 3413 | |
| 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 | } | | |
| 3529 | // Skip resource deallocation in release builds; let the OS do it. | 3414 | // Skip resource deallocation in release builds; let the OS do it. |
| 3530 | return cleanExit(); | 3415 | return cleanExit(); |
| 3531 | } | 3416 | } |
| ... | @@ -3822,7 +3707,6 @@ fn runOrTest( | ... | @@ -3822,7 +3707,6 @@ fn runOrTest( |
| 3822 | self_exe_path: []const u8, | 3707 | self_exe_path: []const u8, |
| 3823 | arg_mode: ArgMode, | 3708 | arg_mode: ArgMode, |
| 3824 | target_info: std.zig.system.NativeTargetInfo, | 3709 | target_info: std.zig.system.NativeTargetInfo, |
| 3825 | watch: bool, | | |
| 3826 | comp_destroyed: *bool, | 3710 | comp_destroyed: *bool, |
| 3827 | all_args: []const []const u8, | 3711 | all_args: []const []const u8, |
| 3828 | runtime_args_start: ?usize, | 3712 | runtime_args_start: ?usize, |
| ... | @@ -3853,7 +3737,7 @@ fn runOrTest( | ... | @@ -3853,7 +3737,7 @@ fn runOrTest( |
| 3853 | | 3737 | |
| 3854 | // We do not execve for tests because if the test fails we want to print | 3738 | // We do not execve for tests because if the test fails we want to print |
| 3855 | // the error message and invocation below. | 3739 | // 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) { |
| 3857 | // execv releases the locks; no need to destroy the Compilation here. | 3741 | // execv releases the locks; no need to destroy the Compilation here. |
| 3858 | const err = std.process.execve(gpa, argv.items, &env_map); | 3742 | const err = std.process.execve(gpa, argv.items, &env_map); |
| 3859 | try warnAboutForeignBinaries(arena, arg_mode, target_info, link_libc); | 3743 | try warnAboutForeignBinaries(arena, arg_mode, target_info, link_libc); |
| ... | @@ -3866,12 +3750,10 @@ fn runOrTest( | ... | @@ -3866,12 +3750,10 @@ fn runOrTest( |
| 3866 | child.stdout_behavior = .Inherit; | 3750 | child.stdout_behavior = .Inherit; |
| 3867 | child.stderr_behavior = .Inherit; | 3751 | child.stderr_behavior = .Inherit; |
| 3868 | | 3752 | |
| 3869 | if (!watch) { | 3753 | // Here we release all the locks associated with the Compilation so |
| 3870 | // Here we release all the locks associated with the Compilation so | 3754 | // that whatever this child process wants to do won't deadlock. |
| 3871 | // that whatever this child process wants to do won't deadlock. | 3755 | comp.destroy(); |
| 3872 | comp.destroy(); | 3756 | comp_destroyed.* = true; |
| 3873 | comp_destroyed.* = true; | | |
| 3874 | } | | |
| 3875 | | 3757 | |
| 3876 | const term = child.spawnAndWait() catch |err| { | 3758 | const term = child.spawnAndWait() catch |err| { |
| 3877 | try warnAboutForeignBinaries(arena, arg_mode, target_info, link_libc); | 3759 | try warnAboutForeignBinaries(arena, arg_mode, target_info, link_libc); |
| ... | @@ -3883,19 +3765,13 @@ fn runOrTest( | ... | @@ -3883,19 +3765,13 @@ fn runOrTest( |
| 3883 | switch (term) { | 3765 | switch (term) { |
| 3884 | .Exited => |code| { | 3766 | .Exited => |code| { |
| 3885 | if (code == 0) { | 3767 | if (code == 0) { |
| 3886 | if (!watch) return cleanExit(); | 3768 | return cleanExit(); |
| 3887 | } else if (watch) { | | |
| 3888 | warn("process exited with code {d}", .{code}); | | |
| 3889 | } else { | 3769 | } else { |
| 3890 | process.exit(code); | 3770 | process.exit(code); |
| 3891 | } | 3771 | } |
| 3892 | }, | 3772 | }, |
| 3893 | else => { | 3773 | else => { |
| 3894 | if (watch) { | 3774 | process.exit(1); |
| 3895 | warn("process aborted abnormally", .{}); | | |
| 3896 | } else { | | |
| 3897 | process.exit(1); | | |
| 3898 | } | | |
| 3899 | }, | 3775 | }, |
| 3900 | } | 3776 | } |
| 3901 | }, | 3777 | }, |
| ... | @@ -3903,7 +3779,7 @@ fn runOrTest( | ... | @@ -3903,7 +3779,7 @@ fn runOrTest( |
| 3903 | switch (term) { | 3779 | switch (term) { |
| 3904 | .Exited => |code| { | 3780 | .Exited => |code| { |
| 3905 | if (code == 0) { | 3781 | if (code == 0) { |
| 3906 | if (!watch) return cleanExit(); | 3782 | return cleanExit(); |
| 3907 | } else { | 3783 | } else { |
| 3908 | const cmd = try std.mem.join(arena, " ", argv.items); | 3784 | const cmd = try std.mem.join(arena, " ", argv.items); |
| 3909 | fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd }); | 3785 | fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd }); |