diff options
author | Hendrik Sollich <hendrik@hoodie.de> | 2017-04-21 19:33:47 +0200 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2019-04-26 22:43:12 +0200 |
commit | 98f8376d7767c9138d32ea272df52e8c725d5da4 (patch) | |
tree | 74a24a31a71a611431c63cdd562d6d3f5f7a2abd | |
parent | 286e5e54b1b6078e990984a83fa0e6bbb8ddbb1a (diff) |
attempt at a parser
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | examples/parse.rs | 10 | ||||
-rw-r--r-- | src/components.rs | 7 | ||||
-rw-r--r-- | src/lib.rs | 8 | ||||
-rw-r--r-- | src/parse.rs | 237 | ||||
-rw-r--r-- | src/properties.rs | 3 |
6 files changed, 264 insertions, 3 deletions
@@ -14,12 +14,14 @@ readme = "README.md" include = [ "Cargo.toml", + "README.md", "src/*.rs", ] [dependencies] chrono = "0.4" +nom = "2.1.0" #error-chain = "*" #vobject = {path="../hub/vobject"} diff --git a/examples/parse.rs b/examples/parse.rs new file mode 100644 index 0000000..2c17638 --- /dev/null +++ b/examples/parse.rs @@ -0,0 +1,10 @@ +extern crate chrono; +extern crate icalendar; +use chrono::*; +use icalendar::*; + +fn main() { + let cal = include_str!("../invoicer.ics"); + let parsed = parse::calendar(&cal); + println!("{:?}", parsed); +} diff --git a/src/components.rs b/src/components.rs index b4efb91..a8440e1 100644 --- a/src/components.rs +++ b/src/components.rs @@ -22,6 +22,13 @@ struct InnerComponent{ multi_properties: Vec<Property> } +//impl<'a> Into<InnerComponent> for parse::Component<'a> { +// fn into(self) -> InnerComponent { +// unimplemented!() +// } +//} + + impl InnerComponent { /// End of builder pattern. /// copies over everything @@ -38,7 +38,7 @@ //! ) //! .done(); //! -//! let todo = Todo::new().summary("Buy some milk").done(); +//! //let todo = Todo::new().summary("Buy some milk").done(); //! //! //! let mut calendar = Calendar::new(); @@ -57,6 +57,11 @@ missing_debug_implementations )] +extern crate chrono; +extern crate uuid; +#[macro_use] +extern crate nom; + macro_rules! print_crlf { () => (print!("\r\n")); ($fmt:expr) => (print!(concat!($fmt, "\r\n"))); @@ -79,6 +84,7 @@ macro_rules! write_crlf { mod components; mod properties; mod calendar; +pub mod parse; //pub mod repeats; pub use crate::properties::{Property, Parameter, Class, ValueType}; diff --git a/src/parse.rs b/src/parse.rs new file mode 100644 index 0000000..832cdb6 --- /dev/null +++ b/src/parse.rs @@ -0,0 +1,237 @@ +#![allow(missing_docs, dead_code, unused_variables, unused_imports)] + +use std::str::from_utf8; +use std::convert::Into; + +use nom; +use nom::IResult::*; +use nom::{alpha, alphanumeric, multispace, space, newline, line_ending}; + +use crate::properties; + +////////// Parameters + +/// Zero-copy version of `properties::Parameter` +#[derive(PartialEq, Debug, Clone)] +struct Parameter<'a> { + key: &'a str, + val: &'a str +} + +impl<'a> Into<properties::Parameter> for Parameter<'a> { + fn into(self) -> properties::Parameter { + properties::Parameter::new(self.key, self.val) + } +} + + +#[test] +fn parse_parameter() { + assert_eq!( + parameter(b";KEY=VALUE"), + Done(&[][..], Parameter{key: "KEY", val: "VALUE"}) + ); + assert_eq!( + parameter(b"; KEY=VALUE"), + Done(&[][..], Parameter{key: "KEY", val: "VALUE"}) + ); + assert!( parameter(b";KEY").is_incomplete()); + assert!( parameter(b";KEY=").is_incomplete()); +} + +named!(parameter(&[u8]) -> Parameter, + do_parse!( + tag!(";") >> + opt!(space) >> + key: map_res!(alpha, from_utf8) >> + tag!("=") >> + val: map_res!(alphanumeric, from_utf8) >> + (Parameter{key: key, val: val}) + ) + ); + +// parameter list + +#[test] +fn parse_parameter_list() { + assert_eq!( + parameter_list(b";KEY=VALUE"), + Done(&[][..], vec![Parameter{key: "KEY", val: "VALUE"}]) + ); + + assert_eq!( + parameter_list(b";KEY=VALUE;DATE=TODAY"), + Done(&[][..], vec![ + Parameter{key: "KEY", val: "VALUE"}, + Parameter{key: "DATE", val:"TODAY"} + ]) + ); + + assert_eq!( + parameter_list(b";KEY=VALUE;DATE=20170218"), + Done(&[][..], vec![ + Parameter{key: "KEY", val: "VALUE"}, + Parameter{key: "DATE", val:"20170218"} + ]) + ); +} + +named!(parameter_list(&[u8]) -> Vec<Parameter>, + many0!(parameter) +); + + + +////////// Properies + +/// Zero-copy version of `properties::Property` +#[derive(PartialEq, Debug, Clone)] +struct Property<'a> { + key: &'a str, + val: &'a str, + params: Vec<Parameter<'a>> +} + +#[test] +fn parse_propery() { + assert_eq!( property(b"KEY:VALUE\n"), Done(&[][..], Property{key: "KEY", val: "VALUE", params: vec![]} )); + + assert_eq!( + property(b"KEY;foo=bar:VALUE\n"), + Done(&[][..], Property{key: "KEY", val: "VALUE", params: vec![ + Parameter{key:"foo", val: "bar"} + ]}) + ); +} + +named!(property(&[u8]) -> Property, + do_parse!( + opt!(multispace) >> + key: map_res!(alpha, from_utf8) >> + params: parameter_list >> + tag!(":") >> + val: map_res!(alphanumeric, from_utf8) >> + line_ending >> + (Property{key: key, val: val, params: params}) + ) +); + +#[test] +fn parse_propery_list() { + + assert_eq!( + property_list(b"KEY;foo=bar:VALUE\n KEY;foo=bar; DATE=20170218:VALUE\n"), + Done(&[][..], vec![ + Property{key: "KEY", val: "VALUE", params: vec![ Parameter{key:"foo", val: "bar"} ]}, + Property{key: "KEY", val: "VALUE", params: vec![ + Parameter{key:"foo", val: "bar"}, + Parameter{key:"DATE", val: "20170218"}, + ]} + ]) + ); + assert_eq!( + property_list(b"KEY;foo=bar:VALUE\nKEY;foo=bar;DATE=20170218:VALUE\n"), + Done(&[][..], vec![ + Property{key: "KEY", val: "VALUE", params: vec![ Parameter{key:"foo", val: "bar"} ]}, + Property{key: "KEY", val: "VALUE", params: vec![ + Parameter{key:"foo", val: "bar"}, + Parameter{key:"DATE", val: "20170218"}, + ]} + ]) + ); + assert_eq!( + property_list(b""), + Done(&[][..], vec![ ])); +} + +named!(property_list(&[u8]) -> Vec<Property>, + many0!(property) +); + +////////// Components + +#[derive(PartialEq, Debug, Clone)] +pub struct Component<'a> { + name: &'a str, + properties: Vec<Property<'a>> +} + +#[test] +#[ignore] +fn parse_empty_component() { + assert_eq!(component(b"BEGIN:VEVENT\nEND:VEVENT\n"), Done(&[][..], Component{name: "VEVENT", properties: vec![]})); + + assert_eq!( + component(b"BEGIN:VEVENT\n\nEND:VEVENT\n"), + Done(&[][..], + Component{name: "VEVENT", properties: vec![]} + )); + assert_eq!( + component(b"BEGIN:VEVENT\nEND:VEVENT\n"), + Done(&[][..], + Component{name: "VEVENT", properties: vec![]} + )); +} + +#[test] +fn parse_component() { + let sample_0 = b"BEGIN:VEVENT\nKEY;foo=bar:VALUE\nKEY;foo=bar;DATE=20170218:VALUE\nEND:VEVENT\n"; + let sample_1 = b"BEGIN:VEVENT +KEY;foo=bar:VALUE + KEY;foo=bar;DATE=20170218:VALUE +END:VEVENT +"; + + //assert_eq!(from_utf8(sample_0), from_utf8(sample_1)); + + let expectation = Component{name: "VEVENT", properties: vec![ + Property{key: "KEY", val: "VALUE", params: vec![ + Parameter{key:"foo", val: "bar"}, + ]}, + Property{key: "KEY", val: "VALUE", params: vec![ + Parameter{key:"foo", val: "bar"}, + Parameter{key:"DATE", val: "20170218"}, + ]}, + ]}; + + println!("expectation: {:#?}", expectation); + println!("vs reality : {:#?}", component(sample_1)); + + //assert_eq!( + // component(sample_1), + // Done(&[][..], expectation.clone())); + + assert_eq!( + component(sample_1).unwrap().1, + expectation.clone()); +} + +named!{components(&[u8]) -> Vec<Component>, + many0!(component) +} + +pub fn calendar(raw: &str) -> Vec<Component> { + let parsed = components(raw.as_bytes()); + println!("{:?}", parsed); + if let Done(_, components) = parsed { + components + } else { vec![] } +} + +named!(component(&[u8]) -> Component, + dbg!( + do_parse!( + tag!("BEGIN:") >> name: map_res!(alpha, from_utf8) >> + properties: many_till!( + + do_parse!(p:property >> (p)), + tag!("END:") + + ) >> + tag!(name) >> + + (Component{name: name, properties: properties.0}) + ) + ) + ); + diff --git a/src/properties.rs b/src/properties.rs index 0cd7efb..ae573de 100644 --- a/src/properties.rs +++ b/src/properties.rs @@ -10,7 +10,6 @@ pub struct Parameter { } impl Parameter { - /// Creates a new `Parameter` pub fn new(key: &str, val: &str) -> Self { Parameter { @@ -21,7 +20,7 @@ impl Parameter { } //type EntryParameters = Vec<Parameter>; -type EntryParameters = HashMap<String,Parameter>; +pub type EntryParameters = HashMap<String,Parameter>; #[derive(Debug)] /// key-value pairs inside of `Component`s |