Commit b750e074c6
Changed files (1)
src
src/main.zig
@@ -50,6 +50,7 @@ const normal_usage =
\\ c++ Use Zig as a drop-in C++ compiler
\\ env Print lib path, std path, cache directory, and version
\\ fmt Reformat Zig source into canonical form
+ \\ ast-check Look for simple compile errors in any set of files
\\ help Print this help and exit
\\ init-exe Initialize a `zig build` application in the cwd
\\ init-lib Initialize a `zig build` library in the cwd
@@ -71,7 +72,6 @@ const debug_usage = normal_usage ++
\\
\\Debug Commands:
\\
- \\ astgen Print ZIR code for a .zig source file
\\ changelist Compute mappings from old ZIR to new ZIR
\\
;
@@ -239,8 +239,8 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
return io.getStdOut().writeAll(info_zen);
} else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) {
return io.getStdOut().writeAll(usage);
- } else if (debug_extensions_enabled and mem.eql(u8, cmd, "astgen")) {
- return cmdAstgen(gpa, arena, cmd_args);
+ } else if (mem.eql(u8, cmd, "ast-check")) {
+ return cmdAstCheck(gpa, arena, cmd_args);
} else if (debug_extensions_enabled and mem.eql(u8, cmd, "changelist")) {
return cmdChangelist(gpa, arena, cmd_args);
} else {
@@ -2246,7 +2246,8 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi
if (errors.list.len != 0) {
const ttyconf: std.debug.TTY.Config = switch (comp.color) {
- .auto, .on => std.debug.detectTTYConfig(),
+ .auto => std.debug.detectTTYConfig(),
+ .on => .escape_codes,
.off => .no_color,
};
for (errors.list) |full_err_msg| {
@@ -2823,13 +2824,17 @@ fn argvCmd(allocator: *Allocator, argv: []const []const u8) ![]u8 {
return cmd.toOwnedSlice();
}
-fn readSourceFileToEndAlloc(allocator: *mem.Allocator, input: *const fs.File, size_hint: ?usize) ![]const u8 {
+fn readSourceFileToEndAlloc(
+ allocator: *mem.Allocator,
+ input: *const fs.File,
+ size_hint: ?usize,
+) ![:0]u8 {
const source_code = input.readToEndAllocOptions(
allocator,
max_src_size,
size_hint,
@alignOf(u16),
- null,
+ 0,
) catch |err| switch (err) {
error.ConnectionResetByPeer => unreachable,
error.ConnectionTimedOut => unreachable,
@@ -2853,7 +2858,7 @@ fn readSourceFileToEndAlloc(allocator: *mem.Allocator, input: *const fs.File, si
// If the file starts with a UTF-16 little endian BOM, translate it to UTF-8
if (mem.startsWith(u8, source_code, "\xff\xfe")) {
const source_code_utf16_le = mem.bytesAsSlice(u16, source_code);
- const source_code_utf8 = std.unicode.utf16leToUtf8Alloc(allocator, source_code_utf16_le) catch |err| switch (err) {
+ const source_code_utf8 = std.unicode.utf16leToUtf8AllocZ(allocator, source_code_utf16_le) catch |err| switch (err) {
error.DanglingSurrogateHalf => error.UnsupportedEncoding,
error.ExpectedSecondSurrogateHalf => error.UnsupportedEncoding,
error.UnexpectedSecondSurrogateHalf => error.UnsupportedEncoding,
@@ -3562,8 +3567,22 @@ pub fn cleanExit() void {
}
}
-/// This is only enabled for debug builds.
-pub fn cmdAstgen(
+const usage_ast_check =
+ \\Usage: zig ast-check [file]
+ \\
+ \\ Given a .zig source file, reports any compile errors that can be
+ \\ ascertained on the basis of the source code alone, without target
+ \\ information or type checking.
+ \\
+ \\ If [file] is omitted, stdin is used.
+ \\
+ \\Options:
+ \\ -h, --help Print this help and exit
+ \\ --color [auto|off|on] Enable or disable colored error messages
+ \\ -t (debug option) Output ZIR in text form to stdout
+;
+
+pub fn cmdAstCheck(
gpa: *Allocator,
arena: *Allocator,
args: []const []const u8,
@@ -3572,45 +3591,91 @@ pub fn cmdAstgen(
const AstGen = @import("AstGen.zig");
const Zir = @import("Zir.zig");
- const zig_source_file = args[0];
-
- var f = try fs.cwd().openFile(zig_source_file, .{});
- defer f.close();
-
- const stat = try f.stat();
-
- if (stat.size > max_src_size)
- return error.FileTooBig;
+ var color: Color = .auto;
+ var want_output_text = false;
+ var have_zig_source_file = false;
+ var zig_source_file: ?[]const u8 = null;
+
+ var i: usize = 0;
+ while (i < args.len) : (i += 1) {
+ const arg = args[i];
+ if (mem.startsWith(u8, arg, "-")) {
+ if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
+ try io.getStdOut().writeAll(usage_ast_check);
+ return cleanExit();
+ } else if (mem.eql(u8, arg, "-t")) {
+ want_output_text = true;
+ } else if (mem.eql(u8, arg, "--color")) {
+ if (i + 1 >= args.len) {
+ fatal("expected [auto|on|off] after --color", .{});
+ }
+ i += 1;
+ const next_arg = args[i];
+ color = std.meta.stringToEnum(Color, next_arg) orelse {
+ fatal("expected [auto|on|off] after --color, found '{s}'", .{next_arg});
+ };
+ } else {
+ fatal("unrecognized parameter: '{s}'", .{arg});
+ }
+ } else if (zig_source_file == null) {
+ zig_source_file = arg;
+ } else {
+ fatal("extra positional parameter: '{s}'", .{arg});
+ }
+ }
var file: Module.Scope.File = .{
.status = .never_loaded,
.source_loaded = false,
.tree_loaded = false,
.zir_loaded = false,
- .sub_file_path = zig_source_file,
+ .sub_file_path = undefined,
.source = undefined,
- .stat_size = stat.size,
- .stat_inode = stat.inode,
- .stat_mtime = stat.mtime,
+ .stat_size = undefined,
+ .stat_inode = undefined,
+ .stat_mtime = undefined,
.tree = undefined,
.zir = undefined,
.pkg = undefined,
.root_decl = null,
};
-
- const source = try arena.allocSentinel(u8, stat.size, 0);
- const amt = try f.readAll(source);
- if (amt != stat.size)
- return error.UnexpectedEndOfFile;
- file.source = source;
- file.source_loaded = true;
+ if (zig_source_file) |file_name| {
+ var f = try fs.cwd().openFile(file_name, .{});
+ defer f.close();
+
+ const stat = try f.stat();
+
+ if (stat.size > max_src_size)
+ return error.FileTooBig;
+
+ const source = try arena.allocSentinel(u8, stat.size, 0);
+ const amt = try f.readAll(source);
+ if (amt != stat.size)
+ return error.UnexpectedEndOfFile;
+
+ file.sub_file_path = file_name;
+ file.source = source;
+ file.source_loaded = true;
+ file.stat_size = stat.size;
+ file.stat_inode = stat.inode;
+ file.stat_mtime = stat.mtime;
+ } else {
+ const stdin = io.getStdIn();
+ const source = readSourceFileToEndAlloc(arena, &stdin, null) catch |err| {
+ fatal("unable to read stdin: {s}", .{err});
+ };
+ file.sub_file_path = "<stdin>";
+ file.source = source;
+ file.source_loaded = true;
+ file.stat_size = source.len;
+ }
file.tree = try std.zig.parse(gpa, file.source);
file.tree_loaded = true;
defer file.tree.deinit(gpa);
for (file.tree.errors) |parse_error| {
- try printErrMsgToFile(gpa, parse_error, file.tree, zig_source_file, io.getStdErr(), .auto);
+ try printErrMsgToFile(gpa, parse_error, file.tree, file.sub_file_path, io.getStdErr(), color);
}
if (file.tree.errors.len != 0) {
process.exit(1);
@@ -3620,6 +3685,27 @@ pub fn cmdAstgen(
file.zir_loaded = true;
defer file.zir.deinit(gpa);
+ if (file.zir.hasCompileErrors()) {
+ var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena);
+ try Compilation.AllErrors.addZir(arena, &errors, &file);
+ const ttyconf: std.debug.TTY.Config = switch (color) {
+ .auto => std.debug.detectTTYConfig(),
+ .on => .escape_codes,
+ .off => .no_color,
+ };
+ for (errors.items) |full_err_msg| {
+ full_err_msg.renderToStdErr(ttyconf);
+ }
+ process.exit(1);
+ }
+
+ if (!want_output_text) {
+ return cleanExit();
+ }
+ if (!debug_extensions_enabled) {
+ fatal("-t option only available in debug builds of zig", .{});
+ }
+
{
const token_bytes = @sizeOf(std.zig.ast.TokenList) +
file.tree.tokens.len * (@sizeOf(std.zig.Token.Tag) + @sizeOf(std.zig.ast.ByteOffset));
@@ -3647,7 +3733,7 @@ pub fn cmdAstgen(
\\# Extra Data Items: {d} ({})
\\
, .{
- fmtIntSizeBin(source.len),
+ fmtIntSizeBin(file.source.len),
file.tree.tokens.len, fmtIntSizeBin(token_bytes),
file.tree.nodes.len, fmtIntSizeBin(tree_bytes),
fmtIntSizeBin(total_bytes),
@@ -3658,16 +3744,6 @@ pub fn cmdAstgen(
// zig fmt: on
}
- if (file.zir.hasCompileErrors()) {
- var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena);
- try Compilation.AllErrors.addZir(arena, &errors, &file);
- const ttyconf = std.debug.detectTTYConfig();
- for (errors.items) |full_err_msg| {
- full_err_msg.renderToStdErr(ttyconf);
- }
- process.exit(1);
- }
-
return Zir.renderAsTextToFile(gpa, &file, io.getStdOut());
}