diff --git a/Makefile b/Makefile index 80eece3..c06948b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ RUSTC := rustc +RUSTDOC := rustdoc BUILD := build LIB := $(BUILD)/$(shell $(RUSTC) --crate-file-name src/toml.rs) TEST := $(BUILD)/tomltest @@ -12,11 +13,14 @@ $(LIB): src/toml.rs @mkdir -p $(@D) $(RUSTC) -O $< --out-dir $(@D) --dep-info -check: $(TEST) +check: $(TEST) doctest $(TEST) $(TEST): src/toml.rs $(RUSTC) $< --test -o $@ --dep-info +doctest: $(LIB) + $(RUSTDOC) --test -L $(BUILD) src/toml.rs + clean: rm -rf $(BUILD) diff --git a/src/parser.rs b/src/parser.rs index dac3e28..96048b4 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -5,21 +5,58 @@ use std::str; use {Array, Table, Value, String, Float, Integer, Boolean, Datetime}; +/// Parser for converting a string to a TOML `Value` instance. +/// +/// This parser contains the string slice that is being parsed, and exports the +/// list of errors which have occurred during parsing. pub struct Parser<'a> { input: &'a str, cur: str::CharOffsets<'a>, tables_defined: HashSet, + + /// A list of all errors which have occurred during parsing. + /// + /// Not all parse errors are fatal, so this list is added to as much as + /// possible without aborting parsing. If `None` is returned by `parse`, it + /// is guaranteed that this list is not empty. pub errors: Vec, } +/// A structure representing a parse error. +/// +/// The data in this structure can be used to trace back to the original cause +/// of the error in order to provide diagnostics about parse errors. #[deriving(Show)] pub struct Error { + /// The low byte at which this error is pointing at. pub lo: uint, + /// One byte beyond the last character at which this error is pointing at. pub hi: uint, + /// A human-readable description explaining what the error is. pub desc: String, } impl<'a> Parser<'a> { + /// Creates a new parser for a string. + /// + /// The parser can be executed by invoking the `parse` method. + /// + /// # Example + /// + /// ``` + /// let toml = r#" + /// [test] + /// foo = "bar" + /// "#; + /// + /// let mut parser = toml::Parser::new(toml); + /// match parser.parse() { + /// Some(value) => println!("found toml: {}", value), + /// None => { + /// println!("parse errors: {}", parser.errors); + /// } + /// } + /// ``` pub fn new(s: &'a str) -> Parser<'a> { Parser { input: s, @@ -76,6 +113,14 @@ impl<'a> Parser<'a> { } } + /// Executes the parser, parsing the string contained within. + /// + /// This function will return the `Table` instance if parsing is successful, + /// or it will return `None` if any parse error or invalid TOML error + /// occurs. + /// + /// If an error occurs, the `errors` field of this parser can be consulted + /// to determine the cause of the parse failure. pub fn parse(&mut self) -> Option { let mut ret = HashMap::new(); loop { diff --git a/src/toml.rs b/src/toml.rs index cebdb37..74a4d36 100644 --- a/src/toml.rs +++ b/src/toml.rs @@ -1,5 +1,29 @@ +//! A TOML-parsing library +//! +//! This library is an implementation in Rust of a parser for TOML configuration +//! files [1]. It is focused around high quality errors including specific spans +//! and detailed error messages when things go wrong. +//! +//! This implementation currently passes the language agnostic [test suite][2]. +//! +//! # Example +//! +//! ``` +//! let toml = r#" +//! [test] +//! foo = "bar" +//! "#; +//! +//! let value = toml::Parser::new(toml).parse().unwrap(); +//! println!("{}", value); +//! ``` +//! +//! [1]: https://github.com/mojombo/toml +//! [2]: https://github.com/BurntSushi/toml-test + #![crate_type = "lib"] #![feature(macro_rules)] +#![deny(warnings, missing_doc)] use std::collections::HashMap; @@ -9,6 +33,9 @@ mod parser; #[cfg(test)] mod test; +/// Representation of a TOML value. +#[deriving(Show, PartialEq, Clone)] +#[allow(missing_doc)] pub enum Value { String(String), Integer(i64), @@ -23,7 +50,8 @@ pub type Array = Vec; pub type Table = HashMap; impl Value { - fn same_type(&self, other: &Value) -> bool { + /// Tests whether this and another value have the same type. + pub fn same_type(&self, other: &Value) -> bool { match (self, other) { (&String(..), &String(..)) | (&Integer(..), &Integer(..)) | @@ -37,7 +65,8 @@ impl Value { } } - fn type_str(&self) -> &'static str { + /// Returns a human-readable representation of the type of this value. + pub fn type_str(&self) -> &'static str { match *self { String(..) => "string", Integer(..) => "integer", @@ -48,4 +77,46 @@ impl Value { Table(..) => "table", } } + + /// Extracts the string of this value if it is a string. + pub fn as_str<'a>(&'a self) -> Option<&'a str> { + match *self { String(ref s) => Some(s.as_slice()), _ => None } + } + + /// Extracts the integer value if it is an integer. + pub fn as_integer(&self) -> Option { + match *self { Integer(i) => Some(i), _ => None } + } + + /// Extracts the float value if it is a float. + pub fn as_float(&self) -> Option { + match *self { Float(f) => Some(f), _ => None } + } + + /// Extracts the boolean value if it is a boolean. + pub fn as_bool(&self) -> Option { + match *self { Boolean(b) => Some(b), _ => None } + } + + /// Extracts the datetime value if it is a datetime. + /// + /// Note that a parsed TOML value will only contain ISO 8601 dates. An + /// example date is: + /// + /// ```notrust + /// 1979-05-27T07:32:00Z + /// ``` + pub fn as_datetime<'a>(&'a self) -> Option<&'a str> { + match *self { Datetime(ref s) => Some(s.as_slice()), _ => None } + } + + /// Extracts the array value if it is an array. + pub fn as_slice<'a>(&'a self) -> Option<&'a [Value]> { + match *self { Array(ref s) => Some(s.as_slice()), _ => None } + } + + /// Extracts the table value if it is a table. + pub fn as_table<'a>(&'a self) -> Option<&'a Table> { + match *self { Table(ref s) => Some(s), _ => None } + } }