From ac01c4a224f9b2db08248c45170bea202e08ada9 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 27 Oct 2017 20:37:43 +0200 Subject: Initial bootstrapping of nom-based parser --- Cargo.toml | 7 +-- build.rs | 6 -- src/grammar.rustpeg | 2 - src/lib.rs | 3 +- src/parser.rs | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 175 insertions(+), 20 deletions(-) delete mode 100644 build.rs delete mode 100644 src/grammar.rustpeg diff --git a/Cargo.toml b/Cargo.toml index bc8f016..c0a4c1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,17 +12,14 @@ license = "MPL-2.0" repository = "https://github.com/matthiasbeyer/kairos" -build = "build.rs" - [dependencies] chrono = "0.4" error-chain = "0.10" +nom = "3.2" +iso8601 = { git = "https://github.com/matthiasbeyer/iso8601", branch = "update-nom" } filters = { version = "0.1.1", optional = true } -[build-dependencies] -peg = { version = "0.5" } - [dev-dependencies] env_logger = "0.4" log = "0.3" diff --git a/build.rs b/build.rs deleted file mode 100644 index af09e85..0000000 --- a/build.rs +++ /dev/null @@ -1,6 +0,0 @@ -extern crate peg; - -fn main() { - peg::cargo_build("src/grammar.rustpeg"); -} - diff --git a/src/grammar.rustpeg b/src/grammar.rustpeg deleted file mode 100644 index 36a3fa0..0000000 --- a/src/grammar.rustpeg +++ /dev/null @@ -1,2 +0,0 @@ -use timetype::TimeType; - diff --git a/src/lib.rs b/src/lib.rs index 8f7fed9..d39493a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,8 @@ extern crate error_chain; extern crate chrono; #[macro_use] -extern crate peg; +extern crate nom; +extern crate iso8601; #[cfg(feature = "with-filters")] extern crate filters; diff --git a/src/parser.rs b/src/parser.rs index 4820668..d50cbec 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -29,13 +29,178 @@ //! //! ## User-facing syntax nodes //! -//! AmountExp = ( )? -//! ExactDate = "today" | "yesterday" | "tomorrow" | -//! Date = ( )? -//! Iterator = ("until" | "times")? +//! AmountExpr = ( )? +//! ExactDate = "today" | "yesterday" | "tomorrow" | +//! Date = ( )? +//! Iterator = ("until" | "times")? //! -mod grammar { - include!(concat!(env!("OUT_DIR"), "/grammar.rs")); +use nom::{IResult, space, alpha, alphanumeric, digit}; +use std::str; +use std::str::FromStr; + +named!(integer, alt!( + map_res!( + map_res!( + ws!(digit), + str::from_utf8 + ), + FromStr::from_str + ) +)); + +named!(unit_parser, alt!( + tag!("second") => { |_| Unit::Second } | + tag!("seconds") => { |_| Unit::Second } | + tag!("sec") => { |_| Unit::Second } | + tag!("secs") => { |_| Unit::Second } | + tag!("s") => { |_| Unit::Second } | + tag!("minute") => { |_| Unit::Minute } | + tag!("minutes") => { |_| Unit::Minute } | + tag!("min") => { |_| Unit::Minute } | + tag!("mins") => { |_| Unit::Minute } | + tag!("hour") => { |_| Unit::Hour } | + tag!("hours") => { |_| Unit::Hour } | + tag!("hr") => { |_| Unit::Hour } | + tag!("hrs") => { |_| Unit::Hour } | + tag!("day") => { |_| Unit::Day } | + tag!("days") => { |_| Unit::Day } | + tag!("d") => { |_| Unit::Day } | + tag!("week") => { |_| Unit::Week } | + tag!("weeks") => { |_| Unit::Week } | + tag!("w") => { |_| Unit::Week } | + tag!("month") => { |_| Unit::Month } | + tag!("months") => { |_| Unit::Month } | + tag!("year") => { |_| Unit::Year } | + tag!("years") => { |_| Unit::Year } | + tag!("yrs") => { |_| Unit::Year } +)); + +pub enum Unit { + Second, + Minute, + Hour, + Day, + Week, + Month, + Year, +} + +named!(operator_parser, alt!( + tag!("+") => { |_| Operator::Plus } | + tag!("-") => { |_| Operator::Minus } +)); + +pub enum Operator { + Plus, + Minus, +} + +named!(amount_parser, do_parse!( + number: integer >> + unit : unit_parser >> + (Amount(number, unit)) +)); + +pub struct Amount(i64, Unit); + +named!(iter_spec, alt!( + tag!("secondly") => { |_| Iterspec::Secondly } | + tag!("minutely") => { |_| Iterspec::Minutely } | + tag!("hourly") => { |_| Iterspec::Hourly } | + tag!("daily") => { |_| Iterspec::Daily } | + tag!("weekly") => { |_| Iterspec::Weekly } | + tag!("monthly") => { |_| Iterspec::Monthly } | + tag!("yearly") => { |_| Iterspec::Yearly } | + do_parse!( + tag!("every") >> + number:integer >> + unit:unit_parser >> + (Iterspec::Every(number, unit)) + ) +)); + +pub enum Iterspec { + Secondly, + Minutely, + Hourly, + Daily, + Weekly, + Monthly, + Yearly, + Every(i64, Unit), +} + +named!(amount_expr, do_parse!( + amount:amount_parser >> + o: opt!(do_parse!(op:operator_parser >> amexp:amount_expr >> ((op, Box::new(amexp))))) >> + (AmountExpr { amount: amount, next: o, }) +)); + +pub struct AmountExpr { + amount: Amount, + next: Option<(Operator, Box)>, +} + +impl AmountExpr { + fn new(amount: Amount, next: Option<(Operator, Box)>) -> AmountExpr { + AmountExpr { + amount: amount, + next: next + } + } } +use iso8601::parsers::parse_date; +use iso8601::parsers::parse_datetime; +named!(exact_date_parser, alt!( + tag!("today") => { |_| ExactDate::Today } | + tag!("yesterday") => { |_| ExactDate::Yesterday } | + tag!("tomorrow") => { |_| ExactDate::Tomorrow } | + do_parse!(d: parse_date >> (ExactDate::Iso8601Date(d))) | + do_parse!(d: parse_datetime >> (ExactDate::Iso8601DateTime(d))) +)); + +pub enum ExactDate { + Today, + Yesterday, + Tomorrow, + Iso8601Date(::iso8601::Date), + Iso8601DateTime(::iso8601::DateTime) +} + +named!(date, do_parse!( + exact:exact_date_parser >> + o: opt!(do_parse!(op:operator_parser >> a:amount_expr >> (op, a))) >> + (Date(exact, o)) +)); + +pub struct Date(ExactDate, Option<(Operator, AmountExpr)>); + +named!(until_spec, alt!( + do_parse!( + tag!("until") >> + exact: exact_date_parser >> + (UntilSpec::Exact(exact)) + ) | + do_parse!( + num: integer >> + tag!("times") >> + (UntilSpec::Times(num)) + ) +)); + +pub enum UntilSpec { + Exact(ExactDate), + Times(i64) +} + +named!(iterator, do_parse!( + d: date >> + spec: iter_spec >> + until: opt!(until_spec) >> + (Iterator(d, spec, until)) +)); + +pub struct Iterator(Date, Iterspec, Option); + -- cgit v1.2.3