commit 85e34ae697939b3ce62d344e7f78d4273555f49c
parent 6261e1011e0ea30d375b75da4bdb0079564e057a
Author: Drew DeVault <sir@cmpwn.com>
Date: Tue, 20 Apr 2021 12:08:39 -0400
haredoc: initial pass on references
Diffstat:
3 files changed, 77 insertions(+), 18 deletions(-)
diff --git a/Makefile b/Makefile
@@ -38,7 +38,8 @@ haredoc_srcs=\
./cmd/haredoc/env.ha \
./cmd/haredoc/hare.ha \
./cmd/haredoc/html.ha \
- ./cmd/haredoc/sort.ha
+ ./cmd/haredoc/sort.ha \
+ ./cmd/haredoc/resolver.ha
$(HARECACHE)/hare.ssa: $(hare_srcs) $(hare_stdlib_deps)
@printf 'HAREC\t$@\n'
diff --git a/cmd/haredoc/html.ha b/cmd/haredoc/html.ha
@@ -1,3 +1,4 @@
+// Note: ast::ident should never have to be escaped
use bufio;
use fmt;
use format::html;
@@ -32,7 +33,7 @@ fn emit_html(ctx: *context) (void | error) = {
null => void,
f: *io::stream => {
fmt::println("<div class='readme'>")?;
- markup_html(f)?;
+ markup_html(ctx, f)?;
fmt::println("</div>")?;
},
};
@@ -66,13 +67,13 @@ fn emit_html(ctx: *context) (void | error) = {
fmt::println("<hr />")?;
for (let i = 0z; i < len(decls.types); i += 1) {
- details(decls.types[i])?;
+ details(ctx, decls.types[i])?;
};
for (let i = 0z; i < len(decls.globals); i += 1) {
- details(decls.globals[i])?;
+ details(ctx, decls.globals[i])?;
};
for (let i = 0z; i < len(decls.funcs); i += 1) {
- details(decls.funcs[i])?;
+ details(ctx, decls.funcs[i])?;
};
};
@@ -104,7 +105,7 @@ fn tocentry(decl: ast::decl) (void | error) = {
return;
};
-fn details(decl: ast::decl) (void | error) = {
+fn details(ctx: *context, decl: ast::decl) (void | error) = {
fmt::println("<section class='member'>");
fmt::print("<h3 id='")?;
unparse::ident(os::stdout, decl_ident(decl))?;
@@ -116,9 +117,8 @@ fn details(decl: ast::decl) (void | error) = {
_: []ast::decl_global => "let",
});
unparse::ident(os::stdout, decl_ident(decl))?;
- // TODO: Make this URL real
+ // TODO: Add source URL
fmt::print("<span class='heading-extra'>
- <a href='#'>[source]</a>
<a href='#")?;
unparse::ident(os::stdout, decl_ident(decl))?;
fmt::print("'>[link]</a>
@@ -131,14 +131,34 @@ fn details(decl: ast::decl) (void | error) = {
if (len(decl.docs) != 0) {
const buf = strings::toutf8(decl.docs);
- markup_html(bufio::fixed(buf, io::mode::READ))?;
+ markup_html(ctx, bufio::fixed(buf, io::mode::READ))?;
};
fmt::println("</section>")?;
return;
};
-fn markup_html(in: *io::stream) (void | io::error) = {
+fn htmlref(ctx: *context, ref: ast::ident) (void | io::error) = {
+ match (resolve(ctx, ref)) {
+ _: void => {
+ const ident = unparse::identstr(ref);
+ fmt::errorfln("Warning: Unresolved reference: {}", ident);
+ fmt::printf("<a href='#' "
+ "class='ref invalid' "
+ "title='This reference could not be found'>{}</a>",
+ ident)?;
+ free(ident);
+ },
+ ik: (ast::ident, symkind) => {
+ const kind = ik.1, id = ik.0;
+ const ident = unparse::identstr(id);
+ fmt::printf("<a href='#{0}' class='ref'>{0}</a>", ident)?;
+ free(ident);
+ },
+ };
+};
+
+fn markup_html(ctx: *context, in: *io::stream) (void | io::error) = {
let parser = parsedoc(in);
for (true) {
const tok = match (scandoc(&parser)) {
@@ -154,14 +174,7 @@ fn markup_html(in: *io::stream) (void | io::error) = {
html::escape(os::stdout, tx);
free(tx);
},
- re: reference => {
- fmt::print("<a href='#' class='ref invalid'>")?;
- const ident = unparse::identstr(re);
- defer free(ident);
- html::escape(os::stdout, ident);
- fmt::print("</a>")?;
- ast::ident_free(re);
- },
+ re: reference => htmlref(ctx, re)?,
sa: sample => {
fmt::print("<pre class='sample'>")?;
html::escape(os::stdout, sa);
diff --git a/cmd/haredoc/resolver.ha b/cmd/haredoc/resolver.ha
@@ -0,0 +1,45 @@
+use hare::ast;
+
+type symkind = enum {
+ LOCAL,
+ MODULE,
+ SYMBOL,
+};
+
+// Resolves a reference. Given an identifier, determines if it refers to a local
+// symbol, a module, or a symbol in a remote module, then returns this
+// information combined with a corrected ident if necessary.
+fn resolve(ctx: *context, what: ast::ident) ((ast::ident, symkind) | void) = {
+ if (is_local(ctx, what)) {
+ return (what, symkind::LOCAL);
+ };
+ return void;
+};
+
+fn is_local(ctx: *context, what: ast::ident) bool = {
+ if (len(what) != 1) {
+ return false;
+ };
+
+ const summary = ctx.summary;
+ for (let i = 0z; i < len(summary.types); i += 1) {
+ const name = decl_ident(summary.types[i])[0];
+ if (name == what[0]) {
+ return true;
+ };
+ };
+ for (let i = 0z; i < len(summary.globals); i += 1) {
+ const name = decl_ident(summary.globals[i])[0];
+ if (name == what[0]) {
+ return true;
+ };
+ };
+ for (let i = 0z; i < len(summary.funcs); i += 1) {
+ const name = decl_ident(summary.funcs[i])[0];
+ if (name == what[0]) {
+ return true;
+ };
+ };
+
+ return false;
+};