commit bd34fbc9e6164f96a23011e0e2c877a9931e82c6
parent cda8429547a5f9a18a6e12b4d8b5105ceffbce5f
Author: Lou Woell <lou.woell@posteo.de>
Date:   Mon,  6 Oct 2025 18:35:46 +0200

[find-refs] scan dirtree

Diffstat:
Mcmd/harehelper/find_refs.ha | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 68 insertions(+), 20 deletions(-)

diff --git a/cmd/harehelper/find_refs.ha b/cmd/harehelper/find_refs.ha @@ -12,6 +12,8 @@ // You should have received a copy of the GNU General Public License along with // this program. If not, see <https://www.gnu.org/licenses/>. +// TODO: Handle enums. + use bufio; use fmt; use fs; @@ -27,23 +29,37 @@ use path; use strings; type xref = struct { - lex::location, + loc: lex::location, name: ast::ident, + context: str, +}; + +fn finish_xref (ref: *xref) void = { + ast::ident_free(ref.name); + free(ref.context); +}; + +fn print_ref (ref: xref) void = { + fmt::printfln("{}:{}:{}: {}", ref.loc.path, ref.loc.line, ref.loc.col, ref.context)!; }; -fn print_ref (ref: xref, file: io::handle) void = { - fmt::printf("{}:{}:{}: ", ref.path, ref.line, ref.col)!; +// 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) = { + + let off = loc.off; for (true) { - io::seek(file, ref.off, 0)!; + io::seek(file, off, 0)!; let r = bufio::read_rune(file); if('\n' == r) break; - ref.off -= 1; + off -= 1; }; - match (bufio::read_line(file)) { + + return match (bufio::read_line(file)?) { case let b: []u8 => - fmt::println(strings::fromutf8(b)!)!; - free(b); - case => void; + yield strings::fromutf8(b)!; + case io::EOF => + yield ""; }; }; @@ -60,16 +76,40 @@ fn find_refs (cmd: getopt::command, ctx: *module::context) void = { defer ast::ident_free(id); const path = path::init(cmd.args[1])!; - const (p, srcset) = module::find(ctx, &path)!; + scan_tree(ctx, &path, id); +}; + +fn scan_tree (ctx: *module::context, path: *path::buffer, id: ast::ident) ([]xref | void) = { - defer module::finish_srcset(&srcset); + let mods: []module::module = []; + defer module::free_slice(mods); - for (let s .. srcset.ha) { - scan_file(s, id); + let err = module::gather(ctx, &mods, path, false); + let err = module::gather_submodules(ctx, &mods, path, false); + + let res: []xref = []; + + for (let mod .. mods) { + if (mod.is_dep) continue; + + let id_c = id; + + // TODO: Move this check into [[scan_file]]. + if (ast::ident_eq(ident_ns(id), mod.ns)) id_c = ident_last(id); + + for (let s .. mod.srcs.ha) + scan_file(s, id_c, &res); }; + for (let ref .. res) { + print_ref(ref); + finish_xref(&ref); + }; + free(res); }; +// 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) = { for (true) { @@ -82,25 +122,26 @@ fn next_ref (lex: *lex::lexer) (xref | done | lex::error | parse::error) = { case ltok::NAME => lex::unlex(lex, tok); return xref { + loc = tok.2, name = parse::ident_trailing(lex)?.0, - path = tok.2.path, - line = tok.2.line, - col = tok.2.col, - off = tok.2.off, + // calling [[get_line]] for every ref would be very slow. + context = "", }; + case => void; }; }; }; -fn scan_file (path: str, id: ast::ident) void = { +fn scan_file (path: str, id: ast::ident, res: *[]xref) (size | void) = { 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)); + fmt::errorf("Error reading {}: {}", path, fs::strerror(err))!; + return void; }; defer io::close(input)!; const sc = bufio::newscanner(input); @@ -141,9 +182,16 @@ fn scan_file (path: str, id: ast::ident) void = { if (!found && len(id) > 1) return void; + let s: size = 0; for (let ref => next_ref(&lexer)!) { if(ast::ident_eq(id_f, ref.name) || ast::ident_eq(id, ref.name)) { - print_ref(ref, input); + ref.context = get_line(lexer.in.src, &ref)!; + append(res, ref)!; + s += 1; + } else { + finish_xref(&ref); }; }; + + return s; };