diff --git a/doc/src/doc/index.html b/doc/src/doc/index.html index 2d0bf331c1..dae48e7a25 100644 --- a/doc/src/doc/index.html +++ b/doc/src/doc/index.html @@ -21,6 +21,13 @@

Modules

+ {{#each directories}} + + + + {{/each}} {{#each modules}}
+ {{this}} +
diff --git a/doc/src/lib.rs b/doc/src/lib.rs index c4809f680f..146a0cf19d 100644 --- a/doc/src/lib.rs +++ b/doc/src/lib.rs @@ -21,6 +21,7 @@ extern crate log; extern crate gluon; +use std::collections::BTreeMap; use std::fs::{create_dir_all, File}; use std::io::{self, Read, Write}; use std::path::{Path, PathBuf}; @@ -46,14 +47,14 @@ use gluon::{Compiler, Thread}; pub type Error = failure::Error; pub type Result = ::std::result::Result; -#[derive(Serialize, PartialEq, Debug)] +#[derive(Serialize, PartialEq, Debug, Default)] pub struct Module { pub name: String, pub comment: String, pub record: Record, } -#[derive(Serialize, PartialEq, Debug)] +#[derive(Serialize, PartialEq, Debug, Default)] pub struct Record { pub types: Vec, pub values: Vec, @@ -231,16 +232,17 @@ fn symbol_link(index: bool, current_module: &str, param: &str) -> String { ) } -fn module_link(index: bool, current_module: &str, param: &str) -> String { +fn module_link(index: bool, directory_module: bool, current_module: &str, param: &str) -> String { let skipped = if index { 0 } else { 1 }; format!( - "{}{}.html", + "{}{}{}.html", current_module .split('.') .skip(skipped) .map(|_| "../") .format(""), - param.replace(".", "/") + param.replace(".", "/"), + if directory_module { "/index" } else { "" } ) } @@ -261,7 +263,13 @@ fn handlebars() -> Result { let param = String::deserialize(h.param(0).unwrap().value())?; let index = rc.get_root_template_name().map(|s| &s[..]) == Some(INDEX_TEMPLATE); - out.write(&module_link(index, current_module, ¶m))?; + let directory_module = h.param(1).is_some(); + out.write(&module_link( + index, + directory_module, + current_module, + ¶m, + ))?; Ok(()) } reg.register_helper("module_link", Box::new(module_link_helper)); @@ -395,17 +403,18 @@ where } pub fn generate_for_path_(thread: &Thread, path: &Path, out_path: &Path) -> Result<()> { - let mut directories = Vec::new(); + let mut directories = BTreeMap::new(); for entry in walkdir::WalkDir::new(path) { let entry = entry?; if !entry.file_type().is_file() || entry.path().extension().and_then(|ext| ext.to_str()) != Some("glu") { if entry.file_type().is_dir() { - directories.push((entry.path().to_owned(), Vec::new())); + directories.insert(entry.path().to_owned(), Vec::new()); } continue; } + let mut input = File::open(&*entry.path()).with_context(|err| { format!( "Unable to open gluon file `{}`: {}", @@ -446,22 +455,22 @@ pub fn generate_for_path_(thread: &Thread, path: &Path, out_path: &Path) -> Resu }; directories - .last_mut() + .get_mut(entry.path().parent().expect("Parent path")) .expect("Directory before this file") - .1 .push(module); } #[derive(Serialize)] struct Index<'a> { name: String, + directories: &'a [String], modules: &'a [Module], } let reg = handlebars()?; - for (path, modules) in directories { - for module in &modules { + for (path, modules) in &directories { + for module in modules { let out_path = out_path.join(PathBuf::from(module.name.replace(".", "/")).with_extension("html")); let mut doc_file = File::create(&*out_path).with_context(|err| { @@ -499,10 +508,17 @@ pub fn generate_for_path_(thread: &Thread, path: &Path, out_path: &Path) -> Resu .ok_or_else(|| failure::err_msg("Non-UTF-8 filename"))?, ); + let directory_modules: Vec<_> = directories + .keys() + .filter(|dir_path| Some(&**path) == dir_path.parent()) + .map(|dir_path| filename_to_module(dir_path.to_str().unwrap())) + .collect(); + reg.render_to_write( INDEX_TEMPLATE, &Index { name, + directories: &directory_modules, modules: &modules, }, &mut doc_file, diff --git a/std/serialization/de.glu b/std/serialization/de.glu index 4296ca394b..48e45d46b2 100644 --- a/std/serialization/de.glu +++ b/std/serialization/de.glu @@ -1,3 +1,4 @@ +//! JSON deserialzation let { Value } = import! std.serialization.types let prim = import! std.serialization.prim @@ -17,6 +18,7 @@ let { ? } = import! std.array type Error = String type Deserializer i a = i -> Result Error { value : a, input : i } +/// Deserializer which extracts the data from the `Value` type type ValueDeserializer a = Deserializer Value a let error_msg = id @@ -60,6 +62,7 @@ let monad : Monad (Deserializer i) = { ), } +/// Deserializes a `Bool` /// /// ``` /// let { Value, bool, deserialize } = import! std.serialization.de @@ -74,6 +77,9 @@ let bool : ValueDeserializer Bool = \input -> | Bool i -> Ok { value = i, input } | _ -> Err (error_msg "Expected bool") +/// Deserializes a `Float` +/// +/// Note that the deserializer will "integers" such as 123 as floats /// /// ``` /// let { Value, float, deserialize } = import! std.serialization.de @@ -90,6 +96,7 @@ let float : ValueDeserializer Float = \input -> | Float f -> Ok { value = f, input } | _ -> Err (error_msg "Expected float") +/// Deserializes an `Int` /// /// ``` /// let { Value, int, deserialize } = import! std.serialization.de @@ -104,6 +111,7 @@ let int : ValueDeserializer Int = \input -> | Int i -> Ok { value = i, input } | _ -> Err (error_msg "Expected integer") +/// Deserializes a `String` /// /// ``` /// let { Value, string, deserialize } = import! std.serialization.de @@ -118,6 +126,7 @@ let string : ValueDeserializer String = \input -> | String s -> Ok { value = s, input } | _ -> Err (error_msg "Expected string") +/// Deserializes an `Array` of `a` /// /// ``` /// let { Value, array, int, deserialize } = import! std.serialization.de @@ -137,6 +146,9 @@ let array a : ValueDeserializer a -> ValueDeserializer (Array a) = \input -> Ok { value, input } | _ -> Err (error_msg "Expected array") +/// Deserializes an `Option` of `a`. +/// +/// `null` maps to `None` and all other values to `a` /// /// ``` /// let { Value, option, int, deserialize } = import! std.serialization.de @@ -153,6 +165,7 @@ let option a : ValueDeserializer a -> ValueDeserializer (Option a) = \input -> | Null -> Ok { value = None, input } | _ -> (map Some a) input +/// Deserializes the field `name` of an object using `a` /// /// ``` /// let { Value, field, int, deserialize } = import! std.serialization.de @@ -172,6 +185,9 @@ let field name a : String -> ValueDeserializer a -> ValueDeserializer a = \input Ok { value = state.value, input } | None -> Err (error_msg ("Expected field `" ++ name ++ "`")) | _ -> Err (error_msg "Expected map") + +/// Runs the deserializer `de` on `input` +/// Produces a value of type `a` if deserialization was successful let deserialize de input : ValueDeserializer a -> String -> Result Error a = do value = prim.deserialize input do state = de value diff --git a/tests/main.rs b/tests/main.rs index ad6e59ed02..25ede0eba3 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -6,12 +6,11 @@ extern crate collect_mac; extern crate futures; extern crate futures_cpupool; extern crate gluon; +extern crate pulldown_cmark; extern crate tensile; extern crate tokio; extern crate walkdir; -extern crate pulldown_cmark; - use gluon::base::ast::{Expr, Pattern, SpannedExpr}; use gluon::base::filename_to_module; use gluon::base::symbol::Symbol; diff --git a/vm/src/api/mod.rs b/vm/src/api/mod.rs index 68e81ef825..5ed4608a48 100644 --- a/vm/src/api/mod.rs +++ b/vm/src/api/mod.rs @@ -211,6 +211,16 @@ impl<'a> Data<'a> { }, } } + + #[doc(hidden)] + pub fn field_names(&self) -> Vec<::interner::InternedStr> { + match self.0 { + DataInner::Tag(_) => Vec::new(), + DataInner::Data(data) => unsafe { + GcPtr::from_raw(data).field_map().keys().cloned().collect() + }, + } + } } /// Marker type representing a hole