Commit a05acaf9fd
Changed files (4)
src-self-hosted
std
zig
src-self-hosted/errmsg.zig
@@ -0,0 +1,87 @@
+const std = @import("std");
+const mem = std.mem;
+const os = std.os;
+const Token = std.zig.Token;
+const ast = std.zig.ast;
+const TokenIndex = std.zig.ast.TokenIndex;
+
+pub const Color = enum {
+ Auto,
+ Off,
+ On,
+};
+
+pub const Msg = struct {
+ path: []const u8,
+ text: []u8,
+ first_token: TokenIndex,
+ last_token: TokenIndex,
+ tree: &ast.Tree,
+};
+
+/// `path` must outlive the returned Msg
+/// `tree` must outlive the returned Msg
+/// Caller owns returned Msg and must free with `allocator`
+pub fn createFromParseError(
+ allocator: &mem.Allocator,
+ parse_error: &const ast.Error,
+ tree: &ast.Tree,
+ path: []const u8,
+) !&Msg {
+ const loc_token = parse_error.loc();
+ var text_buf = try std.Buffer.initSize(allocator, 0);
+ defer text_buf.deinit();
+
+ var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
+ try parse_error.render(&tree.tokens, out_stream);
+
+ const msg = try allocator.construct(Msg{
+ .tree = tree,
+ .path = path,
+ .text = text_buf.toOwnedSlice(),
+ .first_token = loc_token,
+ .last_token = loc_token,
+ });
+ errdefer allocator.destroy(msg);
+
+ return msg;
+}
+
+pub fn printToStream(stream: var, msg: &const Msg, color_on: bool) !void {
+ const first_token = msg.tree.tokens.at(msg.first_token);
+ const last_token = msg.tree.tokens.at(msg.last_token);
+ const start_loc = msg.tree.tokenLocationPtr(0, first_token);
+ const end_loc = msg.tree.tokenLocationPtr(first_token.end, last_token);
+ if (!color_on) {
+ try stream.print(
+ "{}:{}:{}: error: {}\n",
+ msg.path,
+ start_loc.line + 1,
+ start_loc.column + 1,
+ msg.text,
+ );
+ return;
+ }
+
+ try stream.print(
+ "{}:{}:{}: error: {}\n{}\n",
+ msg.path,
+ start_loc.line + 1,
+ start_loc.column + 1,
+ msg.text,
+ msg.tree.source[start_loc.line_start..start_loc.line_end],
+ );
+ try stream.writeByteNTimes(' ', start_loc.column);
+ try stream.writeByteNTimes('~', last_token.end - first_token.start);
+ try stream.write("\n");
+}
+
+pub fn printToFile(file: &os.File, msg: &const Msg, color: Color) !void {
+ const color_on = switch (color) {
+ Color.Auto => file.isTty(),
+ Color.On => true,
+ Color.Off => false,
+ };
+ var stream = &std.io.FileOutStream.init(file).stream;
+ return printToStream(stream, msg, color_on);
+}
src-self-hosted/main.zig
@@ -15,7 +15,9 @@ const Args = arg.Args;
const Flag = arg.Flag;
const Module = @import("module.zig").Module;
const Target = @import("target.zig").Target;
+const errmsg = @import("errmsg.zig");
+var stderr_file: os.File = undefined;
var stderr: &io.OutStream(io.FileOutStream.Error) = undefined;
var stdout: &io.OutStream(io.FileOutStream.Error) = undefined;
@@ -51,7 +53,7 @@ pub fn main() !void {
var stdout_out_stream = std.io.FileOutStream.init(&stdout_file);
stdout = &stdout_out_stream.stream;
- var stderr_file = try std.io.getStdErr();
+ stderr_file = try std.io.getStdErr();
var stderr_out_stream = std.io.FileOutStream.init(&stderr_file);
stderr = &stderr_out_stream.stream;
@@ -440,18 +442,19 @@ fn buildOutputType(allocator: &Allocator, args: []const []const u8, out_type: Mo
build_mode = builtin.Mode.ReleaseSafe;
}
- var color = Module.ErrColor.Auto;
- if (flags.single("color")) |color_flag| {
- if (mem.eql(u8, color_flag, "auto")) {
- color = Module.ErrColor.Auto;
- } else if (mem.eql(u8, color_flag, "on")) {
- color = Module.ErrColor.On;
- } else if (mem.eql(u8, color_flag, "off")) {
- color = Module.ErrColor.Off;
+ const color = blk: {
+ if (flags.single("color")) |color_flag| {
+ if (mem.eql(u8, color_flag, "auto")) {
+ break :blk errmsg.Color.Auto;
+ } else if (mem.eql(u8, color_flag, "on")) {
+ break :blk errmsg.Color.On;
+ } else if (mem.eql(u8, color_flag, "off")) {
+ break :blk errmsg.Color.Off;
+ } else unreachable;
} else {
- unreachable;
+ break :blk errmsg.Color.Auto;
}
- }
+ };
var emit_type = Module.Emit.Binary;
if (flags.single("emit")) |emit_flag| {
@@ -687,7 +690,14 @@ const usage_fmt =
\\
;
-const args_fmt_spec = []Flag{Flag.Bool("--help")};
+const args_fmt_spec = []Flag{
+ Flag.Bool("--help"),
+ Flag.Option("--color", []const []const u8{
+ "auto",
+ "off",
+ "on",
+ }),
+};
fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void {
var flags = try Args.parse(allocator, args_fmt_spec, args);
@@ -703,6 +713,20 @@ fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void {
os.exit(1);
}
+ const color = blk: {
+ if (flags.single("color")) |color_flag| {
+ if (mem.eql(u8, color_flag, "auto")) {
+ break :blk errmsg.Color.Auto;
+ } else if (mem.eql(u8, color_flag, "on")) {
+ break :blk errmsg.Color.On;
+ } else if (mem.eql(u8, color_flag, "off")) {
+ break :blk errmsg.Color.Off;
+ } else unreachable;
+ } else {
+ break :blk errmsg.Color.Auto;
+ }
+ };
+
for (flags.positionals.toSliceConst()) |file_path| {
var file = try os.File.openRead(allocator, file_path);
defer file.close();
@@ -721,25 +745,10 @@ fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void {
var error_it = tree.errors.iterator(0);
while (error_it.next()) |parse_error| {
- const token = tree.tokens.at(parse_error.loc());
- const loc = tree.tokenLocation(0, parse_error.loc());
- try stderr.print("{}:{}:{}: error: ", file_path, loc.line + 1, loc.column + 1);
- try tree.renderError(parse_error, stderr);
- try stderr.print("\n{}\n", source_code[loc.line_start..loc.line_end]);
- {
- var i: usize = 0;
- while (i < loc.column) : (i += 1) {
- try stderr.write(" ");
- }
- }
- {
- const caret_count = token.end - token.start;
- var i: usize = 0;
- while (i < caret_count) : (i += 1) {
- try stderr.write("~");
- }
- }
- try stderr.write("\n");
+ const msg = try errmsg.createFromParseError(allocator, parse_error, &tree, file_path);
+ defer allocator.destroy(msg);
+
+ try errmsg.printToFile(&stderr_file, msg, color);
}
if (tree.errors.len != 0) {
continue;
src-self-hosted/module.zig
@@ -10,6 +10,7 @@ const Target = @import("target.zig").Target;
const warn = std.debug.warn;
const Token = std.zig.Token;
const ArrayList = std.ArrayList;
+const errmsg = @import("errmsg.zig");
pub const Module = struct {
allocator: &mem.Allocator,
@@ -55,7 +56,7 @@ pub const Module = struct {
link_libs_list: ArrayList(&LinkLib),
libc_link_lib: ?&LinkLib,
- err_color: ErrColor,
+ err_color: errmsg.Color,
verbose_tokenize: bool,
verbose_ast_tree: bool,
@@ -87,12 +88,6 @@ pub const Module = struct {
Obj,
};
- pub const ErrColor = enum {
- Auto,
- Off,
- On,
- };
-
pub const LinkLib = struct {
name: []const u8,
path: ?[]const u8,
@@ -195,7 +190,7 @@ pub const Module = struct {
.windows_subsystem_console = false,
.link_libs_list = ArrayList(&LinkLib).init(allocator),
.libc_link_lib = null,
- .err_color = ErrColor.Auto,
+ .err_color = errmsg.Color.Auto,
.darwin_frameworks = [][]const u8{},
.darwin_version_min = DarwinVersionMin.None,
.test_filters = [][]const u8{},
std/zig/ast.zig
@@ -120,7 +120,7 @@ pub const Error = union(enum) {
ExpectedToken: ExpectedToken,
ExpectedCommaOrEnd: ExpectedCommaOrEnd,
- pub fn render(self: &Error, tokens: &Tree.TokenList, stream: var) !void {
+ pub fn render(self: &const Error, tokens: &Tree.TokenList, stream: var) !void {
switch (self.*) {
// TODO https://github.com/ziglang/zig/issues/683
@TagType(Error).InvalidToken => |*x| return x.render(tokens, stream),
@@ -145,7 +145,7 @@ pub const Error = union(enum) {
}
}
- pub fn loc(self: &Error) TokenIndex {
+ pub fn loc(self: &const Error) TokenIndex {
switch (self.*) {
// TODO https://github.com/ziglang/zig/issues/683
@TagType(Error).InvalidToken => |x| return x.token,
@@ -190,7 +190,7 @@ pub const Error = union(enum) {
pub const ExpectedCall = struct {
node: &Node,
- pub fn render(self: &ExpectedCall, tokens: &Tree.TokenList, stream: var) !void {
+ pub fn render(self: &const ExpectedCall, tokens: &Tree.TokenList, stream: var) !void {
return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ ", found {}", @tagName(self.node.id));
}
};
@@ -198,7 +198,7 @@ pub const Error = union(enum) {
pub const ExpectedCallOrFnProto = struct {
node: &Node,
- pub fn render(self: &ExpectedCallOrFnProto, tokens: &Tree.TokenList, stream: var) !void {
+ pub fn render(self: &const ExpectedCallOrFnProto, tokens: &Tree.TokenList, stream: var) !void {
return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ " or " ++ @tagName(Node.Id.FnProto) ++ ", found {}", @tagName(self.node.id));
}
};
@@ -207,7 +207,7 @@ pub const Error = union(enum) {
token: TokenIndex,
expected_id: @TagType(Token.Id),
- pub fn render(self: &ExpectedToken, tokens: &Tree.TokenList, stream: var) !void {
+ pub fn render(self: &const ExpectedToken, tokens: &Tree.TokenList, stream: var) !void {
const token_name = @tagName(tokens.at(self.token).id);
return stream.print("expected {}, found {}", @tagName(self.expected_id), token_name);
}
@@ -217,7 +217,7 @@ pub const Error = union(enum) {
token: TokenIndex,
end_id: @TagType(Token.Id),
- pub fn render(self: &ExpectedCommaOrEnd, tokens: &Tree.TokenList, stream: var) !void {
+ pub fn render(self: &const ExpectedCommaOrEnd, tokens: &Tree.TokenList, stream: var) !void {
const token_name = @tagName(tokens.at(self.token).id);
return stream.print("expected ',' or {}, found {}", @tagName(self.end_id), token_name);
}
@@ -229,7 +229,7 @@ pub const Error = union(enum) {
token: TokenIndex,
- pub fn render(self: &ThisError, tokens: &Tree.TokenList, stream: var) !void {
+ pub fn render(self: &const ThisError, tokens: &Tree.TokenList, stream: var) !void {
const token_name = @tagName(tokens.at(self.token).id);
return stream.print(msg, token_name);
}
@@ -242,7 +242,7 @@ pub const Error = union(enum) {
token: TokenIndex,
- pub fn render(self: &ThisError, tokens: &Tree.TokenList, stream: var) !void {
+ pub fn render(self: &const ThisError, tokens: &Tree.TokenList, stream: var) !void {
return stream.write(msg);
}
};