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
|