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:
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;
};