Skip to content

Commit 8cfd6eb

Browse files
committed
Add docs for structs & consts
1 parent 3e27f99 commit 8cfd6eb

5 files changed

Lines changed: 166 additions & 39 deletions

File tree

src/compiler_top.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ impl Linker {
295295
template_args: FlatAlloc::new(),
296296
});
297297
} else {
298-
let md_with_args = md.link_info.display_full_name_and_args(
298+
let md_with_args = md.link_info.display_full_name_and_args::<false>(
299299
&self.files[md.link_info.span.file].file_text,
300300
);
301301
fatal_exit!(

src/dev_aid/gen_docs.rs

Lines changed: 144 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ use crate::config::GenDocs;
22
use crate::dev_aid::port_diagram;
33
use crate::file_position::FileText;
44
use crate::flattening::{
5-
ClockVisibility, FieldDeclKind, InterfaceDeclaration, InterfaceKind, Module,
5+
ClockVisibility, FieldDeclKind, InterfaceDeclaration, InterfaceKind, Module, NamedConstant,
6+
StructType,
67
};
78
use crate::latency::port_latency_inference::InferenceTarget;
8-
use crate::linker::{FileData, GlobalObj, LinkInfo};
9+
use crate::linker::{FileData, GlobalObj, IsExtern, LinkInfo};
910
use crate::prelude::*;
1011
use crate::typing::template::TemplateKind;
1112
use pulldown_cmark::{Options, Parser, html::push_html as md_push_html};
@@ -116,14 +117,8 @@ fn build_interface_block(md: &Module, ft: &FileText) -> String {
116117
let li = &md.link_info;
117118
let mut out = String::new();
118119

119-
if li.parameters.is_empty() {
120-
out.push_str(&format!("module {} {{\n", li.name));
121-
} else {
122-
out.push_str(&format!(
123-
"module {} {{\n",
124-
li.display_full_name_and_args(ft)
125-
));
126-
}
120+
let name = li.display_full_name_and_args::<true>(ft);
121+
out.push_str(&format!("module {name} {{\n"));
127122

128123
// Collect (source_pos, line) for clocks and fields, then sort to preserve source order.
129124
let mut items: Vec<(usize, String)> = Vec::new();
@@ -251,11 +246,8 @@ fn render_module_section(
251246
let name = &li.name;
252247
let raw_doc = li.documentation.to_string(ft);
253248

254-
let heading = if li.parameters.is_empty() {
255-
html_escape(name)
256-
} else {
257-
html_escape(&li.display_full_name_and_args(ft).to_string())
258-
};
249+
let module_name = li.display_full_name_and_args::<true>(ft);
250+
let heading = html_escape(&module_name.to_string());
259251

260252
let mut s = format!("<section class=\"module\" id=\"{name}\">\n");
261253
s.push_str(&format!(
@@ -280,6 +272,93 @@ fn render_module_section(
280272
s
281273
}
282274

275+
fn build_struct_block(typ: &StructType, ft: &FileText) -> String {
276+
let li = &typ.link_info;
277+
let name = li.display_full_name_and_args::<true>(ft);
278+
if matches!(li.is_extern, IsExtern::Builtin) {
279+
format!("__builtin__ struct {name}")
280+
} else {
281+
let mut out = format!("struct {name} {{\n",);
282+
let mut items: Vec<(usize, String)> = Vec::new();
283+
for (_, field) in &typ.fields {
284+
let decl = li.instructions[field.declaration_instruction].unwrap_declaration();
285+
items.push((
286+
field.name_span.start,
287+
format!(" {}\n", li.display_decl(None, decl, ft)),
288+
));
289+
}
290+
items.sort_by_key(|(pos, _)| *pos);
291+
for (_, line) in items {
292+
out.push_str(&line);
293+
}
294+
out.push('}');
295+
out
296+
}
297+
}
298+
299+
fn render_struct_section(
300+
typ: &StructType,
301+
ft: &FileText,
302+
current_stem: &str,
303+
index: &ModuleIndex,
304+
) -> String {
305+
let li = &typ.link_info;
306+
let name = &li.name;
307+
let raw_doc = li.documentation.to_string(ft);
308+
let struct_name = li.display_full_name_and_args::<true>(ft);
309+
let heading = html_escape(&struct_name.to_string());
310+
let mut s = format!("<section class=\"module\" id=\"{name}\">\n");
311+
s.push_str(&format!(
312+
"<div class=\"module-heading\"><h2>{heading}</h2></div>\n"
313+
));
314+
let block = build_struct_block(typ, ft);
315+
s.push_str("<div class=\"interface-block\"><pre><code class=\"language-sus\">");
316+
s.push_str(&html_escape(&block));
317+
s.push_str("</code></pre></div>\n");
318+
if !raw_doc.trim().is_empty() {
319+
s.push_str("<div class=\"doc-prose\">\n");
320+
s.push_str(&render_prose(&raw_doc, current_stem, index));
321+
s.push_str("</div>\n");
322+
}
323+
s.push_str("</section>\n");
324+
s
325+
}
326+
327+
fn build_const_block(cst: &NamedConstant, ft: &FileText) -> String {
328+
let li = &cst.link_info;
329+
let decl = li.instructions[cst.output_decl].unwrap_declaration();
330+
let return_type = &ft[decl.typ_expr.get_span()];
331+
let const_name = li.display_full_name_and_args::<true>(ft);
332+
format!("const {return_type} {const_name}")
333+
}
334+
335+
fn render_const_section(
336+
cst: &NamedConstant,
337+
ft: &FileText,
338+
current_stem: &str,
339+
index: &ModuleIndex,
340+
) -> String {
341+
let li = &cst.link_info;
342+
let name = &li.name;
343+
let raw_doc = li.documentation.to_string(ft);
344+
let heading = html_escape(&li.display_full_name_and_args::<true>(ft).to_string());
345+
let mut s = format!("<section class=\"module\" id=\"{name}\">\n");
346+
s.push_str(&format!(
347+
"<div class=\"module-heading\"><h2>{heading}</h2></div>\n"
348+
));
349+
let block = build_const_block(cst, ft);
350+
s.push_str("<div class=\"interface-block\"><pre><code class=\"language-sus\">");
351+
s.push_str(&html_escape(&block));
352+
s.push_str("</code></pre></div>\n");
353+
if !raw_doc.trim().is_empty() {
354+
s.push_str("<div class=\"doc-prose\">\n");
355+
s.push_str(&render_prose(&raw_doc, current_stem, index));
356+
s.push_str("</div>\n");
357+
}
358+
s.push_str("</section>\n");
359+
s
360+
}
361+
283362
fn generate_file_html(
284363
file_stem: &str,
285364
linker: &Linker,
@@ -320,59 +399,81 @@ fn generate_file_html(
320399
for stem in all_stems {
321400
if stem == file_stem {
322401
html.push_str(&format!(
323-
"<li><a href=\"{stem}.html\" class=\"sidebar-current\">{stem}</a></li>\n"
402+
"<li><a class=\"language-item-ref sidebar-current\" href=\"{stem}.html\">{stem}</a></li>\n"
324403
));
325404
} else {
326-
html.push_str(&format!("<li><a href=\"{stem}.html\">{stem}</a></li>\n"));
405+
html.push_str(&format!(
406+
"<li><a class=\"language-item-ref\" href=\"{stem}.html\">{stem}</a></li>\n"
407+
));
327408
}
328409
}
329410
html.push_str("</ul>\n");
330411
}
331412

332413
if has_structs {
333-
html.push_str("<p class=\"sidebar-title\">Structs</p>\n<ul>\n");
414+
html.push_str("<a href=\"#Types\" class=\"sidebar-title\">Types</a>\n<ul>\n");
334415
for obj_id in &file_data.associated_values {
335416
let GlobalObj::Type(typ_id) = obj_id else {
336417
continue;
337418
};
338419
let name = &linker.globals.types[*typ_id].link_info.name;
339-
html.push_str(&format!("<li><a href=\"#{name}\">{name}</a></li>\n"));
420+
html.push_str(&format!(
421+
"<li><a class=\"language-item-ref\" href=\"#{name}\">{name}</a></li>\n"
422+
));
340423
}
341424
html.push_str("</ul>\n");
342425
}
343426

344427
if has_modules {
345-
html.push_str("<p class=\"sidebar-title\">Modules</p>\n<ul>\n");
428+
html.push_str("<a href=\"#Modules\" class=\"sidebar-title\">Modules</a>\n<ul>\n");
346429
for obj_id in &file_data.associated_values {
347430
let GlobalObj::Module(md_id) = obj_id else {
348431
continue;
349432
};
350433
let name = &linker.globals.modules[*md_id].link_info.name;
351-
html.push_str(&format!("<li><a href=\"#{name}\">{name}</a></li>\n"));
434+
html.push_str(&format!(
435+
"<li><a class=\"language-item-ref\" href=\"#{name}\">{name}</a></li>\n"
436+
));
352437
}
353438
html.push_str("</ul>\n");
354439
}
355440

356441
if has_consts {
357-
html.push_str("<p class=\"sidebar-title\">Compile-Time Functions</p>\n<ul>\n");
442+
html.push_str("<a href=\"#CompileTimeFunctions\" class=\"sidebar-title\">Compile-Time Functions</a>\n<ul>\n");
358443
for obj_id in &file_data.associated_values {
359444
let GlobalObj::Constant(const_id) = obj_id else {
360445
continue;
361446
};
362447
let name = &linker.globals.constants[*const_id].link_info.name;
363-
html.push_str(&format!("<li><a href=\"#{name}\">{name}</a></li>\n"));
448+
html.push_str(&format!(
449+
"<li><a class=\"language-item-ref\" href=\"#{name}\">{name}</a></li>\n"
450+
));
364451
}
365452
html.push_str("</ul>\n");
366453
}
367454

368455
html.push_str("</aside>\n");
369456

370457
html.push_str("<div class=\"doc-main\">\n");
371-
372458
html.push_str(&format!("<h1 class=\"page-title\">{file_stem}</h1>\n"));
373459

374-
// TODO Add structs
460+
if has_structs {
461+
html.push_str("<h2 class=\"doc-section\" id=\"Types\">Types</h2>\n");
462+
for obj_id in &file_data.associated_values {
463+
let GlobalObj::Type(typ_id) = obj_id else {
464+
continue;
465+
};
466+
let typ = &linker.globals.types[*typ_id];
467+
html.push_str(&render_struct_section(
468+
typ,
469+
&file_data.file_text,
470+
file_stem,
471+
index,
472+
));
473+
}
474+
}
375475
if has_modules {
476+
html.push_str("<h2 class=\"doc-section\" id=\"Modules\">Modules</h2>\n");
376477
for obj_id in &file_data.associated_values {
377478
let GlobalObj::Module(md_id) = obj_id else {
378479
continue;
@@ -385,10 +486,26 @@ fn generate_file_html(
385486
index,
386487
));
387488
}
388-
html.push_str("</div>\n");
389489
}
390-
// TODO Add consts
490+
if has_consts {
491+
html.push_str(
492+
"<h2 class=\"doc-section\" id=\"CompileTimeFunctions\">Compile-Time Functions</h2>\n",
493+
);
494+
for obj_id in &file_data.associated_values {
495+
let GlobalObj::Constant(const_id) = obj_id else {
496+
continue;
497+
};
498+
let cst = &linker.globals.constants[*const_id];
499+
html.push_str(&render_const_section(
500+
cst,
501+
&file_data.file_text,
502+
file_stem,
503+
index,
504+
));
505+
}
506+
}
391507

508+
html.push_str("</div>\n");
392509
html.push_str("</div>\n</main>\n");
393510
html.push_str(&format!(
394511
"<script src=\"{host}/docs/highlight.js\"></script>\n"

src/dev_aid/lsp/hover_info.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ pub fn hover(info: LocationInfo, linker: &Linker) -> Vec<MarkedString> {
150150
hover.documentation(&link_info.documentation, file);
151151
hover.sus_code(
152152
link_info
153-
.display_full_name_and_args(&file.file_text)
153+
.display_full_name_and_args::<true>(&file.file_text)
154154
.to_string(),
155155
);
156156
match global {

src/flattening/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ pub struct StructType {
114114
/// Created in Stage 1: Initialization
115115
///
116116
/// [StructField::declaration_instruction] are set in Stage 2: Flattening
117-
fields: FlatAlloc<StructField, StructFieldIDMarker>,
117+
pub fields: FlatAlloc<StructField, StructFieldIDMarker>,
118118
}
119119

120120
/// Represents a field in a struct

src/to_string.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,20 @@ impl LinkInfo {
128128
}) => f.write_str(&file_text[*decl_span]),
129129
})
130130
}
131-
pub fn display_full_name_and_args<'s>(&'s self, file_text: &'s FileText) -> impl Display + 's {
132-
self.display_with_template_args(&self.parameters, |f, (_, t)| {
133-
self.display_template_arg(file_text, t).fmt(f)
131+
/// set ´TIDY: true´ for a simplified display. Just `bool` instead of `bool #()`
132+
pub fn display_full_name_and_args<'s, const TIDY: bool>(
133+
&'s self,
134+
file_text: &'s FileText,
135+
) -> impl Display + 's {
136+
FmtWrapper(|f| {
137+
if self.parameters.is_empty() && TIDY {
138+
self.display_full_name().fmt(f)
139+
} else {
140+
self.display_with_template_args(&self.parameters, |f, (_, t)| {
141+
self.display_template_arg(file_text, t).fmt(f)
142+
})
143+
.fmt(f)
144+
}
134145
})
135146
}
136147
pub fn display_with_template_args<'s, T: 's, Iter: Iterator<Item = T> + Clone + 's>(
@@ -139,11 +150,8 @@ impl LinkInfo {
139150
func: impl Fn(&mut Formatter<'_>, T) -> std::fmt::Result + 's,
140151
) -> impl Display + 's {
141152
let template_args = display_join(", ", iter, func);
142-
FmtWrapper(move |f| {
143-
let full_name = self.display_full_name();
144-
145-
write!(f, "{full_name} #({template_args})")
146-
})
153+
let full_name = self.display_full_name();
154+
FmtWrapper(move |f| write!(f, "{full_name} #({template_args})"))
147155
}
148156
}
149157

@@ -1061,7 +1069,9 @@ impl Module {
10611069
}
10621070

10631071
pub fn display_all_ports_info<'s>(&'s self, file_text: &'s FileText) -> impl Display {
1064-
let full_name_with_args = self.link_info.display_full_name_and_args(file_text);
1072+
let full_name_with_args = self
1073+
.link_info
1074+
.display_full_name_and_args::<false>(file_text);
10651075

10661076
FmtWrapper(move |f| {
10671077
write!(f, "module {full_name_with_args}:")?;

0 commit comments

Comments
 (0)