Skip to content

Commit

Permalink
Start work on documentation generator
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Mar 25, 2023
1 parent fa7074e commit 5a7d3b2
Show file tree
Hide file tree
Showing 26 changed files with 1,122 additions and 55 deletions.
2 changes: 1 addition & 1 deletion crates/rune-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ codespan-reporting = "0.11.1"
anyhow = { version = "1.0.70", features = ["std"] }
structopt = { version = "0.3.26", default-features = false, features = ["wrap_help", "suggestions", "color"] }

rune = { version = "0.12.3", path = "../rune", features = ["workspace"] }
rune = { version = "0.12.3", path = "../rune", features = ["workspace", "doc"] }
rune-modules = { version = "0.12.3", path = "../rune-modules", features = ["full", "experiments", "capture-io"] }

[build-dependencies]
Expand Down
8 changes: 7 additions & 1 deletion crates/rune-cli/src/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,17 @@ pub(crate) fn run(
queue.push_back(ItemBuf::new());
walk_items(io, &doc_finder, &mut queue)?;

let root = Path::new("target/rune-doc");
rune::doc::write_html(&context, root)?;

let mut it = context.iter_meta().peekable();

while let Some((item, meta)) = it.next() {
if !meta.docs.is_empty() {
let args = meta.docs.args().join(", ");
let args = match meta.docs.args() {
Some(args) => args.join(", "),
None => String::from("?"),
};

writeln!(io.stdout, "fn {item}({args}):")?;
writeln!(io.stdout)?;
Expand Down
14 changes: 13 additions & 1 deletion crates/rune-macros/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ impl Function {
}

/// Expand the function declaration.
pub(crate) fn expand(self, attrs: FunctionAttrs) -> Result<TokenStream, Error> {
pub(crate) fn expand(mut self, attrs: FunctionAttrs) -> Result<TokenStream, Error> {
let real_fn_path = if attrs.path.is_self() || self.takes_self {
let mut segments = Punctuated::default();

Expand Down Expand Up @@ -265,6 +265,18 @@ impl Function {
(_, None, true) => "async_function",
};

if instance && !self.takes_self {
// Ensure that the first argument is called `self`.
if let Some(argument) = self.arguments.elems.first_mut() {
let span = argument.span();

*argument = syn::Expr::Lit(syn::ExprLit {
attrs: Vec::new(),
lit: syn::Lit::Str(syn::LitStr::new("self", span)),
});
}
}

let meta_kind = syn::Ident::new(function, self.sig.span());
let mut stream = TokenStream::new();

Expand Down
5 changes: 5 additions & 0 deletions crates/rune/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ default = ["emit"]
emit = ["codespan-reporting"]
bench = []
workspace = ["toml", "toml-spanned-value", "semver", "relative-path", "serde-hashkey"]
doc = ["rust-embed", "handlebars", "pulldown-cmark", "syntect"]

[dependencies]
thiserror = "1.0.40"
Expand All @@ -44,6 +45,10 @@ semver = { version = "1.0.17", optional = true, features = ["serde"] }
relative-path = { version = "1.8.0", optional = true, features = ["serde"] }
serde-hashkey = { version = "0.4.5", optional = true }
linked-hash-map = "0.5.6"
pulldown-cmark = { version = "0.9.2", optional = true }
rust-embed = { version = "6.6.0", optional = true }
handlebars = { version = "4.3.6", optional = true }
syntect = { version = "5.0.0", optional = true }

rune-macros = { version = "=0.12.3", path = "../rune-macros" }

Expand Down
82 changes: 50 additions & 32 deletions crates/rune/src/compile/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ impl Context {
}

for (key, inst) in &module.associated_functions {
self.install_associated_function(key, inst)?;
self.install_associated_function(module, key, inst)?;
}

Ok(())
Expand Down Expand Up @@ -373,6 +373,17 @@ impl Context {
self.meta.get(name)
}

/// Lookup function info based on item.
pub(crate) fn lookup_function_info(&self, item: &Item) -> Option<&ContextSignature> {
let meta = self.meta.get(item)?;

if let ContextMetaKind::Function { type_hash, .. } = &meta.kind {
self.functions_info.get(type_hash)
} else {
None
}
}

/// Iterate over all metadata in the context.
pub fn iter_meta(&self) -> impl Iterator<Item = (&Item, &ContextMeta)> + '_ {
self.meta.iter().map(|(item, meta)| (item.as_ref(), meta))
Expand Down Expand Up @@ -520,11 +531,7 @@ impl Context {
variant,
};

self.install_meta(ContextMeta {
item,
kind,
docs: Docs::default(),
})?;
self.install_meta(ContextMeta::new(module, item, kind, Docs::default()))?;
}

ContextMetaKind::Enum { type_hash }
Expand All @@ -534,7 +541,7 @@ impl Context {
ContextMetaKind::Unknown { type_hash }
};

self.install_meta(ContextMeta { item, kind, docs })?;
self.install_meta(ContextMeta::new(module, item, kind, docs))?;
Ok(())
}

Expand Down Expand Up @@ -593,14 +600,15 @@ impl Context {

self.functions.insert(hash, f.handler.clone());

self.install_meta(ContextMeta {
self.install_meta(ContextMeta::new(
module,
item,
kind: ContextMetaKind::Function {
ContextMetaKind::Function {
type_hash: hash,
instance_function: f.instance_function,
},
docs: f.docs.clone(),
})?;
f.docs.clone(),
))?;

Ok(())
}
Expand Down Expand Up @@ -638,19 +646,21 @@ impl Context {

self.constants.insert(hash, v.clone());

self.install_meta(ContextMeta {
self.install_meta(ContextMeta::new(
module,
item,
kind: ContextMetaKind::Const {
ContextMetaKind::Const {
const_value: v.clone(),
},
docs,
})?;
))?;

Ok(())
}

fn install_associated_function(
&mut self,
module: &Module,
key: &AssocKey,
assoc: &AssocFn,
) -> Result<(), ContextError> {
Expand Down Expand Up @@ -697,6 +707,7 @@ impl Context {
// and plain hashes.
if let (InstFnKind::Instance(name), AssocKind::Instance) = (&assoc.name, key.kind) {
let item = info.item.extended(name);
self.names.insert(&item);

let type_hash = Hash::type_hash(&item);
let hash = type_hash.with_parameters(key.parameters);
Expand All @@ -720,14 +731,15 @@ impl Context {
}

if !self.meta.contains_key(&item) {
self.install_meta(ContextMeta {
self.install_meta(ContextMeta::new(
module,
item,
kind: ContextMetaKind::Function {
ContextMetaKind::Function {
type_hash,
instance_function: true,
},
docs: assoc.docs.clone(),
})?;
assoc.docs.clone(),
))?;
}

self.functions.insert(hash, assoc.handler.clone());
Expand All @@ -745,7 +757,7 @@ impl Context {
) -> Result<(), ContextError> {
let item = module.item.extended(&*unit_type.name);
let hash = Hash::type_hash(&item);
self.add_internal_tuple(None, item.clone(), 0, || (), docs)?;
self.add_internal_tuple(module, None, item.clone(), 0, || (), docs)?;

self.install_type_info(
hash,
Expand Down Expand Up @@ -776,13 +788,14 @@ impl Context {
let enum_item = module.item.join(&internal_enum.base_type);
let enum_hash = Hash::type_hash(&enum_item);

self.install_meta(ContextMeta {
item: enum_item.clone(),
kind: ContextMetaKind::Enum {
self.install_meta(ContextMeta::new(
module,
enum_item.clone(),
ContextMetaKind::Enum {
type_hash: internal_enum.static_type.hash,
},
docs,
})?;
))?;

self.install_type_info(
enum_hash,
Expand All @@ -808,9 +821,10 @@ impl Context {
},
)?;

self.install_meta(ContextMeta {
item: item.clone(),
kind: ContextMetaKind::Variant {
self.install_meta(ContextMeta::new(
module,
item.clone(),
ContextMetaKind::Variant {
type_hash: hash,
enum_item: enum_item.clone(),
enum_hash,
Expand All @@ -820,8 +834,8 @@ impl Context {
hash,
}),
},
docs: Docs::default(),
})?;
Docs::default(),
))?;

let signature = ContextSignature::Function {
type_hash: hash,
Expand All @@ -845,6 +859,7 @@ impl Context {
/// Add a piece of internal tuple meta.
fn add_internal_tuple<C, Args>(
&mut self,
module: &Module,
enum_item: Option<(ItemBuf, Hash, usize)>,
item: ItemBuf,
args: usize,
Expand All @@ -861,18 +876,21 @@ impl Context {
let tuple = PrivTupleMeta { args, hash };

let meta = match enum_item {
Some((enum_item, enum_hash, index)) => ContextMeta {
item: item.clone(),
kind: ContextMetaKind::Variant {
Some((enum_item, enum_hash, index)) => ContextMeta::new(
module,
item.clone(),
ContextMetaKind::Variant {
type_hash,
enum_item,
enum_hash,
index,
variant: PrivVariantMeta::Tuple(tuple),
},
docs,
},
),
None => ContextMeta {
#[cfg(feature = "doc")]
module: module.item.clone(),
item: item.clone(),
kind: ContextMetaKind::Struct {
type_hash,
Expand Down
7 changes: 2 additions & 5 deletions crates/rune/src/compile/docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,8 @@ pub struct Docs {

impl Docs {
/// Get arguments associated with documentation.
pub fn args(&self) -> &[String] {
self.arguments
.as_ref()
.map(AsRef::as_ref)
.unwrap_or_default()
pub fn args(&self) -> Option<&[String]> {
self.arguments.as_ref().map(AsRef::as_ref)
}

/// Iterate over lines in the documentation.
Expand Down
15 changes: 14 additions & 1 deletion crates/rune/src/compile/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::compile::{Docs, Item, ItemBuf, ItemId, Location, ModId, Pool, Visibil
use crate::parse::{Id, ParseError, ResolveContext};
use crate::query::ImportEntry;
use crate::runtime::ConstValue;
use crate::Hash;
use crate::{Hash, Module};

/// Provides an owned human-readable description of a meta item.
#[derive(Debug, Clone)]
Expand Down Expand Up @@ -179,6 +179,9 @@ impl Doc {
/// Context metadata.
#[non_exhaustive]
pub struct ContextMeta {
/// The module that the declared item belongs to.
#[cfg(feature = "doc")]
pub module: ItemBuf,
/// The item of the returned compile meta.
pub item: ItemBuf,
/// The kind of the compile meta.
Expand All @@ -188,6 +191,16 @@ pub struct ContextMeta {
}

impl ContextMeta {
pub(crate) fn new(module: &Module, item: ItemBuf, kind: ContextMetaKind, docs: Docs) -> Self {
Self {
#[cfg(feature = "doc")]
module: module.item.clone(),
item,
kind,
docs,
}
}

/// Get the [Meta] which describes this [ContextMeta] object.
pub(crate) fn info(&self) -> Meta {
Meta {
Expand Down
4 changes: 2 additions & 2 deletions crates/rune/src/compile/names.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::collections::HashMap;
use crate::collections::BTreeMap;
use crate::compile::{Component, ComponentRef, IntoComponent};
use std::mem;

Expand Down Expand Up @@ -104,7 +104,7 @@ struct Node {
/// If the node is terminating.
term: bool,
/// The children of this node.
children: HashMap<Component, Node>,
children: BTreeMap<Component, Node>,
}

#[cfg(test)]
Expand Down
Loading

0 comments on commit 5a7d3b2

Please sign in to comment.