2018-05-30 15:26:09 -07:00
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2018-07-10 17:18:43 -07:00
|
|
|
pub const Span = struct {
|
|
|
|
first: ast.TokenIndex,
|
|
|
|
last: ast.TokenIndex,
|
2018-07-13 18:56:38 -07:00
|
|
|
|
|
|
|
pub fn token(i: TokenIndex) Span {
|
2018-07-22 20:27:58 -07:00
|
|
|
return Span{
|
2018-07-13 18:56:38 -07:00
|
|
|
.first = i,
|
|
|
|
.last = i,
|
|
|
|
};
|
|
|
|
}
|
2018-07-22 20:27:58 -07:00
|
|
|
|
|
|
|
pub fn node(n: *ast.Node) Span {
|
|
|
|
return Span{
|
|
|
|
.first = n.firstToken(),
|
|
|
|
.last = n.lastToken(),
|
|
|
|
};
|
|
|
|
}
|
2018-07-10 17:18:43 -07:00
|
|
|
};
|
|
|
|
|
2018-05-30 15:26:09 -07:00
|
|
|
pub const Msg = struct {
|
|
|
|
path: []const u8,
|
|
|
|
text: []u8,
|
2018-07-10 17:18:43 -07:00
|
|
|
span: Span,
|
2018-05-31 07:56:59 -07:00
|
|
|
tree: *ast.Tree,
|
2018-05-30 15:26:09 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
/// `path` must outlive the returned Msg
|
|
|
|
/// `tree` must outlive the returned Msg
|
|
|
|
/// Caller owns returned Msg and must free with `allocator`
|
|
|
|
pub fn createFromParseError(
|
2018-05-31 07:56:59 -07:00
|
|
|
allocator: *mem.Allocator,
|
|
|
|
parse_error: *const ast.Error,
|
|
|
|
tree: *ast.Tree,
|
2018-05-30 15:26:09 -07:00
|
|
|
path: []const u8,
|
2018-05-31 07:56:59 -07:00
|
|
|
) !*Msg {
|
2018-05-30 15:26:09 -07:00
|
|
|
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);
|
|
|
|
|
2018-06-20 14:33:29 -07:00
|
|
|
const msg = try allocator.create(Msg{
|
2018-05-30 15:26:09 -07:00
|
|
|
.tree = tree,
|
|
|
|
.path = path,
|
|
|
|
.text = text_buf.toOwnedSlice(),
|
2018-07-10 17:18:43 -07:00
|
|
|
.span = Span{
|
|
|
|
.first = loc_token,
|
|
|
|
.last = loc_token,
|
|
|
|
},
|
2018-05-30 15:26:09 -07:00
|
|
|
});
|
|
|
|
errdefer allocator.destroy(msg);
|
|
|
|
|
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
|
2018-05-31 07:56:59 -07:00
|
|
|
pub fn printToStream(stream: var, msg: *const Msg, color_on: bool) !void {
|
2018-07-10 17:18:43 -07:00
|
|
|
const first_token = msg.tree.tokens.at(msg.span.first);
|
|
|
|
const last_token = msg.tree.tokens.at(msg.span.last);
|
2018-05-30 15:26:09 -07:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
2018-05-31 07:56:59 -07:00
|
|
|
pub fn printToFile(file: *os.File, msg: *const Msg, color: Color) !void {
|
2018-05-30 15:26:09 -07:00
|
|
|
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);
|
|
|
|
}
|