commit 066afc4a432fa935705b157827e49aaa388712d1
parent 7e89859138660adc267f51de1a9ca05a39c953cd
Author: Alexey Yerin <yyp@disroot.org>
Date: Wed, 30 Mar 2022 14:12:09 +0300
cmd/haredoc: resolve enum members
Signed-off-by: Alexey Yerin <yyp@disroot.org>
Diffstat:
2 files changed, 107 insertions(+), 0 deletions(-)
diff --git a/cmd/haredoc/html.ha b/cmd/haredoc/html.ha
@@ -339,6 +339,14 @@ fn htmlref(ctx: *context, ref: ast::ident) (void | io::error) = {
defer free(ipath);
fmt::fprintf(ctx.out, "<a href='/{}#{}' class='ref'>{}</a>",
ipath, id[len(id) - 1], ident)?;
+ case symkind::ENUM_LOCAL =>
+ fmt::fprintf(ctx.out, "<a href='#{}' class='ref'>{}</a>",
+ id[len(id) - 2], ident)?;
+ case symkind::ENUM_REMOTE =>
+ let ipath = module::identpath(id[..len(id) - 2]);
+ defer free(ipath);
+ fmt::fprintf(ctx.out, "<a href='/{}#{}' class='ref'>{}</a>",
+ ipath, id[len(id) - 2], ident)?;
};
free(ident);
};
diff --git a/cmd/haredoc/resolver.ha b/cmd/haredoc/resolver.ha
@@ -1,13 +1,18 @@
// License: GPL-3.0
// (c) 2021 Drew DeVault <sir@cmpwn.com>
// (c) 2021 Eyal Sawady <ecs@d2evs.net>
+// (c) 2022 Alexey Yerin <yyp@disroot.org>
+use fmt;
use hare::ast;
use hare::module;
+use path;
type symkind = enum {
LOCAL,
MODULE,
SYMBOL,
+ ENUM_LOCAL,
+ ENUM_REMOTE,
};
// Resolves a reference. Given an identifier, determines if it refers to a local
@@ -28,6 +33,20 @@ fn resolve(ctx: *context, what: ast::ident) ((ast::ident, symkind) | void) = {
case module::error => void;
};
};
+ if (len(what) == 2) {
+ match (lookup_local_enum(ctx, what)) {
+ case let id: ast::ident =>
+ return (id, symkind::ENUM_LOCAL);
+ case => void;
+ };
+ };
+ if (len(what) > 2) {
+ match (lookup_remote_enum(ctx, what)) {
+ case let id: ast::ident =>
+ return (id, symkind::ENUM_REMOTE);
+ case => void;
+ };
+ };
match (module::lookup(ctx.mctx, what)) {
case let ver: module::version =>
@@ -77,3 +96,83 @@ fn is_local(ctx: *context, what: ast::ident) bool = {
return false;
};
+
+fn lookup_local_enum(ctx: *context, what: ast::ident) (ast::ident | void) = {
+ for (let i = 0z; i < len(ctx.summary.types); i += 1) {
+ const decl = ctx.summary.types[i];
+ const name = decl_ident(decl)[0];
+ if (name == what[0]) {
+ const t = (decl.decl as []ast::decl_type)[0];
+ const e = match (t._type.repr) {
+ case let e: ast::enum_type =>
+ yield e;
+ case =>
+ return;
+ };
+ for (let i = 0z; i < len(e.values); i += 1) {
+ if (e.values[i].name == what[1]) {
+ return what;
+ };
+ };
+ };
+ };
+};
+
+fn lookup_remote_enum(ctx: *context, what: ast::ident) (ast::ident | void) = {
+ // mod::decl_name::member
+ const mod = what[..len(what) - 2];
+ const decl_name = what[len(what) - 2];
+ const member = what[len(what) - 1];
+
+ const version = match (module::lookup(ctx.mctx, mod)) {
+ case let ver: module::version =>
+ yield ver;
+ case module::error =>
+ abort();
+ };
+
+ // This would take a lot of memory to load
+ let decls: []ast::decl = [];
+ defer {
+ for (let i = 0z; i < len(decls); i += 1) {
+ ast::decl_free(decls[i]);
+ };
+ free(decls);
+ };
+ for (let i = 0z; i < len(version.inputs); i += 1) {
+ const in = version.inputs[i];
+ const ext = path::extension(in.path);
+ if (ext.1 != ".ha") {
+ continue;
+ };
+ match (scan(in.path)) {
+ case let u: ast::subunit =>
+ append(decls, u.decls...);
+ case let err: error =>
+ fmt::fatal("Error: {}", strerror(err));
+ };
+ };
+
+ for (let i = 0z; i < len(decls); i += 1) {
+ const decl = match (decls[i].decl) {
+ case let t: []ast::decl_type =>
+ yield t;
+ case => continue;
+ };
+ for (let i = 0z; i < len(decl); i += 1) {
+ if (decl[i].ident[0] == decl_name) {
+ const e = match (decl[i]._type.repr) {
+ case let e: ast::enum_type =>
+ yield e;
+ case =>
+ abort();
+ };
+ for (let i = 0z; i < len(e.values); i += 1) {
+ if (e.values[i].name == member) {
+ return what;
+ };
+ };
+ };
+ };
+ };
+};