commit 8cafe76a3f807932d1137165a13d8e5ed15cb94d
parent 664c0b62450c7c6688b40f0ab6c68533778460ef
Author: Lou Woell <lou.woell@posteo.de>
Date:   Mon,  6 Oct 2025 03:31:47 +0200

[find-refs] implement reference finder

Diffstat:
Acmd/harehelper/find_refs.ha | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcmd/harehelper/helper.ha | 7+++++++
Mcmd/harehelper/list_symbols.ha | 4++--
3 files changed, 144 insertions(+), 2 deletions(-)

diff --git a/cmd/harehelper/find_refs.ha b/cmd/harehelper/find_refs.ha @@ -0,0 +1,135 @@ +use bufio; +use fmt; +use fs; +use getopt; +use hare::ast; +use hare::lex::{ltok}; +use hare::lex; +use hare::module; +use hare::parse; +use io; +use os; +use path; +use strings; + +type xref = struct { + lex::location, + name: ast::ident, +}; + +fn print_ref (ref: xref, file: io::handle) void = { + fmt::printf("{}:{}:{}: ", ref.path, ref.line, ref.col)!; + for (true) { + io::seek(file, ref.off, 0)!; + let r = bufio::read_rune(file); + if('\n' == r) break; + ref.off -= 1; + }; + match (bufio::read_line(file)) { + case let b: []u8 => + fmt::println(strings::fromutf8(b)!)!; + free(b); + case => void; + }; +}; + +fn find_refs (cmd: getopt::command, ctx: *module::context) void = { + + if(len(cmd.args) != 2) fmt::fatal("Expected 2 Arguments"); + + const id = match (parse::identstr(cmd.args[0])) { + case let e: parse::error => + fmt::fatal(parse::strerror(e)); + case let res: ast::ident => + yield res; + }; + defer ast::ident_free(id); + + const path = path::init(cmd.args[1])!; + const (p, srcset) = module::find(ctx, &path)!; + + defer module::finish_srcset(&srcset); + + for (let s .. srcset.ha) { + scan_file(s, id); + }; + +}; + +fn next_ref (lex: *lex::lexer) (xref | done | lex::error | parse::error) = { + + for (true) { + + const tok = lex::lex(lex)?; + + switch (tok.0) { + case ltok::EOF => + return done; + case ltok::NAME => + lex::unlex(lex, tok); + return xref { + name = parse::ident_trailing(lex)?.0, + path = tok.2.path, + line = tok.2.line, + col = tok.2.col, + off = tok.2.off, + }; + case => + void; + }; + }; +}; + +fn scan_file (path: str, id: ast::ident) 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)); + }; + 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)!; + defer ast::imports_finish(imps); + + const ns = ident_ns(id); + let found = false; + let id_f: ast::ident = ["", ""]; + + for :imps (let i .. imps) { + found = ast::ident_eq(ns, i.ident); + if (found) { + + match (i.bindings) { + case void => + id_f = id[len(id)-2..]; + case let a: ast::import_alias => + id_f[0] = a; + id_f[1] = ident_last(id)[0]; + case let members: ast::import_members => + id_f = ident_last(id); + for (let m .. members) { + if(id_f[0] == m) break :imps; + }; + continue :imps; + case ast::import_wildcard => + id_f = ident_last(id); + }; + + break; + }; + }; + + if (!found && len(id) > 1) return void; + + for (let ref => next_ref(&lexer)!) { + if(ast::ident_eq(id_f, ref.name) || ast::ident_eq(id, ref.name)) { + print_ref(ref, input); + }; + }; +}; diff --git a/cmd/harehelper/helper.ha b/cmd/harehelper/helper.ha @@ -44,6 +44,11 @@ const help: []getopt::help = [ ("list-modules", [ "list all modules in current harepath", ]: []getopt::help), + ("find-references", [ + "find all references to symbol", + "identifier", + "path", + ]: []getopt::help), ]; export fn main () void = { @@ -97,6 +102,8 @@ export fn main () void = { list_modules(&ctx); case "locate" => locate(*c.1, &ctx); + case "find-references" => + find_refs(*c.1, &ctx); case => void; }; os::exit(0); diff --git a/cmd/harehelper/list_symbols.ha b/cmd/harehelper/list_symbols.ha @@ -51,8 +51,8 @@ fn list (cmd: getopt::command, ctx: *module::context) void = { fn list_symbols ( ctx: *module::context, - id: ast::ident, - unexp: bool = false + id: module::location, + unexp: bool = false, ) []ast::ident = { let (path, src) = match(module::find(ctx, id)){