| ... | ... | @@ -50,6 +50,7 @@ const normal_usage = |
| 50 | 50 | \\ c++ Use Zig as a drop-in C++ compiler |
| 51 | 51 | \\ env Print lib path, std path, cache directory, and version |
| 52 | 52 | \\ fmt Reformat Zig source into canonical form |
| 53 | \\ ast-check Look for simple compile errors in any set of files |
| 53 | 54 | \\ help Print this help and exit |
| 54 | 55 | \\ init-exe Initialize a `zig build` application in the cwd |
| 55 | 56 | \\ init-lib Initialize a `zig build` library in the cwd |
| ... | ... | @@ -71,7 +72,6 @@ const debug_usage = normal_usage ++ |
| 71 | 72 | \\ |
| 72 | 73 | \\Debug Commands: |
| 73 | 74 | \\ |
| 74 | | \\ astgen Print ZIR code for a .zig source file |
| 75 | 75 | \\ changelist Compute mappings from old ZIR to new ZIR |
| 76 | 76 | \\ |
| 77 | 77 | ; |
| ... | ... | @@ -239,8 +239,8 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v |
| 239 | 239 | return io.getStdOut().writeAll(info_zen); |
| 240 | 240 | } else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) { |
| 241 | 241 | return io.getStdOut().writeAll(usage); |
| 242 | | } else if (debug_extensions_enabled and mem.eql(u8, cmd, "astgen")) { |
| 243 | | return cmdAstgen(gpa, arena, cmd_args); |
| 242 | } else if (mem.eql(u8, cmd, "ast-check")) { |
| 243 | return cmdAstCheck(gpa, arena, cmd_args); |
| 244 | 244 | } else if (debug_extensions_enabled and mem.eql(u8, cmd, "changelist")) { |
| 245 | 245 | return cmdChangelist(gpa, arena, cmd_args); |
| 246 | 246 | } else { |
| ... | ... | @@ -2246,7 +2246,8 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi |
| 2246 | 2246 | |
| 2247 | 2247 | if (errors.list.len != 0) { |
| 2248 | 2248 | const ttyconf: std.debug.TTY.Config = switch (comp.color) { |
| 2249 | | .auto, .on => std.debug.detectTTYConfig(), |
| 2249 | .auto => std.debug.detectTTYConfig(), |
| 2250 | .on => .escape_codes, |
| 2250 | 2251 | .off => .no_color, |
| 2251 | 2252 | }; |
| 2252 | 2253 | for (errors.list) |full_err_msg| { |
| ... | ... | @@ -2823,13 +2824,17 @@ fn argvCmd(allocator: *Allocator, argv: []const []const u8) ![]u8 { |
| 2823 | 2824 | return cmd.toOwnedSlice(); |
| 2824 | 2825 | } |
| 2825 | 2826 | |
| 2826 | | fn readSourceFileToEndAlloc(allocator: *mem.Allocator, input: *const fs.File, size_hint: ?usize) ![]const u8 { |
| 2827 | fn readSourceFileToEndAlloc( |
| 2828 | allocator: *mem.Allocator, |
| 2829 | input: *const fs.File, |
| 2830 | size_hint: ?usize, |
| 2831 | ) ![:0]u8 { |
| 2827 | 2832 | const source_code = input.readToEndAllocOptions( |
| 2828 | 2833 | allocator, |
| 2829 | 2834 | max_src_size, |
| 2830 | 2835 | size_hint, |
| 2831 | 2836 | @alignOf(u16), |
| 2832 | | null, |
| 2837 | 0, |
| 2833 | 2838 | ) catch |err| switch (err) { |
| 2834 | 2839 | error.ConnectionResetByPeer => unreachable, |
| 2835 | 2840 | error.ConnectionTimedOut => unreachable, |
| ... | ... | @@ -2853,7 +2858,7 @@ fn readSourceFileToEndAlloc(allocator: *mem.Allocator, input: *const fs.File, si |
| 2853 | 2858 | // If the file starts with a UTF-16 little endian BOM, translate it to UTF-8 |
| 2854 | 2859 | if (mem.startsWith(u8, source_code, "\xff\xfe")) { |
| 2855 | 2860 | const source_code_utf16_le = mem.bytesAsSlice(u16, source_code); |
| 2856 | | const source_code_utf8 = std.unicode.utf16leToUtf8Alloc(allocator, source_code_utf16_le) catch |err| switch (err) { |
| 2861 | const source_code_utf8 = std.unicode.utf16leToUtf8AllocZ(allocator, source_code_utf16_le) catch |err| switch (err) { |
| 2857 | 2862 | error.DanglingSurrogateHalf => error.UnsupportedEncoding, |
| 2858 | 2863 | error.ExpectedSecondSurrogateHalf => error.UnsupportedEncoding, |
| 2859 | 2864 | error.UnexpectedSecondSurrogateHalf => error.UnsupportedEncoding, |
| ... | ... | @@ -3562,8 +3567,22 @@ pub fn cleanExit() void { |
| 3562 | 3567 | } |
| 3563 | 3568 | } |
| 3564 | 3569 | |
| 3565 | | /// This is only enabled for debug builds. |
| 3566 | | pub fn cmdAstgen( |
| 3570 | const usage_ast_check = |
| 3571 | \\Usage: zig ast-check [file] |
| 3572 | \\ |
| 3573 | \\ Given a .zig source file, reports any compile errors that can be |
| 3574 | \\ ascertained on the basis of the source code alone, without target |
| 3575 | \\ information or type checking. |
| 3576 | \\ |
| 3577 | \\ If [file] is omitted, stdin is used. |
| 3578 | \\ |
| 3579 | \\Options: |
| 3580 | \\ -h, --help Print this help and exit |
| 3581 | \\ --color [auto|off|on] Enable or disable colored error messages |
| 3582 | \\ -t (debug option) Output ZIR in text form to stdout |
| 3583 | ; |
| 3584 | |
| 3585 | pub fn cmdAstCheck( |
| 3567 | 3586 | gpa: *Allocator, |
| 3568 | 3587 | arena: *Allocator, |
| 3569 | 3588 | args: []const []const u8, |
| ... | ... | @@ -3572,45 +3591,91 @@ pub fn cmdAstgen( |
| 3572 | 3591 | const AstGen = @import("AstGen.zig"); |
| 3573 | 3592 | const Zir = @import("Zir.zig"); |
| 3574 | 3593 | |
| 3575 | | const zig_source_file = args[0]; |
| 3576 | | |
| 3577 | | var f = try fs.cwd().openFile(zig_source_file, .{}); |
| 3578 | | defer f.close(); |
| 3579 | | |
| 3580 | | const stat = try f.stat(); |
| 3581 | | |
| 3582 | | if (stat.size > max_src_size) |
| 3583 | | return error.FileTooBig; |
| 3594 | var color: Color = .auto; |
| 3595 | var want_output_text = false; |
| 3596 | var have_zig_source_file = false; |
| 3597 | var zig_source_file: ?[]const u8 = null; |
| 3598 | |
| 3599 | var i: usize = 0; |
| 3600 | while (i < args.len) : (i += 1) { |
| 3601 | const arg = args[i]; |
| 3602 | if (mem.startsWith(u8, arg, "-")) { |
| 3603 | if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { |
| 3604 | try io.getStdOut().writeAll(usage_ast_check); |
| 3605 | return cleanExit(); |
| 3606 | } else if (mem.eql(u8, arg, "-t")) { |
| 3607 | want_output_text = true; |
| 3608 | } else if (mem.eql(u8, arg, "--color")) { |
| 3609 | if (i + 1 >= args.len) { |
| 3610 | fatal("expected [auto|on|off] after --color", .{}); |
| 3611 | } |
| 3612 | i += 1; |
| 3613 | const next_arg = args[i]; |
| 3614 | color = std.meta.stringToEnum(Color, next_arg) orelse { |
| 3615 | fatal("expected [auto|on|off] after --color, found '{s}'", .{next_arg}); |
| 3616 | }; |
| 3617 | } else { |
| 3618 | fatal("unrecognized parameter: '{s}'", .{arg}); |
| 3619 | } |
| 3620 | } else if (zig_source_file == null) { |
| 3621 | zig_source_file = arg; |
| 3622 | } else { |
| 3623 | fatal("extra positional parameter: '{s}'", .{arg}); |
| 3624 | } |
| 3625 | } |
| 3584 | 3626 | |
| 3585 | 3627 | var file: Module.Scope.File = .{ |
| 3586 | 3628 | .status = .never_loaded, |
| 3587 | 3629 | .source_loaded = false, |
| 3588 | 3630 | .tree_loaded = false, |
| 3589 | 3631 | .zir_loaded = false, |
| 3590 | | .sub_file_path = zig_source_file, |
| 3632 | .sub_file_path = undefined, |
| 3591 | 3633 | .source = undefined, |
| 3592 | | .stat_size = stat.size, |
| 3593 | | .stat_inode = stat.inode, |
| 3594 | | .stat_mtime = stat.mtime, |
| 3634 | .stat_size = undefined, |
| 3635 | .stat_inode = undefined, |
| 3636 | .stat_mtime = undefined, |
| 3595 | 3637 | .tree = undefined, |
| 3596 | 3638 | .zir = undefined, |
| 3597 | 3639 | .pkg = undefined, |
| 3598 | 3640 | .root_decl = null, |
| 3599 | 3641 | }; |
| 3600 | | |
| 3601 | | const source = try arena.allocSentinel(u8, stat.size, 0); |
| 3602 | | const amt = try f.readAll(source); |
| 3603 | | if (amt != stat.size) |
| 3604 | | return error.UnexpectedEndOfFile; |
| 3605 | | file.source = source; |
| 3606 | | file.source_loaded = true; |
| 3642 | if (zig_source_file) |file_name| { |
| 3643 | var f = try fs.cwd().openFile(file_name, .{}); |
| 3644 | defer f.close(); |
| 3645 | |
| 3646 | const stat = try f.stat(); |
| 3647 | |
| 3648 | if (stat.size > max_src_size) |
| 3649 | return error.FileTooBig; |
| 3650 | |
| 3651 | const source = try arena.allocSentinel(u8, stat.size, 0); |
| 3652 | const amt = try f.readAll(source); |
| 3653 | if (amt != stat.size) |
| 3654 | return error.UnexpectedEndOfFile; |
| 3655 | |
| 3656 | file.sub_file_path = file_name; |
| 3657 | file.source = source; |
| 3658 | file.source_loaded = true; |
| 3659 | file.stat_size = stat.size; |
| 3660 | file.stat_inode = stat.inode; |
| 3661 | file.stat_mtime = stat.mtime; |
| 3662 | } else { |
| 3663 | const stdin = io.getStdIn(); |
| 3664 | const source = readSourceFileToEndAlloc(arena, &stdin, null) catch |err| { |
| 3665 | fatal("unable to read stdin: {s}", .{err}); |
| 3666 | }; |
| 3667 | file.sub_file_path = "<stdin>"; |
| 3668 | file.source = source; |
| 3669 | file.source_loaded = true; |
| 3670 | file.stat_size = source.len; |
| 3671 | } |
| 3607 | 3672 | |
| 3608 | 3673 | file.tree = try std.zig.parse(gpa, file.source); |
| 3609 | 3674 | file.tree_loaded = true; |
| 3610 | 3675 | defer file.tree.deinit(gpa); |
| 3611 | 3676 | |
| 3612 | 3677 | for (file.tree.errors) |parse_error| { |
| 3613 | | try printErrMsgToFile(gpa, parse_error, file.tree, zig_source_file, io.getStdErr(), .auto); |
| 3678 | try printErrMsgToFile(gpa, parse_error, file.tree, file.sub_file_path, io.getStdErr(), color); |
| 3614 | 3679 | } |
| 3615 | 3680 | if (file.tree.errors.len != 0) { |
| 3616 | 3681 | process.exit(1); |
| ... | ... | @@ -3620,6 +3685,27 @@ pub fn cmdAstgen( |
| 3620 | 3685 | file.zir_loaded = true; |
| 3621 | 3686 | defer file.zir.deinit(gpa); |
| 3622 | 3687 | |
| 3688 | if (file.zir.hasCompileErrors()) { |
| 3689 | var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena); |
| 3690 | try Compilation.AllErrors.addZir(arena, &errors, &file); |
| 3691 | const ttyconf: std.debug.TTY.Config = switch (color) { |
| 3692 | .auto => std.debug.detectTTYConfig(), |
| 3693 | .on => .escape_codes, |
| 3694 | .off => .no_color, |
| 3695 | }; |
| 3696 | for (errors.items) |full_err_msg| { |
| 3697 | full_err_msg.renderToStdErr(ttyconf); |
| 3698 | } |
| 3699 | process.exit(1); |
| 3700 | } |
| 3701 | |
| 3702 | if (!want_output_text) { |
| 3703 | return cleanExit(); |
| 3704 | } |
| 3705 | if (!debug_extensions_enabled) { |
| 3706 | fatal("-t option only available in debug builds of zig", .{}); |
| 3707 | } |
| 3708 | |
| 3623 | 3709 | { |
| 3624 | 3710 | const token_bytes = @sizeOf(std.zig.ast.TokenList) + |
| 3625 | 3711 | file.tree.tokens.len * (@sizeOf(std.zig.Token.Tag) + @sizeOf(std.zig.ast.ByteOffset)); |
| ... | ... | @@ -3647,7 +3733,7 @@ pub fn cmdAstgen( |
| 3647 | 3733 | \\# Extra Data Items: {d} ({}) |
| 3648 | 3734 | \\ |
| 3649 | 3735 | , .{ |
| 3650 | | fmtIntSizeBin(source.len), |
| 3736 | fmtIntSizeBin(file.source.len), |
| 3651 | 3737 | file.tree.tokens.len, fmtIntSizeBin(token_bytes), |
| 3652 | 3738 | file.tree.nodes.len, fmtIntSizeBin(tree_bytes), |
| 3653 | 3739 | fmtIntSizeBin(total_bytes), |
| ... | ... | @@ -3658,16 +3744,6 @@ pub fn cmdAstgen( |
| 3658 | 3744 | // zig fmt: on |
| 3659 | 3745 | } |
| 3660 | 3746 | |
| 3661 | | if (file.zir.hasCompileErrors()) { |
| 3662 | | var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena); |
| 3663 | | try Compilation.AllErrors.addZir(arena, &errors, &file); |
| 3664 | | const ttyconf = std.debug.detectTTYConfig(); |
| 3665 | | for (errors.items) |full_err_msg| { |
| 3666 | | full_err_msg.renderToStdErr(ttyconf); |
| 3667 | | } |
| 3668 | | process.exit(1); |
| 3669 | | } |
| 3670 | | |
| 3671 | 3747 | return Zir.renderAsTextToFile(gpa, &file, io.getStdOut()); |
| 3672 | 3748 | } |
| 3673 | 3749 | |