commit 6049e2c788b9f6d1784d02fbe1433b43c5722f94
parent b9b10630a680d773d657bf46a73a014915d2fb33
Author: Drew DeVault <sir@cmpwn.com>
Date: Fri, 26 Mar 2021 12:47:46 -0400
cmd/harec: format errors with context
Diffstat:
3 files changed, 53 insertions(+), 8 deletions(-)
diff --git a/bufio/scanner.ha b/bufio/scanner.ha
@@ -15,8 +15,7 @@ export fn scanbyte(stream: *io::stream) (u8 | io::EOF | io::error) = {
};
// Reads a slice of bytes until the delimiter. Delimiter is not
-// included. [io::EOF] is returned when stream emits EOF but nothing was
-// read. Returned buffer has to be freed by the caller.
+// included. The return value must be freed by the caller.
export fn scantok(stream: *io::stream, delim: u8) ([]u8 | io::EOF | io::error) = {
let buf: []u8 = [];
@@ -41,9 +40,9 @@ export fn scantok(stream: *io::stream, delim: u8) ([]u8 | io::EOF | io::error) =
};
// Reads a slice of bytes until a newline character (\n, 0x10). Newline itself
-// is not included. [io::EOF] is returned when stream emits EOF but nothing was
-// read. Returned buffer has to be freed by the caller.
-export fn scanline(stream: *io::stream) ([]u8 | io::EOF | io::error) = scantok(stream, '\n': u32: u8);
+// is not included. The return value must be freed by the caller.
+export fn scanline(stream: *io::stream) ([]u8 | io::EOF | io::error) =
+ scantok(stream, '\n': u32: u8);
// Reads a rune from a UTF-8 stream.
export fn scanrune(stream: *io::stream) (rune | utf8::invalid | io::EOF | io::error) = {
diff --git a/cmd/harec/errors.ha b/cmd/harec/errors.ha
@@ -0,0 +1,40 @@
+use bufio;
+use fmt;
+use hare::lex;
+use hare::parse;
+use io;
+use os;
+use strings;
+
+// TODO: Expand to more kinds of errors
+fn printerr(err: parse::error) void = {
+ match (err) {
+ err: lex::syntax => printerr_syntax(err),
+ err: io::error => fmt::errorln(io::errstr(err)),
+ };
+};
+
+fn printerr_syntax(err: lex::syntax) void = {
+ let location = err.0, details = err.1;
+ let file = os::open(location.path) as *io::stream;
+ defer io::close(file);
+
+ let line = 1u;
+ for (line < location.line) {
+ let r = bufio::scanrune(file) as rune;
+ if (r == '\n') {
+ line += 1u;
+ };
+ };
+
+ let line = bufio::scanline(file) as []u8;
+ defer free(line);
+ let line = strings::fromutf8(line);
+ fmt::errorfln("{}:{},{}: Syntax error: {}",
+ location.path, location.line, location.col, details);
+ fmt::errorln(line);
+ for (let i = 0u; i < location.col - 2; i += 1) {
+ fmt::errorf(" ");
+ };
+ fmt::errorln("^--- here");
+};
diff --git a/cmd/harec/main.ha b/cmd/harec/main.ha
@@ -3,13 +3,19 @@ use hare::ast;
use hare::lex;
use hare::parse;
use hare::unparse;
+use io;
use os;
export fn main() void = {
- let lexer = lex::init(os::stdin, "<stdin>");
+ let input = os::open(os::args[1]) as *io::stream;
+ defer io::close(input);
+
+ let lexer = lex::init(input, os::args[1]);
let su = match (parse::subunit(&lexer)) {
- e: parse::error =>
- fmt::fatal("Syntax error: {}", parse::errstr(e)),
+ err: parse::error => {
+ printerr(err);
+ os::exit(1);
+ },
u: ast::subunit => u,
};
defer ast::subunit_free(su);