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:
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)){