~sircmpwn/hare

066afc4a432fa935705b157827e49aaa388712d1 — Alexey Yerin 2 months ago 7e89859
cmd/haredoc: resolve enum members

Signed-off-by: Alexey Yerin <yyp@disroot.org>
2 files changed, 107 insertions(+), 0 deletions(-)

M cmd/haredoc/html.ha
M cmd/haredoc/resolver.ha
M cmd/haredoc/html.ha => cmd/haredoc/html.ha +8 -0
@@ 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);
};

M cmd/haredoc/resolver.ha => cmd/haredoc/resolver.ha +99 -0
@@ 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;
					};
				};
			};
		};
	};
};