commit f40e6746b23ec54e1db13af3dabc8f3594a1113f
parent b3f3605b8147b052944563e991d16437f2c45529
Author: Lou Woell <lou.woell@posteo.de>
Date: Thu, 9 Oct 2025 19:54:28 +0200
[harehelper] more robust error handling
Diffstat:
8 files changed, 100 insertions(+), 62 deletions(-)
diff --git a/cmd/harehelper/+test/find_references.ha b/cmd/harehelper/+test/find_references.ha
@@ -14,7 +14,7 @@ fn test_xrefs (refs: []xref) void = {
let ref_id = unparse::identstr(ref.name);
defer free(ref_id);
- errorf("needle: {}, haystack: {}", ref_id, ref.context)!;
+ errorfln("needle: {}, haystack: {}", ref_id, ref.context)!;
assert(ref.context != "" && s::contains(ref.context, ref_id));
};
};
@@ -51,8 +51,7 @@ fn test_scan_tree (id: str, in: str = "") void = {
};
};
- if (in != "") assert(false);
-
+ if (in != "") assert(false, "id not found in file");
};
diff --git a/cmd/harehelper/+test/list_test.ha b/cmd/harehelper/+test/list_test.ha
@@ -1,4 +1,6 @@
use dirs;
+use fmt;
+use hare::ast;
use hare::module;
use hare::parse;
use os;
@@ -15,7 +17,12 @@ use os;
tags = ["linux"],
};
- let res = list_symbols(&ctx, parse::identstr("test")!);
+ let res = match (list_symbols(&ctx, parse::identstr("test")!)) {
+ case let e: error =>
+ fmt::fatalf("Error: {}", strerror(e));
+ case let l: []ast::ident =>
+ yield l;
+ };
defer idents_finish(res);
assert(len(res) == 3);
diff --git a/cmd/harehelper/find_refs.ha b/cmd/harehelper/find_refs.ha
@@ -50,16 +50,16 @@ fn print_ref (ref: xref) void = {
// Gets whole line specified by [[hare::lex::location]] from [[io::handle]].
// Return value must be freed by caller.
-fn get_line (file: io::handle, loc: *lex::location) (str | io::error) = {
+fn get_line (file: io::handle, loc: *lex::location) (str | error) = {
let off = loc.off;
- const o_off = io::tell(file)!;
+ const o_off = io::tell(file)?;
// This is slow.
// TODO: figure out a way to get the line from the line/column info.
// Problem: the lexer counts '\t' as 8 columns.
for (true) {
- io::seek(file, off, io::whence::SET)!;
+ io::seek(file, off, io::whence::SET)?;
let r = bufio::read_rune(file);
if('\n' == r) break;
off -= 1;
@@ -67,12 +67,12 @@ fn get_line (file: io::handle, loc: *lex::location) (str | io::error) = {
let result = match (bufio::read_line(file)?) {
case let b: []u8 =>
- yield strings::fromutf8(b)!;
+ yield strings::fromutf8(b)?;
case io::EOF =>
yield "";
};
- io::seek(file, o_off, io::whence::SET)!;
+ io::seek(file, o_off, io::whence::SET)?;
return result;
};
@@ -107,7 +107,7 @@ fn find_refs (cmd: getopt::command, ctx: *module::context) void = {
fn scan_tree (ctx: *module::context, path: *path::buffer, id: ast::ident) []fileref = {
let mods: []module::module = [];
-defer module::free_slice(mods);
+ defer module::free_slice(mods);
let err = module::gather(ctx, &mods, path, false);
let err = module::gather_submodules(ctx, &mods, path, false);
@@ -125,7 +125,10 @@ defer module::free_slice(mods);
for (let s &.. mod.srcs.ha) {
let file_res = match (scan_file(*s, id_c)) {
- case void => continue;
+ case let e: error =>
+ fmt::errorfln ("Error scanning {}: {}", *s, strerror(e))!;
+ // Skip file
+ continue;
case let r: []xref =>
yield r;
};
@@ -146,12 +149,12 @@ defer module::free_slice(mods);
return res;
};
-// Returns [[[xref]]] for next identifier in [[hare::lex::lexer]]. Return value
+// Returns [[xref]] for next identifier in [[hare::lex::lexer]]. Return value
// must be freed with [[finish_xref]].
-fn next_ref (lex: *lex::lexer) (xref | done | lex::error | parse::error) = {
+fn next_ref (lex: *lex::lexer) (xref | done | error) = {
for (true) {
-
+
const tok = lex::lex(lex)?;
switch (tok.0) {
@@ -172,22 +175,17 @@ fn next_ref (lex: *lex::lexer) (xref | done | lex::error | parse::error) = {
};
};
-fn scan_file (path: str, id: ast::ident) ([]xref | void)= {
+fn scan_file (path: str, id: ast::ident) ([]xref | error) = {
- const input = match (os::open(path)) {
- case let f: io::file =>
- yield f;
- case let err: fs::error =>
- fmt::errorf("Error reading {}: {}", path, fs::strerror(err))!;
- return void;
- };
+ const input = os::open(path)?;
defer io::close(input)!;
+
const sc = bufio::newscanner(input);
defer bufio::finish(&sc);
const lexer = lex::init(&sc, path, lex::flag::COMMENTS);
- const imps = parse::imports(&lexer)!;
+ const imps = parse::imports(&lexer)?;
defer ast::imports_finish(imps);
const ns = ident_ns(id);
@@ -219,9 +217,14 @@ fn scan_file (path: str, id: ast::ident) ([]xref | void)= {
};
let res: []xref = [];
- for (let ref => next_ref(&lexer)!) {
+ for (let ref => next_ref(&lexer)?) {
if(ast::ident_eq(id_f, ref.name) || ast::ident_eq(id, ref.name)) {
- ref.context = get_line(lexer.in.src, &ref)!;
+ ref.context = match (get_line(lexer.in.src, &ref)) {
+ case let e: error =>
+ yield strerror(e);
+ case let s: str =>
+ yield s;
+ };
append(res, ref)!;
} else {
finish_xref(&ref);
diff --git a/cmd/harehelper/list_modules.ha b/cmd/harehelper/list_modules.ha
@@ -32,9 +32,9 @@ fn get_modules (ctx: *module::context) []module::module = {
let r = module::gather_submodules(ctx, &res, &mod, true);
match (r) {
- case let e: hare::module::error =>
- fmt::errorln(module::strerror(e))!;
- case => void;
+ case let e: module::error =>
+ fmt::errorln(strerror(e))!;
+ case => void;
};
};
diff --git a/cmd/harehelper/list_symbols.ha b/cmd/harehelper/list_symbols.ha
@@ -41,7 +41,12 @@ fn list (cmd: getopt::command, ctx: *module::context) void = {
};
};
- let list = list_symbols(ctx, id, ls_unexported);
+ let list = match (list_symbols(ctx, id, ls_unexported)) {
+ case let e: error =>
+ fmt::fatal(strerror(e));
+ case let l: []ast::ident =>
+ yield l;
+ };
defer idents_finish(list);
for (let i .. list) {
@@ -53,21 +58,18 @@ fn list_symbols (
ctx: *module::context,
id: module::location,
unexp: bool = false,
-) []ast::ident = {
+) ([]ast::ident | error) = {
- let (path, src) = match(module::find(ctx, id)){
- case let e: module::error =>
- fmt::fatal(module::strerror(e));
- case let res: (str, module::srcset) =>
- yield res;
- };
+ let (path, src) = module::find(ctx, id)?;
let res: []ast::ident = [];
for (let s .. src.ha) {
let decls = match (scan(s)) {
- case let e: parse::error =>
- fmt::fatal(parse::strerror(e));
+ case let e: error =>
+ fmt::errorfln("Error reading {}: {}", s, strerror(e))!;
+ // skip file.
+ continue;
case let d: []ast::decl =>
yield d;
};
diff --git a/cmd/harehelper/locate.ha b/cmd/harehelper/locate.ha
@@ -27,8 +27,8 @@ fn locate (cmd: command, ctx: *module::context) void = {
if(len(cmd.args) == 0) fmt::fatal("Expected Argument");
let (id, trailing) = match (identstr_trailing(cmd.args[0])) {
- case parse::error =>
- return void;
+ case let e: parse::error =>
+ fmt::fatal(parse::strerror(e));
case let r: (ast::ident, bool) =>
yield r;
};
@@ -99,8 +99,10 @@ fn locate_symbol (
for (let s .. src.ha) {
let decls = match (scan(s)) {
- case let e: parse::error =>
- fmt::fatal(parse::strerror(e));
+ case let e: error =>
+ fmt::errorfln("Error reading {}: {}", s, strerror(e))!;
+ // skip file.
+ continue;
case let d: []ast::decl =>
yield d;
};
diff --git a/cmd/harehelper/resolve.ha b/cmd/harehelper/resolve.ha
@@ -49,6 +49,8 @@ fn resolve(cmd: getopt::command, ctx: *module::context) void = {
case let id_exp: ast::ident =>
printident(id_exp, trailing);
ast::ident_free(id_exp);
+ case let e: error =>
+ fmt::errorfln("Error: {}", strerror(e))!;
case =>
printident(id, trailing);
};
@@ -60,7 +62,7 @@ fn resolve_local (
ctx: *module::context,
id: ast::ident,
file: str,
-) (ast::ident | void) = {
+) (ast::ident | void | error) = {
let hp = strings::split(ctx.harepath, ":")!;
defer free(hp);
@@ -91,20 +93,15 @@ fn resolve_local (
return void;
};
-fn list_imports (path: str) []ast::import = {
+fn list_imports (path: str) ([]ast::import | error) = {
- const input = match (os::open(path)) {
- case let f: io::file =>
- yield f;
- case let err: fs::error =>
- fmt::fatalf("Error reading {}: {}", path, fs::strerror(err));
- };
+ const input = os::open(path)?;
defer io::close(input)!;
let sc = bufio::newscanner(input);
defer bufio::finish(&sc);
let lexer = lex::init(&sc, path, lex::flag::NONE);
- return parse::imports(&lexer)!;
+ return parse::imports(&lexer)?;
};
// Resolves id based on imports in file at path. Returns void when id is not
@@ -113,9 +110,14 @@ fn resolve_uid (
ctx: *module::context,
id: ast::ident,
path: str
-) (void | ast::ident) = {
+) (void | ast::ident | error) = {
- let imports = list_imports(path);
+ let imports = match (list_imports(path)) {
+ case let e: error =>
+ fmt::fatalf("Error: {}", strerror(e));
+ case let l: []ast::import =>
+ yield l;
+ };
defer ast::imports_finish(imports);
for (let i .. imports) {
@@ -150,7 +152,14 @@ fn resolve_uid (
// if len(id) > 1 -> id is not an interned
// symbol.
if (len(id) > 1) yield :binding;
- let list = list_symbols(ctx, ident);
+ let list = match (list_symbols(ctx, ident)) {
+ case let e: error =>
+ fmt::errorfln("Error: {}", strerror(e))!;
+ // skip module.
+ yield :binding;
+ case let l: []ast::ident =>
+ yield l;
+ };
defer idents_finish(list);
for (let s .. list) {
diff --git a/cmd/harehelper/util.ha b/cmd/harehelper/util.ha
@@ -14,6 +14,7 @@
use ascii;
use bufio;
+use encoding::utf8;
use fmt;
use fs;
use hare::ast;
@@ -21,8 +22,8 @@ use hare::lex;
use hare::module;
use hare::parse;
use hare::unparse;
-use memio;
use io;
+use memio;
use os;
use strings;
@@ -45,14 +46,29 @@ fn ident_ns(id: ast::ident) ast::ident = {
if (l > 1) return id[..l - 1] else return id;
};
-fn scan(path: str) ([]ast::decl | parse::error) = {
- // This function is copied from haredoc (GPL-3.0-only) (c) Hare authors;
- const input = match (os::open(path)) {
- case let f: io::file =>
- yield f;
- case let err: fs::error =>
- fmt::fatalf("Error reading {}: {}", path, fs::strerror(err));
+type error = !(parse::error | lex::error | fs::error | module::error | io::error |
+ utf8::invalid);
+
+fn strerror (e: error) const str = {
+ match (e) {
+ case let e: parse::error =>
+ return parse::strerror(e);
+ case let e: lex::error =>
+ return lex::strerror(e);
+ case let e: fs::error =>
+ return fs::strerror(e);
+ case let e: module::error =>
+ return module::strerror(e);
+ case let e: io::error =>
+ return io::strerror(e);
+ case =>
+ return "unknown error";
};
+};
+
+fn scan(path: str) ([]ast::decl | error) = {
+ // This function is copied from haredoc (GPL-3.0-only) (c) Hare authors;
+ const input = os::open(path)?;
defer io::close(input)!;
let sc = bufio::newscanner(input);
defer bufio::finish(&sc);