Created scope and idents for module docs, but they appear to be empty when the doc links function tries to use them

This commit is contained in:
Chadtech 2021-05-22 14:06:56 -04:00
parent b22612b93c
commit 12c0067348
9 changed files with 144 additions and 104 deletions

2
Cargo.lock generated
View file

@ -3013,6 +3013,8 @@ dependencies = [
"roc_can", "roc_can",
"roc_collections", "roc_collections",
"roc_load", "roc_load",
"roc_module",
"roc_region",
] ]
[[package]] [[package]]

View file

@ -36,6 +36,7 @@ pub struct ModuleOutput {
pub problems: Vec<Problem>, pub problems: Vec<Problem>,
pub ident_ids: IdentIds, pub ident_ids: IdentIds,
pub references: MutSet<Symbol>, pub references: MutSet<Symbol>,
pub scope: Scope,
} }
// TODO trim these down // TODO trim these down
@ -309,6 +310,7 @@ where
} }
Ok(ModuleOutput { Ok(ModuleOutput {
scope,
aliases, aliases,
rigid_variables, rigid_variables,
declarations, declarations,

View file

@ -1,4 +1,4 @@
use roc_collections::all::{ImMap, MutSet}; use roc_collections::all::{MutSet, SendMap};
use roc_module::ident::{Ident, Lowercase}; use roc_module::ident::{Ident, Lowercase};
use roc_module::symbol::{IdentIds, ModuleId, Symbol}; use roc_module::symbol::{IdentIds, ModuleId, Symbol};
use roc_problem::can::RuntimeError; use roc_problem::can::RuntimeError;
@ -10,14 +10,14 @@ use roc_types::types::{Alias, Type};
pub struct Scope { pub struct Scope {
/// All the identifiers in scope, mapped to were they were defined and /// All the identifiers in scope, mapped to were they were defined and
/// the Symbol they resolve to. /// the Symbol they resolve to.
idents: ImMap<Ident, (Symbol, Region)>, idents: SendMap<Ident, (Symbol, Region)>,
/// A cache of all the symbols in scope. This makes lookups much /// A cache of all the symbols in scope. This makes lookups much
/// faster when checking for unused defs and unused arguments. /// faster when checking for unused defs and unused arguments.
symbols: ImMap<Symbol, Region>, symbols: SendMap<Symbol, Region>,
/// The type aliases currently in scope /// The type aliases currently in scope
aliases: ImMap<Symbol, Alias>, aliases: SendMap<Symbol, Alias>,
/// The current module being processed. This will be used to turn /// The current module being processed. This will be used to turn
/// unqualified idents into Symbols. /// unqualified idents into Symbols.
@ -28,7 +28,7 @@ impl Scope {
pub fn new(home: ModuleId, var_store: &mut VarStore) -> Scope { pub fn new(home: ModuleId, var_store: &mut VarStore) -> Scope {
use roc_types::solved_types::{BuiltinAlias, FreeVars}; use roc_types::solved_types::{BuiltinAlias, FreeVars};
let solved_aliases = roc_types::builtin_aliases::aliases(); let solved_aliases = roc_types::builtin_aliases::aliases();
let mut aliases = ImMap::default(); let mut aliases = SendMap::default();
for (symbol, builtin_alias) in solved_aliases { for (symbol, builtin_alias) in solved_aliases {
let BuiltinAlias { region, vars, typ } = builtin_alias; let BuiltinAlias { region, vars, typ } = builtin_alias;
@ -58,7 +58,7 @@ impl Scope {
Scope { Scope {
home, home,
idents: Symbol::default_in_scope(), idents: Symbol::default_in_scope(),
symbols: ImMap::default(), symbols: SendMap::default(),
aliases, aliases,
} }
} }

View file

@ -1,7 +1,7 @@
use crate::expr::constrain_decls; use crate::expr::constrain_decls;
use roc_builtins::std::StdLib; use roc_builtins::std::StdLib;
use roc_can::constraint::{Constraint, LetConstraint}; use roc_can::constraint::{Constraint, LetConstraint};
use roc_can::module::ModuleOutput; use roc_can::def::Declaration;
use roc_collections::all::{MutMap, MutSet, SendMap}; use roc_collections::all::{MutMap, MutSet, SendMap};
use roc_module::symbol::{ModuleId, Symbol}; use roc_module::symbol::{ModuleId, Symbol};
use roc_region::all::{Located, Region}; use roc_region::all::{Located, Region};
@ -22,16 +22,18 @@ pub struct ConstrainedModule {
pub constraint: Constraint, pub constraint: Constraint,
} }
pub fn constrain_module(module: &ModuleOutput, home: ModuleId) -> Constraint { pub fn constrain_module(
aliases: &MutMap<Symbol, Alias>,
declarations: &[Declaration],
home: ModuleId,
) -> Constraint {
let mut send_aliases = SendMap::default(); let mut send_aliases = SendMap::default();
for (symbol, alias) in module.aliases.iter() { for (symbol, alias) in aliases.iter() {
send_aliases.insert(*symbol, alias.clone()); send_aliases.insert(*symbol, alias.clone());
} }
let decls = &module.declarations; constrain_decls(home, declarations)
constrain_decls(home, decls)
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View file

@ -1,8 +1,10 @@
use crate::docs::DocEntry::DetatchedDoc; use crate::docs::DocEntry::DetatchedDoc;
use crate::docs::TypeAnnotation::{Apply, BoundVariable, Record, TagUnion}; use crate::docs::TypeAnnotation::{Apply, BoundVariable, Record, TagUnion};
use inlinable_string::InlinableString; use inlinable_string::InlinableString;
use roc_can::scope::Scope;
use roc_collections::all::MutMap;
use roc_module::ident::ModuleName; use roc_module::ident::ModuleName;
use roc_module::symbol::IdentIds; use roc_module::symbol::{IdentIds, Interns, ModuleId};
use roc_parse::ast; use roc_parse::ast;
use roc_parse::ast::CommentOrNewline; use roc_parse::ast::CommentOrNewline;
use roc_parse::ast::{AssignedField, Def}; use roc_parse::ast::{AssignedField, Def};
@ -10,18 +12,19 @@ use roc_region::all::Located;
// Documentation generation requirements // Documentation generation requirements
#[derive(Debug, Clone)] #[derive(Debug)]
pub struct Documentation { pub struct Documentation {
pub name: String, pub name: String,
pub version: String, pub version: String,
pub docs: String, pub docs: String,
pub modules: Vec<ModuleDocumentation>, pub modules: Vec<(MutMap<ModuleId, ModuleDocumentation>, Interns)>,
} }
#[derive(Debug, Clone)] #[derive(Debug)]
pub struct ModuleDocumentation { pub struct ModuleDocumentation {
pub name: String, pub name: String,
pub entries: Vec<DocEntry>, pub entries: Vec<DocEntry>,
pub scope: Scope,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -75,19 +78,21 @@ pub struct Tag {
} }
pub fn generate_module_docs<'a>( pub fn generate_module_docs<'a>(
scope: Scope,
module_name: ModuleName, module_name: ModuleName,
exposed_ident_ids: &'a IdentIds, ident_ids: &'a IdentIds,
parsed_defs: &'a [Located<ast::Def<'a>>], parsed_defs: &'a [Located<ast::Def<'a>>],
) -> ModuleDocumentation { ) -> ModuleDocumentation {
let (entries, _) = let (entries, _) =
parsed_defs parsed_defs
.iter() .iter()
.fold((vec![], None), |(acc, maybe_comments_after), def| { .fold((vec![], None), |(acc, maybe_comments_after), def| {
generate_entry_doc(exposed_ident_ids, acc, maybe_comments_after, &def.value) generate_entry_doc(ident_ids, acc, maybe_comments_after, &def.value)
}); });
ModuleDocumentation { ModuleDocumentation {
name: module_name.as_str().to_string(), name: module_name.as_str().to_string(),
scope,
entries, entries,
} }
} }
@ -117,7 +122,7 @@ fn detatched_docs_from_comments_and_new_lines<'a>(
} }
fn generate_entry_doc<'a>( fn generate_entry_doc<'a>(
exposed_ident_ids: &'a IdentIds, ident_ids: &'a IdentIds,
mut acc: Vec<DocEntry>, mut acc: Vec<DocEntry>,
before_comments_or_new_lines: Option<&'a [roc_parse::ast::CommentOrNewline<'a>]>, before_comments_or_new_lines: Option<&'a [roc_parse::ast::CommentOrNewline<'a>]>,
def: &'a ast::Def<'a>, def: &'a ast::Def<'a>,
@ -135,13 +140,13 @@ fn generate_entry_doc<'a>(
acc.push(DetatchedDoc(detatched_doc)); acc.push(DetatchedDoc(detatched_doc));
} }
generate_entry_doc(exposed_ident_ids, acc, Some(comments_or_new_lines), sub_def) generate_entry_doc(ident_ids, acc, Some(comments_or_new_lines), sub_def)
} }
Def::SpaceAfter(sub_def, comments_or_new_lines) => { Def::SpaceAfter(sub_def, comments_or_new_lines) => {
let (new_acc, _) = let (new_acc, _) =
// If there are comments before, attach to this definition // If there are comments before, attach to this definition
generate_entry_doc(exposed_ident_ids, acc, before_comments_or_new_lines, sub_def); generate_entry_doc(ident_ids, acc, before_comments_or_new_lines, sub_def);
// Comments after a definition are attached to the next definition // Comments after a definition are attached to the next definition
(new_acc, Some(comments_or_new_lines)) (new_acc, Some(comments_or_new_lines))
@ -150,7 +155,7 @@ fn generate_entry_doc<'a>(
Def::Annotation(loc_pattern, _loc_ann) => match loc_pattern.value { Def::Annotation(loc_pattern, _loc_ann) => match loc_pattern.value {
Pattern::Identifier(identifier) => { Pattern::Identifier(identifier) => {
// Check if the definition is exposed // Check if the definition is exposed
if exposed_ident_ids if ident_ids
.get_id(&InlinableString::from(identifier)) .get_id(&InlinableString::from(identifier))
.is_some() .is_some()
{ {
@ -170,7 +175,7 @@ fn generate_entry_doc<'a>(
Def::AnnotatedBody { ann_pattern, .. } => match ann_pattern.value { Def::AnnotatedBody { ann_pattern, .. } => match ann_pattern.value {
Pattern::Identifier(identifier) => { Pattern::Identifier(identifier) => {
// Check if the definition is exposed // Check if the definition is exposed
if exposed_ident_ids if ident_ids
.get_id(&InlinableString::from(identifier)) .get_id(&InlinableString::from(identifier))
.is_some() .is_some()
{ {

View file

@ -3502,9 +3502,14 @@ fn fabricate_effects_module<'a>(
problems: can_env.problems, problems: can_env.problems,
ident_ids: can_env.ident_ids, ident_ids: can_env.ident_ids,
references: MutSet::default(), references: MutSet::default(),
scope,
}; };
let constraint = constrain_module(&module_output, module_id); let constraint = constrain_module(
&module_output.aliases,
&module_output.declarations,
module_id,
);
let module = Module { let module = Module {
module_id, module_id,
@ -3521,6 +3526,7 @@ fn fabricate_effects_module<'a>(
let module_docs = ModuleDocumentation { let module_docs = ModuleDocumentation {
name: String::from(name), name: String::from(name),
entries: Vec::new(), entries: Vec::new(),
scope: module_output.scope,
}; };
let constrained_module = ConstrainedModule { let constrained_module = ConstrainedModule {
@ -3602,18 +3608,6 @@ where
.. ..
} = parsed; } = parsed;
// Generate documentation information
// TODO: store timing information?
let module_docs = match module_name {
ModuleNameEnum::PkgConfig => None,
ModuleNameEnum::App(_) => None,
ModuleNameEnum::Interface(name) => Some(crate::docs::generate_module_docs(
name.as_str().into(),
&exposed_ident_ids,
&parsed_defs,
)),
};
let mut var_store = VarStore::default(); let mut var_store = VarStore::default();
let canonicalized = canonicalize_module_defs( let canonicalized = canonicalize_module_defs(
&arena, &arena,
@ -3634,7 +3628,24 @@ where
match canonicalized { match canonicalized {
Ok(module_output) => { Ok(module_output) => {
let constraint = constrain_module(&module_output, module_id); // Generate documentation information
// TODO: store timing information?
let module_docs = match module_name {
ModuleNameEnum::PkgConfig => None,
ModuleNameEnum::App(_) => None,
ModuleNameEnum::Interface(name) => Some(crate::docs::generate_module_docs(
module_output.scope,
name.as_str().into(),
&module_output.ident_ids,
&parsed_defs,
)),
};
let constraint = constrain_module(
&module_output.aliases,
&module_output.declarations,
module_id,
);
let module = Module { let module = Module {
module_id, module_id,

View file

@ -1,6 +1,6 @@
use crate::ident::Ident; use crate::ident::Ident;
use inlinable_string::InlinableString; use inlinable_string::InlinableString;
use roc_collections::all::{default_hasher, ImMap, MutMap}; use roc_collections::all::{default_hasher, MutMap, SendMap};
use roc_region::all::Region; use roc_region::all::Region;
use std::collections::HashMap; use std::collections::HashMap;
use std::{fmt, u32}; use std::{fmt, u32};
@ -697,8 +697,8 @@ macro_rules! define_builtins {
/// and what symbols they should resolve to. /// and what symbols they should resolve to.
/// ///
/// This is for type aliases like `Int` and `Str` and such. /// This is for type aliases like `Int` and `Str` and such.
pub fn default_in_scope() -> ImMap<Ident, (Symbol, Region)> { pub fn default_in_scope() -> SendMap<Ident, (Symbol, Region)> {
let mut scope = ImMap::default(); let mut scope = SendMap::default();
$( $(
$( $(

View file

@ -12,6 +12,8 @@ pulldown-cmark = { version = "0.8", default-features = false }
roc_load = { path = "../compiler/load" } roc_load = { path = "../compiler/load" }
roc_builtins = { path = "../compiler/builtins" } roc_builtins = { path = "../compiler/builtins" }
roc_can = { path = "../compiler/can" } roc_can = { path = "../compiler/can" }
roc_module = { path = "../compiler/module" }
roc_region = { path = "../compiler/region" }
roc_collections = { path = "../compiler/collections" } roc_collections = { path = "../compiler/collections" }
bumpalo = { version = "3.2", features = ["collections"] } bumpalo = { version = "3.2", features = ["collections"] }

View file

@ -4,18 +4,22 @@ use roc_can::builtins::builtin_defs_map;
use roc_load::docs::{DocEntry, TypeAnnotation}; use roc_load::docs::{DocEntry, TypeAnnotation};
use roc_load::docs::{ModuleDocumentation, RecordField}; use roc_load::docs::{ModuleDocumentation, RecordField};
use roc_load::file::LoadingProblem; use roc_load::file::LoadingProblem;
use roc_module::symbol::{Interns, ModuleId};
use std::fs; use std::fs;
extern crate roc_load; extern crate roc_load;
use bumpalo::Bump; use bumpalo::Bump;
use roc_can::scope::Scope;
use roc_collections::all::MutMap; use roc_collections::all::MutMap;
use roc_region::all::Region;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
pub fn generate(filenames: Vec<PathBuf>, std_lib: StdLib, build_dir: &Path) { pub fn generate(filenames: Vec<PathBuf>, std_lib: StdLib, build_dir: &Path) {
let files_docs = files_to_documentations(filenames, std_lib); let files_docs = files_to_documentations(filenames, std_lib);
// //
// TODO: get info from a file like "elm.json" // TODO: get info from a file like "elm.json"
let package = roc_load::docs::Documentation { let mut package = roc_load::docs::Documentation {
name: "roc/builtins".to_string(), name: "roc/builtins".to_string(),
version: "1.0.0".to_string(), version: "1.0.0".to_string(),
docs: "Package introduction or README.".to_string(), docs: "Package introduction or README.".to_string(),
@ -45,36 +49,44 @@ pub fn generate(filenames: Vec<PathBuf>, std_lib: StdLib, build_dir: &Path) {
) )
.expect("TODO gracefully handle failing to make the favicon"); .expect("TODO gracefully handle failing to make the favicon");
let template_html = include_str!("./static/index.html"); let template_html = include_str!("./static/index.html").replace(
"<!-- Module links -->",
render_sidebar(
package
.modules
.iter()
.flat_map(|(docs_by_id, _)| docs_by_id.values()),
)
.as_str(),
);
// Write each package's module docs html file // Write each package's module docs html file
for module in &package.modules { for (docs_by_id, interns) in package.modules.iter_mut() {
let mut filename = String::new(); for module in docs_by_id.values_mut() {
filename.push_str(module.name.as_str()); let mut filename = String::new();
filename.push_str(".html"); filename.push_str(module.name.as_str());
filename.push_str(".html");
let rendered_module = template_html let rendered_module = template_html
.replace( .replace(
"<!-- Module links -->", "<!-- Package Name and Version -->",
render_module_links(&package.modules).as_str(), render_name_and_version(package.name.as_str(), package.version.as_str())
) .as_str(),
.replace( )
"<!-- Package Name and Version -->", .replace(
render_name_and_version(package.name.as_str(), package.version.as_str()).as_str(), "<!-- Module Docs -->",
) render_main_content(interns, module).as_str(),
.replace( );
"<!-- Module Docs -->",
render_main_content(&module).as_str(),
);
fs::write(build_dir.join(filename), rendered_module) fs::write(build_dir.join(filename), rendered_module)
.expect("TODO gracefully handle failing to write html"); .expect("TODO gracefully handle failing to write html");
}
} }
println!("🎉 Docs generated in {}", build_dir.display()); println!("🎉 Docs generated in {}", build_dir.display());
} }
fn render_main_content(module: &ModuleDocumentation) -> String { fn render_main_content(interns: &Interns, module: &mut ModuleDocumentation) -> String {
let mut buf = String::new(); let mut buf = String::new();
buf.push_str( buf.push_str(
@ -119,11 +131,15 @@ fn render_main_content(module: &ModuleDocumentation) -> String {
); );
if let Some(docs) = &doc_def.docs { if let Some(docs) = &doc_def.docs {
buf.push_str(markdown_to_html(docs.to_string()).as_str()); buf.push_str(
markdown_to_html(&mut module.scope, interns, docs.to_string()).as_str(),
);
} }
} }
DocEntry::DetatchedDoc(docs) => { DocEntry::DetatchedDoc(docs) => {
buf.push_str(markdown_to_html(docs.to_string()).as_str()); buf.push_str(
markdown_to_html(&mut module.scope, interns, docs.to_string()).as_str(),
);
} }
}; };
} }
@ -195,7 +211,7 @@ fn render_name_and_version(name: &str, version: &str) -> String {
buf buf
} }
fn render_module_links(modules: &[ModuleDocumentation]) -> String { fn render_sidebar<'a, I: Iterator<Item = &'a ModuleDocumentation>>(modules: I) -> String {
let mut buf = String::new(); let mut buf = String::new();
for module in modules { for module in modules {
@ -269,7 +285,7 @@ fn render_module_links(modules: &[ModuleDocumentation]) -> String {
pub fn files_to_documentations( pub fn files_to_documentations(
filenames: Vec<PathBuf>, filenames: Vec<PathBuf>,
std_lib: StdLib, std_lib: StdLib,
) -> Vec<ModuleDocumentation> { ) -> Vec<(MutMap<ModuleId, ModuleDocumentation>, Interns)> {
let arena = Bump::new(); let arena = Bump::new();
let mut files_docs = vec![]; let mut files_docs = vec![];
@ -286,7 +302,7 @@ pub fn files_to_documentations(
8, // TODO: Is it okay to hardcode ptr_bytes here? I think it should be fine since we'er only type checking (also, 8 => 32bit system) 8, // TODO: Is it okay to hardcode ptr_bytes here? I think it should be fine since we'er only type checking (also, 8 => 32bit system)
builtin_defs_map, builtin_defs_map,
) { ) {
Ok(mut loaded) => files_docs.extend(loaded.documentation.drain().map(|x| x.1)), Ok(loaded) => files_docs.push((loaded.documentation, loaded.interns)),
Err(LoadingProblem::FormattedReport(report)) => { Err(LoadingProblem::FormattedReport(report)) => {
println!("{}", report); println!("{}", report);
panic!(); panic!();
@ -294,6 +310,7 @@ pub fn files_to_documentations(
Err(e) => panic!("{:?}", e), Err(e) => panic!("{:?}", e),
} }
} }
files_docs files_docs
} }
@ -410,11 +427,7 @@ fn type_annotation_to_html(indent_level: usize, buf: &mut String, type_ann: &Typ
} }
} }
fn insert_doc_links(markdown: String) -> String { fn insert_doc_links(scope: &mut Scope, interns: &Interns, markdown: String) -> String {
insert_doc_links_help(markdown)
}
fn insert_doc_links_help(markdown: String) -> String {
let buf = &markdown; let buf = &markdown;
let mut result = String::new(); let mut result = String::new();
@ -440,12 +453,18 @@ fn insert_doc_links_help(markdown: String) -> String {
result = buf.chars().take(from).collect(); result = buf.chars().take(from).collect();
let doc_link = let doc_link = make_doc_link(
make_doc_link(buf.chars().skip(from + 1).take(index - from).collect()); scope,
interns,
&buf.chars()
.skip(from + 1)
.take(index - from)
.collect::<String>(),
);
result.insert_str(from, doc_link.as_str()); result.insert_str(from, doc_link.as_str());
let remainder = insert_doc_links_help(after_link.collect()); let remainder = insert_doc_links(scope, interns, after_link.collect());
result.push_str(remainder.as_str()); result.push_str(remainder.as_str());
break; break;
@ -457,48 +476,45 @@ fn insert_doc_links_help(markdown: String) -> String {
result result
} }
fn make_doc_link(doc_item: String) -> String { fn make_doc_link(scope: &mut Scope, interns: &Interns, doc_item: &str) -> String {
let mut label = String::new(); match scope.lookup(&doc_item.into(), Region::zero()) {
let mut link = String::new(); Ok(symbol) => {
let module_str = symbol.module_string(interns);
let ident_str = symbol.ident_string(interns);
let mut parts = doc_item.split('.').into_iter().peekable(); let mut link = String::new();
while let Some(part) = parts.next() { link.push_str(module_str);
label.push_str(part); link.push_str(".html#");
link.push_str(ident_str);
match parts.peek() { let mut buf = String::new();
None => {
link.push_str(".html#");
link.push_str(part);
}
Some(_) => {
link.push_str(part);
link.push('.');
label.push('.'); buf.push('[');
} buf.push_str(doc_item);
buf.push_str("](");
buf.push_str(link.as_str());
buf.push(')');
buf
}
Err(_) => {
panic!(
"Could not find symbol in scope for module link : {}",
doc_item
)
} }
} }
let mut buf = String::new();
buf.push('[');
buf.push_str(label.as_str());
buf.push_str("](");
buf.push_str(link.as_str());
buf.push(')');
buf
} }
fn markdown_to_html(markdown: String) -> String { fn markdown_to_html(scope: &mut Scope, interns: &Interns, markdown: String) -> String {
use pulldown_cmark::CodeBlockKind; use pulldown_cmark::CodeBlockKind;
use pulldown_cmark::CowStr; use pulldown_cmark::CowStr;
use pulldown_cmark::Event; use pulldown_cmark::Event;
use pulldown_cmark::Tag::*; use pulldown_cmark::Tag::*;
let markdown_with_links = insert_doc_links(markdown); let markdown_with_links = insert_doc_links(scope, interns, markdown);
let markdown_options = pulldown_cmark::Options::empty(); let markdown_options = pulldown_cmark::Options::empty();
let mut docs_parser = vec![]; let mut docs_parser = vec![];