<commit_before>use syntax::{abi, ast, ast_util, codemap, parse};
use syntax::parse::token;
use syntax::ptr::P;
use syntax::ext::base;
use syntax::ext::build::AstBuilder;

static BEFORE_EACH: &'static str = "before_each";
static AFTER_EACH:  &'static str = "after_each";
static BEFORE:      &'static str = "before";
static AFTER:       &'static str = "after";
static IT:          &'static str = "it";
static DESCRIBE:    &'static str = "describe";

/// Defines the state of a `describe!` macro as it is parsing.
struct DescribeState {
    name: Option<String>,
    before: Option<P<ast::Block>>,
    after: Option<P<ast::Block>>,
    before_each: Option<P<ast::Block>>,
    after_each: Option<P<ast::Block>>,
    subblocks: Vec<SubBlock>
}

enum SubBlock {
    TestBlock(Test),
    DescribeBlock(P<ast::Item>)
}

/// A test as a description and associated block.
struct Test {
    description: String,
    block: P<ast::Block>
}

/// Defines the overarching `describe!` syntax extension.
///
/// All other macros in stainless are actually "fake" in the sense
/// that they are detected and expanded inside of the implementation
/// of `describe!`.
pub fn describe(cx: &mut base::ExtCtxt, _: codemap::Span, tokens: &[ast::TokenTree]) -> Box<base::MacResult + 'static> {
    // Parse a full DescribeState from the input, emitting errors if used incorrectly.
    let state = parse_describe(&mut parse::tts_to_parser(cx.parse_sess(), tokens.to_vec(), cx.cfg()), cx);

    // Export the new module.
    base::MacItems::new(Some(create_describe_item(state, cx)).into_iter())
}

fn create_describe_item(state: DescribeState, cx: &mut base::ExtCtxt) -> P<ast::Item> {
    // Get the name of the module from the state.
    let name = cx.ident_of(state.name.clone().unwrap().replace(" ", "_").as_slice());

    // Create subblocks from a full DescribeState
    let subblocks = create_subblocks(state, cx);

    // Get a glob import of all items in scope to the module that `describe!` is called from.
    let super_glob = cx.view_use_glob(codemap::DUMMY_SP, ast::Public, vec![cx.ident_of("super")]);

    // Generate the new module.
    cx.item_mod(codemap::DUMMY_SP, codemap::DUMMY_SP, name, vec![], vec![super_glob], subblocks)
}

fn create_subblocks(state: DescribeState, cx: &mut base::ExtCtxt) -> Vec<P<ast::Item>> {
    // FIXME(reem): Implement before and after.
    let (_before, _after) = (state.before, state.after);

    let (before_each, after_each) = (state.before_each, state.after_each);
    let subblocks = state.subblocks;

    // Create the #[test] attribute.
    let test_attribute = cx.attribute(codemap::DUMMY_SP,
                                      cx.meta_word(codemap::DUMMY_SP, token::InternedString::new("test")));

    subblocks.into_iter().map(|block| {
        match block {
            TestBlock(Test { description, block }) => {
                // Create the full test body by splicing in the statements and view items of the before and
                // after blocks if they are present.
                let test_body = match (&before_each, &after_each) {
                    (&None, &None) => block,

                    (&Some(ref before), &None) => {
                        P(ast::Block {
                            view_items: before.view_items + block.view_items,
                            stmts: before.stmts + block.stmts,
                            ..block.deref().clone()
                        })
                    },

                    (&None, &Some(ref after)) => {
                        P(ast::Block {
                            view_items: block.view_items + after.view_items,
                            stmts: block.stmts + after.stmts,
                            ..block.deref().clone()
                        })
                    },

                    (&Some(ref before), &Some(ref after)) => {
                        P(ast::Block {
                            view_items: before.view_items + block.view_items + after.view_items,
                            stmts: before.stmts + block.stmts + after.stmts,
                            ..block.deref().clone()
                        })
                    }
                };

                // Create the final Item that represents the test.
                P(ast::Item {
                    // Name it with a snake_case version of the description.
                    ident: cx.ident_of(description.replace(" ", "_").as_slice()),

                    // Add #[test]
                    attrs: vec![test_attribute.clone()],
                    id: ast::DUMMY_NODE_ID,
                    node: ast::ItemFn(
                        // Takes no arguments and returns ()
                        cx.fn_decl(vec![], cx.ty_nil()),

                        // All the usual types.
                        ast::NormalFn,
                        abi::Rust,
                        ast_util::empty_generics(),

                        // Add the body of the function.
                        test_body
                    ),
                    // Inherited visibility (not pub)
                    vis: ast::Inherited,
                    span: codemap::DUMMY_SP
                })
            },
            DescribeBlock(item) => item
        }
    }).collect()
}

fn parse_describe(parser: &mut parse::parser::Parser, cx: &mut base::ExtCtxt) -> DescribeState {
    let mut state = DescribeState {
        name: None, before: None, after: None,
        before_each: None, after_each: None, subblocks: vec![]
    };

    // First parse the name of this describe block:
    let (name, _) = parser.parse_str();
    state.name = Some(name.get().to_string());

    // Move past the opening {
    if token::LBRACE != parser.bump_and_get() {
        parser.fatal("Expected { after the description of a describe! block.");
    }

    // Now parse all tests and subsections:
    while parser.token != token::RBRACE {
        // Get the name of this block, must be either:
        //     - before_each
        //     - after_each
        //     - before
        //     - after
        //     - it
        //
        // Any other top-level idents are not allowed.
        let block_name = parser.parse_ident();

        match block_name.as_str() {
            BEFORE_EACH => {
                if state.before_each.is_some() { parser.fatal("Only one `before_each` block is allowed per `describe!` block.") }
                state.before_each = Some(parser.parse_block());
            },

            AFTER_EACH => {
                if state.after_each.is_some() { parser.fatal("Only one `after_each` block is allowed per `describe!` block.") }
                state.after_each = Some(parser.parse_block());
            },

            BEFORE => {
                if state.before.is_some() { parser.fatal("Only one `before` block is allowed per `describe!` block.") }
                state.before = Some(parser.parse_block());
            },

            AFTER => {
                if state.after.is_some() { parser.fatal("Only one `after` block is allowed per `describe!` block.") }
                state.after = Some(parser.parse_block());
            },

            IT => {
                // Description of this `it` block.
                let (description, _) = parser.parse_str();

                state.subblocks.push(TestBlock(Test {
                    // Get as a String
                    description: description.get().to_string(),

                    // The associated block
                    block: parser.parse_block()
                }));
            },

            // Sub `describe!` block.
            DESCRIBE => {
                // Skip over the ! and (
                match (parser.bump_and_get(), parser.bump_and_get()) {
                    (token::NOT, token::LPAREN) => {},
                    (one, two) => parser.fatal(format!("Expected describe!( but found `describe{}{}`", one, two).as_slice())
                };

                // Parse this sublock, generate new item.
                state.subblocks.push(DescribeBlock(create_describe_item(parse_describe(parser, cx), cx)));

                // Move past closing bracket and paren.
                //
                // This has to go in here because it two is EOF on the highest-level invocation.
                match (parser.bump_and_get(), parser.bump_and_get()) {
                    (token::RBRACE, token::RPAREN) => {},
                    (one, two) => parser.fatal(format!("Expected }}) to close `describe!` but found: `{}{}`", one, two).as_slice())
                }
            }

            banned => {
                // Illegal block name.
                let span = parser.span;
                parser.span_fatal(span, format!("Expected one of: `{}`, but found: `{}`",
                    format!("{}, {}, {}, {}, {}", BEFORE_EACH, AFTER_EACH, BEFORE, AFTER, IT).as_slice(),
                    banned).as_slice());
            }
        }
    }

    state
}

<commit_msg>(doc) Updated some comments and error messages.<commit_after>use syntax::{abi, ast, ast_util, codemap, parse};
use syntax::parse::token;
use syntax::ptr::P;
use syntax::ext::base;
use syntax::ext::build::AstBuilder;

static BEFORE_EACH: &'static str = "before_each";
static AFTER_EACH:  &'static str = "after_each";
static BEFORE:      &'static str = "before";
static AFTER:       &'static str = "after";
static IT:          &'static str = "it";
static DESCRIBE:    &'static str = "describe";

/// Defines the state of a `describe!` macro as it is parsing.
struct DescribeState {
    name: Option<String>,
    before: Option<P<ast::Block>>,
    after: Option<P<ast::Block>>,
    before_each: Option<P<ast::Block>>,
    after_each: Option<P<ast::Block>>,
    subblocks: Vec<SubBlock>
}

enum SubBlock {
    TestBlock(Test),
    DescribeBlock(P<ast::Item>)
}

/// A test as a description and associated block.
struct Test {
    description: String,
    block: P<ast::Block>
}

/// Defines the overarching `describe!` syntax extension.
///
/// All other macros in stainless are actually "fake" in the sense
/// that they are detected and expanded inside of the implementation
/// of `describe!`.
pub fn describe(cx: &mut base::ExtCtxt, _: codemap::Span, tokens: &[ast::TokenTree]) -> Box<base::MacResult + 'static> {
    // Parse a full DescribeState from the input, emitting errors if used incorrectly.
    let state = parse_describe(&mut parse::tts_to_parser(cx.parse_sess(), tokens.to_vec(), cx.cfg()), cx);

    // Export the new module.
    base::MacItems::new(Some(create_describe_item(state, cx)).into_iter())
}

fn create_describe_item(state: DescribeState, cx: &mut base::ExtCtxt) -> P<ast::Item> {
    // Get the name of the module from the state.
    let name = cx.ident_of(state.name.clone().unwrap().replace(" ", "_").as_slice());

    // Create subblocks from a full DescribeState
    let subblocks = create_subblocks(state, cx);

    // Get a glob import of all items in scope to the module that `describe!` is called from.
    let super_glob = cx.view_use_glob(codemap::DUMMY_SP, ast::Public, vec![cx.ident_of("super")]);

    // Generate the new module.
    cx.item_mod(codemap::DUMMY_SP, codemap::DUMMY_SP, name, vec![], vec![super_glob], subblocks)
}

fn create_subblocks(state: DescribeState, cx: &mut base::ExtCtxt) -> Vec<P<ast::Item>> {
    // FIXME(reem): Implement before and after.
    let (_before, _after) = (state.before, state.after);

    let (before_each, after_each) = (state.before_each, state.after_each);
    let subblocks = state.subblocks;

    // Create the #[test] attribute.
    let test_attribute = cx.attribute(codemap::DUMMY_SP,
                                      cx.meta_word(codemap::DUMMY_SP, token::InternedString::new("test")));

    subblocks.into_iter().map(|block| {
        match block {
            TestBlock(Test { description, block }) => {
                // Create the full test body by splicing in the statements and view items of the before and
                // after blocks if they are present.
                let test_body = match (&before_each, &after_each) {
                    (&None, &None) => block,

                    (&Some(ref before), &None) => {
                        P(ast::Block {
                            view_items: before.view_items + block.view_items,
                            stmts: before.stmts + block.stmts,
                            ..block.deref().clone()
                        })
                    },

                    (&None, &Some(ref after)) => {
                        P(ast::Block {
                            view_items: block.view_items + after.view_items,
                            stmts: block.stmts + after.stmts,
                            ..block.deref().clone()
                        })
                    },

                    (&Some(ref before), &Some(ref after)) => {
                        P(ast::Block {
                            view_items: before.view_items + block.view_items + after.view_items,
                            stmts: before.stmts + block.stmts + after.stmts,
                            ..block.deref().clone()
                        })
                    }
                };

                // Create the final Item that represents the test.
                P(ast::Item {
                    // Name it with a snake_case version of the description.
                    ident: cx.ident_of(description.replace(" ", "_").as_slice()),

                    // Add #[test]
                    attrs: vec![test_attribute.clone()],
                    id: ast::DUMMY_NODE_ID,
                    node: ast::ItemFn(
                        // Takes no arguments and returns ()
                        cx.fn_decl(vec![], cx.ty_nil()),

                        // All the usual types.
                        ast::NormalFn,
                        abi::Rust,
                        ast_util::empty_generics(),

                        // Add the body of the function.
                        test_body
                    ),
                    // Inherited visibility (not pub)
                    vis: ast::Inherited,
                    span: codemap::DUMMY_SP
                })
            },
            DescribeBlock(item) => item
        }
    }).collect()
}

fn parse_describe(parser: &mut parse::parser::Parser, cx: &mut base::ExtCtxt) -> DescribeState {
    let mut state = DescribeState {
        name: None, before: None, after: None,
        before_each: None, after_each: None, subblocks: vec![]
    };

    // First parse the name of this describe block:
    let (name, _) = parser.parse_str();
    state.name = Some(name.get().to_string());

    // Move past the opening {
    if token::LBRACE != parser.bump_and_get() {
        parser.fatal("Expected { after the name of a describe! block.");
    }

    // Now parse all tests and subsections:
    while parser.token != token::RBRACE {
        // Get the name of this block, must be either:
        //     - before_each
        //     - after_each
        //     - before
        //     - after
        //     - it
        //     - describe!
        //
        // Any other top-level idents are not allowed.
        let block_name = parser.parse_ident();

        match block_name.as_str() {
            BEFORE_EACH => {
                if state.before_each.is_some() { parser.fatal("Only one `before_each` block is allowed per `describe!` block.") }
                state.before_each = Some(parser.parse_block());
            },

            AFTER_EACH => {
                if state.after_each.is_some() { parser.fatal("Only one `after_each` block is allowed per `describe!` block.") }
                state.after_each = Some(parser.parse_block());
            },

            BEFORE => {
                if state.before.is_some() { parser.fatal("Only one `before` block is allowed per `describe!` block.") }
                state.before = Some(parser.parse_block());
            },

            AFTER => {
                if state.after.is_some() { parser.fatal("Only one `after` block is allowed per `describe!` block.") }
                state.after = Some(parser.parse_block());
            },

            IT => {
                // Description of this `it` block.
                let (description, _) = parser.parse_str();

                state.subblocks.push(TestBlock(Test {
                    // Get as a String
                    description: description.get().to_string(),

                    // The associated block
                    block: parser.parse_block()
                }));
            },

            // Nested `describe!` block.
            DESCRIBE => {
                // Skip over the ! and (
                match (parser.bump_and_get(), parser.bump_and_get()) {
                    (token::NOT, token::LPAREN) => {},
                    (one, two) => parser.fatal(format!("Expected describe!( but found `describe{}{}`", one, two).as_slice())
                };

                // Parse this sublock, generate new item.
                state.subblocks.push(DescribeBlock(create_describe_item(parse_describe(parser, cx), cx)));

                // Move past closing bracket and paren.
                //
                // This has to go in here because it two is EOF on the highest-level invocation.
                match (parser.bump_and_get(), parser.bump_and_get()) {
                    (token::RBRACE, token::RPAREN) => {},
                    (one, two) => parser.fatal(format!("Expected }}) to close `describe!` but found: `{}{}`", one, two).as_slice())
                }
            }

            banned => {
                // Illegal block name.
                let span = parser.span;
                parser.span_fatal(span, format!("Expected one of: `{}`, but found: `{}`",
                    format!("{}, {}, {}, {}, {}", BEFORE_EACH, AFTER_EACH, BEFORE, AFTER, IT).as_slice(),
                    banned).as_slice());
            }
        }
    }

    state
}

<|endoftext|>


<commit_before>use std::time;
use std::fmt;
use std::ops;

pub const SECS_PER_DAY: f64 = 60.0*60.0*24.0;
pub const SECS_PER_HOUR: f64 = 60.0*60.0;
pub const SECS_PER_MINUTE: f64 = 60.0;

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct FloatDuration {
    secs: f64,
}

#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct DecomposedTime {
    pub days: u32,
    pub hours: u32,
    pub minutes: u32,
    pub seconds: u32,
    pub fractional_seconds: f64,
    pub sign: i8,
}

impl FloatDuration {
    pub fn new(secs: f64) -> FloatDuration {
        FloatDuration {secs}
    }

    pub fn days(days: f64) -> FloatDuration {
        FloatDuration {secs: days * (3600.0 * 24.0)}
    }
    pub fn hours(hours: f64) -> FloatDuration {
        FloatDuration {secs: hours * 3600.0}
    }
    pub fn minutes(mins: f64) -> FloatDuration {
        FloatDuration {secs: mins * 60.0}
    }
    pub fn seconds(secs: f64) -> FloatDuration {
        FloatDuration {secs}
    }
    pub fn milliseconds(millis: f64) -> FloatDuration {
        FloatDuration {secs: millis / 1000.0}
    }
    pub fn microseconds(micros: f64) -> FloatDuration {
        FloatDuration {secs: micros / 1.0e6}
    }
    pub fn nanoseconds(nanos: f64) -> FloatDuration {
        FloatDuration {secs: nanos / 1.0e9}
    }

    pub fn decompose(&self) -> DecomposedTime {
        let mut secs_left = self.secs;

        let days = (secs_left / SECS_PER_DAY).trunc();
        secs_left -= days*SECS_PER_DAY;
        let hours = (secs_left / SECS_PER_HOUR).trunc();
        secs_left -= hours*SECS_PER_HOUR;
        let minutes = (secs_left / SECS_PER_MINUTE).trunc();
        secs_left -= hours*SECS_PER_MINUTE;
        let seconds = secs_left.trunc();
        let fract = secs_left.fract();

        DecomposedTime {
            days: days as u32,
            hours: hours as u32,
            minutes: minutes as u32,
            seconds: seconds as u32,
            fractional_seconds: fract,
            sign: self.secs.signum() as i8,
        }
    }

    pub fn as_days(&self) -> f64 {
        self.secs / SECS_PER_DAY
    }
    pub fn as_hours(&self) -> f64 {
        self.secs / SECS_PER_HOUR
    }
    pub fn as_minutes(&self) -> f64 {
        self.secs / SECS_PER_MINUTE
    }
    pub fn as_seconds(&self) -> f64 {
        self.secs
    }
    pub fn as_milliseconds(&self) -> f64 {
        self.secs * 1.0e3
    }
    pub fn as_microseconds(&self) -> f64 {
        self.secs * 1.0e6
    }
    pub fn as_nanoseconds(&self) -> f64 {
        self.secs * 1.0e9
    }

    pub fn zero() -> FloatDuration {
        FloatDuration {secs: 0.0}
    }
    pub fn is_zero(&self) -> bool {
        self.secs == 0.0
    }
    pub fn is_positive(&self) -> bool {
        self.secs.is_sign_positive()
    }
    pub fn is_negative(&self) -> bool {
        self.secs.is_sign_negative()
    }

    pub fn as_std(&self) -> Option<time::Duration> {
        if self.secs.is_sign_negative() {
            None
        } else {
            let seconds = self.secs.trunc();
            let nanos = self.secs.fract() * 1e9;

            Some(time::Duration::new(seconds as u64, nanos as u32))
        }
    }

    pub fn from_std(duration: time::Duration) -> FloatDuration {
        return FloatDuration::seconds(
            (duration.as_secs() as f64) + (duration.subsec_nanos() as f64)*1.0e-9);
    }

    pub fn from_decomposed(decomposed: &DecomposedTime) -> FloatDuration {
        let seconds = (decomposed.days as f64)*SECS_PER_DAY
            + (decomposed.hours as f64)*SECS_PER_HOUR
            + (decomposed.minutes as f64)*SECS_PER_MINUTE
            + (decomposed.seconds as f64)
            + decomposed.fractional_seconds;

        FloatDuration {
            secs: seconds
        }
    }
}

impl DecomposedTime {
    pub fn from_components(days: u32, hours: u32, minutes: u32,
               seconds: u32, fractional_seconds: f64) -> DecomposedTime
    {
        DecomposedTime {
            days, hours, minutes, seconds, fractional_seconds, sign: 1}
    }

    pub fn negate(mut self) -> DecomposedTime {
        self.sign *= -1;
        self
    }
}

impl fmt::Display for FloatDuration {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let decompose_time = self.decompose();

        if decompose_time.days > 0 {
            write!(fmt, "{}d ", decompose_time.days as u64)?;
        }

        if decompose_time.sign.is_negative() {
            write!(fmt, "-")?;
        }
        write!(fmt, "{:02}:{:02}:{:02}.{}",
            decompose_time.hours,
            decompose_time.minutes,
            decompose_time.seconds,
            decompose_time.fractional_seconds)
    }
}

impl ops::Neg for FloatDuration {
    type Output = FloatDuration;

    fn neg(self) -> FloatDuration {
        FloatDuration {secs: -self.secs}
    }
}

impl ops::Add<FloatDuration> for FloatDuration {
    type Output = FloatDuration;

    fn add(self, rhs: FloatDuration) -> FloatDuration {
        FloatDuration {secs: self.secs + rhs.secs}
    }
}
impl ops::Sub<FloatDuration> for FloatDuration {
    type Output = FloatDuration;

    fn sub(self, rhs: FloatDuration) -> FloatDuration {
        FloatDuration {secs: self.secs - rhs.secs}
    }
}

impl ops::Mul<f64> for FloatDuration {
    type Output = FloatDuration;

    fn mul(self, rhs: f64) -> FloatDuration {
        FloatDuration {secs: self.secs * rhs}
    }
}
impl ops::Div<f64> for FloatDuration {
    type Output = FloatDuration;

    fn div(self, rhs: f64) -> FloatDuration {
        FloatDuration {secs: self.secs / rhs}
    }
}

impl ops::AddAssign<FloatDuration> for FloatDuration {
    fn add_assign(&mut self, rhs: FloatDuration) {
        self.secs += rhs.secs;
    }
}
impl ops::SubAssign<FloatDuration> for FloatDuration {
    fn sub_assign(&mut self, rhs: FloatDuration) {
        self.secs -= rhs.secs;
    }
}

impl ops::MulAssign<f64> for FloatDuration {
    fn mul_assign(&mut self, rhs: f64) {
        self.secs *= rhs;
    }
}
impl ops::DivAssign<f64> for FloatDuration {
    fn div_assign(&mut self, rhs: f64) {
        self.secs /= rhs;
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::time;

    #[test]
    fn test_construct() {
        let duration1 = FloatDuration::hours(3.0);
        assert_eq!(duration1.as_hours(), 3.0);
        assert_eq!(duration1.as_minutes(), 180.0);
        assert_eq!(duration1.as_seconds(), 180.0*60.0);
        assert_eq!(duration1.as_days(), 3.0/24.0);
        assert_eq!(duration1.as_milliseconds(), 180.0*60.0*1000.0);

        let duration2 = FloatDuration::milliseconds(55.0);
        assert_eq!(duration2.as_seconds(), 0.055);
        assert_eq!(duration2.as_milliseconds(), 55.0);
        assert_eq!(duration2.as_microseconds(), 55000.0);
        assert_eq!(duration2.as_nanoseconds(), 55000000.0);
        assert!(!duration2.is_zero());

        let duration3 = FloatDuration::zero();
        assert!(duration3.is_zero());

        assert_eq!(FloatDuration::days(1.5), FloatDuration::hours(36.0));
        assert_eq!(FloatDuration::minutes(30.0), FloatDuration::hours(0.5));
        assert_eq!(FloatDuration::seconds(180.0), FloatDuration::minutes(3.0));
        assert_eq!(FloatDuration::seconds(3.5), FloatDuration::milliseconds(3500.0));
        assert_eq!(FloatDuration::microseconds(300.0), FloatDuration::milliseconds(0.30));
        assert_eq!(FloatDuration::nanoseconds(1000.0), FloatDuration::microseconds(1.0));
    }

    #[test]
    fn test_arithmetic() {
        let duration1 = FloatDuration::minutes(5.0) + FloatDuration::seconds(30.0);
        assert_eq!(duration1, FloatDuration::seconds(330.0));

        let duration2 = FloatDuration::hours(3.0) * 2.5;
        assert_eq!(duration2, FloatDuration::hours(7.5));

        let duration3 = FloatDuration::days(3.0) / 3.0 - FloatDuration::hours(2.0);
        assert_eq!(duration3, FloatDuration::hours(22.0));

        let duration4 = FloatDuration::zero() + FloatDuration::milliseconds(500.0)
            + FloatDuration::microseconds(500.0);
        assert_eq!(duration4, FloatDuration::microseconds(500500.0));

    }

    #[test]
    fn test_std_conversion() {
        let duration1 = FloatDuration::minutes(5.0);
        let std_duration1 = duration1.as_std().unwrap();
        assert!(duration1.is_positive());
        assert_eq!(std_duration1, time::Duration::new(300, 0));
        assert_eq!(FloatDuration::from_std(std_duration1), duration1);

        let duration2 = FloatDuration::hours(-2.0);
        assert!(duration2.is_negative());
        assert_eq!(duration2.as_std(), None);
        let std_duration2 = (-duration2).as_std().unwrap();
        assert_eq!(std_duration2, time::Duration::new(3600*2, 0));
        assert_eq!(FloatDuration::from_std(std_duration2), -duration2);
    }
}
<commit_msg>Added a few enhancements for `DecomposedTime`.<commit_after>use std::time;
use std::fmt;
use std::ops;

pub const SECS_PER_DAY: f64 = 60.0*60.0*24.0;
pub const SECS_PER_HOUR: f64 = 60.0*60.0;
pub const SECS_PER_MINUTE: f64 = 60.0;

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct FloatDuration {
    secs: f64,
}

#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct DecomposedTime {
    pub days: u32,
    pub hours: u32,
    pub minutes: u32,
    pub seconds: u32,
    pub fractional_seconds: f64,
    pub sign: i8,
}

impl FloatDuration {
    pub fn new(secs: f64) -> FloatDuration {
        FloatDuration {secs}
    }

    pub fn days(days: f64) -> FloatDuration {
        FloatDuration {secs: days * (3600.0 * 24.0)}
    }
    pub fn hours(hours: f64) -> FloatDuration {
        FloatDuration {secs: hours * 3600.0}
    }
    pub fn minutes(mins: f64) -> FloatDuration {
        FloatDuration {secs: mins * 60.0}
    }
    pub fn seconds(secs: f64) -> FloatDuration {
        FloatDuration {secs}
    }
    pub fn milliseconds(millis: f64) -> FloatDuration {
        FloatDuration {secs: millis / 1000.0}
    }
    pub fn microseconds(micros: f64) -> FloatDuration {
        FloatDuration {secs: micros / 1.0e6}
    }
    pub fn nanoseconds(nanos: f64) -> FloatDuration {
        FloatDuration {secs: nanos / 1.0e9}
    }

    pub fn decompose(&self) -> DecomposedTime {
        let mut secs_left = self.secs;

        let days = (secs_left / SECS_PER_DAY).trunc();
        secs_left -= days*SECS_PER_DAY;
        let hours = (secs_left / SECS_PER_HOUR).trunc();
        secs_left -= hours*SECS_PER_HOUR;
        let minutes = (secs_left / SECS_PER_MINUTE).trunc();
        secs_left -= hours*SECS_PER_MINUTE;
        let seconds = secs_left.trunc();
        let fract = secs_left.fract();

        DecomposedTime {
            days: days as u32,
            hours: hours as u32,
            minutes: minutes as u32,
            seconds: seconds as u32,
            fractional_seconds: fract,
            sign: self.secs.signum() as i8,
        }
    }

    pub fn as_days(&self) -> f64 {
        self.secs / SECS_PER_DAY
    }
    pub fn as_hours(&self) -> f64 {
        self.secs / SECS_PER_HOUR
    }
    pub fn as_minutes(&self) -> f64 {
        self.secs / SECS_PER_MINUTE
    }
    pub fn as_seconds(&self) -> f64 {
        self.secs
    }
    pub fn as_milliseconds(&self) -> f64 {
        self.secs * 1.0e3
    }
    pub fn as_microseconds(&self) -> f64 {
        self.secs * 1.0e6
    }
    pub fn as_nanoseconds(&self) -> f64 {
        self.secs * 1.0e9
    }

    pub fn zero() -> FloatDuration {
        FloatDuration {secs: 0.0}
    }
    pub fn is_zero(&self) -> bool {
        self.secs == 0.0
    }
    pub fn is_positive(&self) -> bool {
        self.secs.is_sign_positive()
    }
    pub fn is_negative(&self) -> bool {
        self.secs.is_sign_negative()
    }

    pub fn as_std(&self) -> Option<time::Duration> {
        if self.secs.is_sign_negative() {
            None
        } else {
            let seconds = self.secs.trunc();
            let nanos = self.secs.fract() * 1e9;

            Some(time::Duration::new(seconds as u64, nanos as u32))
        }
    }

    pub fn from_std(duration: time::Duration) -> FloatDuration {
        return FloatDuration::seconds(
            (duration.as_secs() as f64) + (duration.subsec_nanos() as f64)*1.0e-9);
    }

    pub fn from_decomposed(decomposed: &DecomposedTime) -> FloatDuration {
        let seconds = (decomposed.days as f64)*SECS_PER_DAY
            + (decomposed.hours as f64)*SECS_PER_HOUR
            + (decomposed.minutes as f64)*SECS_PER_MINUTE
            + (decomposed.seconds as f64)
            + decomposed.fractional_seconds;

        FloatDuration {
            secs: seconds
        }
    }
}

impl DecomposedTime {
    pub fn new() -> DecomposedTime {
        DecomposedTime { days: 0, hours: 0, minutes: 0, seconds: 0,
            fractional_seconds: 0.0, sign: 1 }
    }

    pub fn from_components(days: u32, hours: u32, minutes: u32,
               seconds: u32, fractional_seconds: f64) -> DecomposedTime
    {
        DecomposedTime {
            days, hours, minutes, seconds, fractional_seconds, sign: 1}
    }

    pub fn negate(mut self) -> DecomposedTime {
        self.sign *= -1;
        self
    }
}

impl fmt::Display for DecomposedTime {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        if self.days > 0 {
            write!(fmt, "{}d ", self.days as u64)?;
        }

        if self.sign.is_negative() {
            write!(fmt, "-")?;
        }
        write!(fmt, "{:02}:{:02}:{:02}.{}",
            self.hours,
            self.minutes,
            self.seconds,
            self.fractional_seconds)
    }
}

impl fmt::Display for FloatDuration {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let decomposed_time = self.decompose();
        write!(fmt, "{}", decomposed_time)
    }
}

impl ops::Neg for FloatDuration {
    type Output = FloatDuration;

    fn neg(self) -> FloatDuration {
        FloatDuration {secs: -self.secs}
    }
}

impl ops::Add<FloatDuration> for FloatDuration {
    type Output = FloatDuration;

    fn add(self, rhs: FloatDuration) -> FloatDuration {
        FloatDuration {secs: self.secs + rhs.secs}
    }
}
impl ops::Sub<FloatDuration> for FloatDuration {
    type Output = FloatDuration;

    fn sub(self, rhs: FloatDuration) -> FloatDuration {
        FloatDuration {secs: self.secs - rhs.secs}
    }
}

impl ops::Mul<f64> for FloatDuration {
    type Output = FloatDuration;

    fn mul(self, rhs: f64) -> FloatDuration {
        FloatDuration {secs: self.secs * rhs}
    }
}
impl ops::Div<f64> for FloatDuration {
    type Output = FloatDuration;

    fn div(self, rhs: f64) -> FloatDuration {
        FloatDuration {secs: self.secs / rhs}
    }
}

impl ops::AddAssign<FloatDuration> for FloatDuration {
    fn add_assign(&mut self, rhs: FloatDuration) {
        self.secs += rhs.secs;
    }
}
impl ops::SubAssign<FloatDuration> for FloatDuration {
    fn sub_assign(&mut self, rhs: FloatDuration) {
        self.secs -= rhs.secs;
    }
}

impl ops::MulAssign<f64> for FloatDuration {
    fn mul_assign(&mut self, rhs: f64) {
        self.secs *= rhs;
    }
}
impl ops::DivAssign<f64> for FloatDuration {
    fn div_assign(&mut self, rhs: f64) {
        self.secs /= rhs;
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::time;

    #[test]
    fn test_construct() {
        let duration1 = FloatDuration::hours(3.0);
        assert_eq!(duration1.as_hours(), 3.0);
        assert_eq!(duration1.as_minutes(), 180.0);
        assert_eq!(duration1.as_seconds(), 180.0*60.0);
        assert_eq!(duration1.as_days(), 3.0/24.0);
        assert_eq!(duration1.as_milliseconds(), 180.0*60.0*1000.0);

        let duration2 = FloatDuration::milliseconds(55.0);
        assert_eq!(duration2.as_seconds(), 0.055);
        assert_eq!(duration2.as_milliseconds(), 55.0);
        assert_eq!(duration2.as_microseconds(), 55000.0);
        assert_eq!(duration2.as_nanoseconds(), 55000000.0);
        assert!(!duration2.is_zero());

        let duration3 = FloatDuration::zero();
        assert!(duration3.is_zero());

        assert_eq!(FloatDuration::days(1.5), FloatDuration::hours(36.0));
        assert_eq!(FloatDuration::minutes(30.0), FloatDuration::hours(0.5));
        assert_eq!(FloatDuration::seconds(180.0), FloatDuration::minutes(3.0));
        assert_eq!(FloatDuration::seconds(3.5), FloatDuration::milliseconds(3500.0));
        assert_eq!(FloatDuration::microseconds(300.0), FloatDuration::milliseconds(0.30));
        assert_eq!(FloatDuration::nanoseconds(1000.0), FloatDuration::microseconds(1.0));
    }

    #[test]
    fn test_arithmetic() {
        let duration1 = FloatDuration::minutes(5.0) + FloatDuration::seconds(30.0);
        assert_eq!(duration1, FloatDuration::seconds(330.0));

        let duration2 = FloatDuration::hours(3.0) * 2.5;
        assert_eq!(duration2, FloatDuration::hours(7.5));

        let duration3 = FloatDuration::days(3.0) / 3.0 - FloatDuration::hours(2.0);
        assert_eq!(duration3, FloatDuration::hours(22.0));

        let duration4 = FloatDuration::zero() + FloatDuration::milliseconds(500.0)
            + FloatDuration::microseconds(500.0);
        assert_eq!(duration4, FloatDuration::microseconds(500500.0));

    }

    #[test]
    fn test_std_conversion() {
        let duration1 = FloatDuration::minutes(5.0);
        let std_duration1 = duration1.as_std().unwrap();
        assert!(duration1.is_positive());
        assert_eq!(std_duration1, time::Duration::new(300, 0));
        assert_eq!(FloatDuration::from_std(std_duration1), duration1);

        let duration2 = FloatDuration::hours(-2.0);
        assert!(duration2.is_negative());
        assert_eq!(duration2.as_std(), None);
        let std_duration2 = (-duration2).as_std().unwrap();
        assert_eq!(std_duration2, time::Duration::new(3600*2, 0));
        assert_eq!(FloatDuration::from_std(std_duration2), -duration2);
    }
}
<|endoftext|>


<commit_before>use value::{InternedString, Pair, Value};
use value::Value::*;
use cell_gc::{GcHeapSession, GcLeaf};
use cell_gc::collections::VecRef;

#[derive(IntoHeap)]
pub enum Expr<'h> {
    /// A constant (`quote` expressions produce this, but also numbers and
    /// other self-evaluating values).
    Con(Value<'h>),

    /// A variable-expression (evaluates to the variable's value).
    Var(GcLeaf<InternedString>),

    /// A lambda expression.
    Fun(CodeRef<'h>),

    /// A function call expression (an application).
    App(VecRef<'h, Expr<'h>>),

    /// A sequence-expression (`begin` used as an expression).
    Seq(VecRef<'h, Expr<'h>>),

    /// A conditional expression (`if`).
    If(IfRef<'h>),

    /// A definition.
    Def(DefRef<'h>),

    /// An assignment expression (`set!`).
    Set(DefRef<'h>),

    /// A `letrec*` expression.
    Letrec(LetrecRef<'h>),

    /// Evaluates to the current global environment.
    /// Used to implement (interactive-environment), for (eval).
    ToplevelEnv,
}

#[derive(IntoHeap)]
pub struct Code<'h> {
    pub params: VecRef<'h, GcLeaf<InternedString>>,
    pub rest: bool,
    pub body: Expr<'h>,
}

#[derive(IntoHeap)]
pub struct Def<'h> {
    pub name: GcLeaf<InternedString>,
    pub value: Expr<'h>
}

#[derive(IntoHeap)]
pub struct If<'h> {
    pub cond: Expr<'h>,
    pub t_expr: Expr<'h>,
    pub f_expr: Expr<'h>,
}

#[derive(IntoHeap)]
pub struct Letrec<'h> {
    pub names: VecRef<'h, GcLeaf<InternedString>>,
    pub exprs: VecRef<'h, Expr<'h>>,
    pub body: Expr<'h>
}

// Convert the linked list of a `<body>` to a vector; also splice in the
// contents of `(begin)` expressions nested within the `<body>`.
fn flatten_body<'h>(forms: Value<'h>, out: &mut Vec<Value<'h>>) -> Result<(), String> {
    for form_res in forms {
        let form = form_res?;
        if let Cons(ref pair) = form {
            if let Symbol(op) = pair.car() {
                if op.as_str() == "begin" {
                    flatten_body(pair.cdr(), out)?;
                    continue;
                }
            }
        }
        out.push(form);
    }
    Ok(())
}

fn is_definition<'h>(form: &Value<'h>) -> bool {
    if let Cons(ref pair) = *form {
        if let Symbol(op) = pair.car() {
            if op.as_str() == "define" {
                return true;
            }
        }
    }
    false
}

// Compile the body of a lambda or letrec*.
fn compile_body<'h>(
    hs: &mut GcHeapSession<'h>,
    body_list: Value<'h>,
) -> Result<Expr<'h>, String> {
    let mut forms = vec![];
    flatten_body(body_list, &mut forms)?;

    let mut names = vec![];
    let mut exprs = vec![];

    let mut i = 0;
    while i < forms.len() && is_definition(&forms[i]) {
        let (name, expr) = parse_define(hs, forms[i].clone())?;
        names.push(name);
        exprs.push(expr);
        i += 1;
    }

    if i == forms.len() {
        return Err("expression required".into());
    }

    let names = hs.alloc(names);
    let exprs = hs.alloc(exprs);
    let body_exprs: Result<Vec<Expr>, String> = forms
        .drain(i..)
        .map(|form| compile_expr(hs, form))
        .collect();
    let body = seq(hs, body_exprs?);
    Ok(Expr::Letrec(hs.alloc(Letrec {
        names,
        exprs,
        body,
    })))
}

fn seq<'h>(hs: &mut GcHeapSession<'h>, mut exprs: Vec<Expr<'h>>) -> Expr<'h> {
    if exprs.len() == 0 {
        Expr::Con(Value::Nil)
    } else if exprs.len() == 1 {
        exprs.pop().unwrap()
    } else {
        Expr::Seq(hs.alloc(exprs))
    }
}

/// On success, returns the two parts of a `(define)` that we care about: the
/// name to define and the compiled expression to populate it.
fn parse_define<'h>(hs: &mut GcHeapSession<'h>, mut defn: Value<'h>)
    -> Result<(GcLeaf<InternedString>, Expr<'h>), String>
{
    loop {
        let (define_symbol, tail) = defn.as_pair("internal error")?;
        let (pattern, rest) = tail.as_pair("(define) with no name")?;
        match pattern {
            Symbol(ident) => {
                let (expr, rest) = rest.as_pair("(define) with no value")?;
                match rest {
                    Nil => {}
                    _ => {
                        return Err(
                            "too many arguments in (define)".to_string(),
                        )
                    }
                };

                let value = compile_expr(hs, expr)?;
                return Ok((ident, value));
            }
            Cons(pair) => {
                // Build desugared definition and compile that.
                let name = pair.car();
                let formals = pair.cdr();

                // Transform `(define (,name ,@formals) ,@rest)
                // to        `(define ,name (lambda ,formals ,@rest))
                let lambda_cdr = Cons(hs.alloc(Pair {
                    car: formals,
                    cdr: rest,
                }));
                let lambda = Cons(hs.alloc(Pair {
                    car: Symbol(GcLeaf::new(InternedString::get("lambda"))),
                    cdr: lambda_cdr,
                }));
                let defn_cddr = Cons(hs.alloc(Pair {
                    car: lambda,
                    cdr: Nil,
                }));
                let defn_cdr = Cons(hs.alloc(Pair {
                    car: name,
                    cdr: defn_cddr,
                }));
                defn = Cons(hs.alloc(Pair {
                    car: define_symbol,
                    cdr: defn_cdr
                }));
            }
            _ => return Err("(define) with a non-symbol name".to_string())
        }
    }
}

pub fn compile_toplevel<'h>(
    hs: &mut GcHeapSession<'h>,
    expr: Value<'h>,
) -> Result<Expr<'h>, String> {
    // TODO: support (begin) here
    if is_definition(&expr) {
        let (name, value) = parse_define(hs, expr)?;
        Ok(Expr::Def(hs.alloc(Def { name, value })))
    } else {
        compile_expr(hs, expr)
    }
}

pub fn compile_expr<'h>(
    hs: &mut GcHeapSession<'h>,
    expr: Value<'h>,
) -> Result<Expr<'h>, String> {
    match expr {
        Symbol(s) => Ok(Expr::Var(s)),

        Cons(p) => {
            let f = p.car();
            if let Symbol(ref s) = f {
                if s.as_str() == "lambda" {
                    let (mut param_list, body_forms) = p.cdr().as_pair("syntax error in lambda")?;

                    let mut names = vec![];
                    while let Cons(pair) = param_list {
                        if let Symbol(s) = pair.car() {
                            names.push(s);
                        } else {
                            return Err("syntax error in lambda arguments".to_string());
                        }
                        param_list = pair.cdr();
                    }
                    let rest =
                        match param_list {
                            Nil => false,
                            Symbol(rest_name) => {
                                names.push(rest_name);
                                true
                            }
                            _ => return Err("syntax error in lambda arguments".to_string())
                        };

                    let params = hs.alloc(names);
                    let body = compile_body(hs, body_forms)?;
                    return Ok(Expr::Fun(hs.alloc(Code { params, rest, body })));
                } else if s.as_str() == "quote" {
                    let (datum, rest) = p.cdr().as_pair("(quote) with no arguments")?;
                    if !rest.is_nil() {
                        return Err("too many arguments to (quote)".to_string());
                    }
                    return Ok(Expr::Con(datum));
                } else if s.as_str() == "if" {
                    let (cond, rest) = p.cdr().as_pair("(if) with no arguments")?;
                    let cond = compile_expr(hs, cond)?;
                    let (tc, rest) = rest.as_pair("missing arguments after (if COND)")?;
                    let t_expr = compile_expr(hs, tc)?;
                    let f_expr =
                        if rest == Nil {
                            Expr::Con(Nil)
                        } else {
                            let (fc, rest) =
                                rest.as_pair("missing 'else' argument after (if COND X)")?;
                            if !rest.is_nil() {
                                return Err("too many arguments in (if) expression".to_string());
                            }
                            compile_expr(hs, fc)?
                        };
                    return Ok(Expr::If(hs.alloc(If { cond, t_expr, f_expr })));
                } else if s.as_str() == "begin" {
                    // In expression context, this is sequencing, not splicing.
                    let mut exprs = vec![];
                    for expr_result in p.cdr() {
                        let expr = expr_result?;
                        exprs.push(compile_expr(hs, expr)?);
                    }
                    return Ok(Expr::Seq(hs.alloc(exprs)));
                } else if s.as_str() == "define" {
                    // In expression context, definitions aren't allowed.
                    return Err("(define) is allowed only at toplevel or in the body \
                                of a function or let-form".into());
                } else if s.as_str() == "letrec*" {
                    let (bindings, body_forms) = p.cdr().as_pair("letrec*: bindings required")?;
                    let mut names = vec![];
                    let mut exprs = vec![];
                    for binding_result in bindings {
                        let binding = binding_result?;
                        let (name_v, rest) = binding.as_pair("letrec*: invalid binding")?;
                        let name = name_v.as_symbol("letrec*: name required")?;
                        let (expr, rest) = rest.as_pair("letrec*: value required for binding")?;
                        if !rest.is_nil() {
                            return Err("(letrec*): too many arguments".to_string());
                        }
                        names.push(GcLeaf::new(name));
                        exprs.push(compile_expr(hs, expr)?);
                    }
                    let names = hs.alloc(names);
                    let exprs = hs.alloc(exprs);
                    let body = compile_body(hs, body_forms)?;
                    return Ok(Expr::Letrec(hs.alloc(Letrec {
                        names,
                        exprs,
                        body,
                    })));
                } else if s.as_str() == "set!" {
                    let (first, rest) = p.cdr().as_pair("(set!) with no name")?;
                    let name = first.as_symbol("(set!) first argument must be a name")?;
                    let (expr, rest) = rest.as_pair("(set!) with no value")?;
                    if !rest.is_nil() {
                        return Err("(set!): too many arguments".to_string());
                    }
                    let value = compile_expr(hs, expr)?;
                    return Ok(Expr::Set(hs.alloc(Def {
                        name: GcLeaf::new(name),
                        value: value
                    })));
                }
            }

            let subexprs: Vec<Expr<'h>> =
                Cons(p)
                    .into_iter()
                    .map(|v| compile_expr(hs, v?))
                    .collect::<Result<_, String>>()?;
            Ok(Expr::App(hs.alloc(subexprs)))
        }

        // Self-evaluating values.
        Bool(v) => Ok(Expr::Con(Bool(v))),
        Int(v) => Ok(Expr::Con(Int(v))),
        ImmString(v) => Ok(Expr::Con(ImmString(v))),

        // Everything else is an error.
        _ => Err(format!("not an expression")),
    }
}
<commit_msg>lisp: Make letrec an alias for letrec*.<commit_after>use value::{InternedString, Pair, Value};
use value::Value::*;
use cell_gc::{GcHeapSession, GcLeaf};
use cell_gc::collections::VecRef;

#[derive(IntoHeap)]
pub enum Expr<'h> {
    /// A constant (`quote` expressions produce this, but also numbers and
    /// other self-evaluating values).
    Con(Value<'h>),

    /// A variable-expression (evaluates to the variable's value).
    Var(GcLeaf<InternedString>),

    /// A lambda expression.
    Fun(CodeRef<'h>),

    /// A function call expression (an application).
    App(VecRef<'h, Expr<'h>>),

    /// A sequence-expression (`begin` used as an expression).
    Seq(VecRef<'h, Expr<'h>>),

    /// A conditional expression (`if`).
    If(IfRef<'h>),

    /// A definition.
    Def(DefRef<'h>),

    /// An assignment expression (`set!`).
    Set(DefRef<'h>),

    /// A `letrec*` expression.
    Letrec(LetrecRef<'h>),

    /// Evaluates to the current global environment.
    /// Used to implement (interactive-environment), for (eval).
    ToplevelEnv,
}

#[derive(IntoHeap)]
pub struct Code<'h> {
    pub params: VecRef<'h, GcLeaf<InternedString>>,
    pub rest: bool,
    pub body: Expr<'h>,
}

#[derive(IntoHeap)]
pub struct Def<'h> {
    pub name: GcLeaf<InternedString>,
    pub value: Expr<'h>
}

#[derive(IntoHeap)]
pub struct If<'h> {
    pub cond: Expr<'h>,
    pub t_expr: Expr<'h>,
    pub f_expr: Expr<'h>,
}

#[derive(IntoHeap)]
pub struct Letrec<'h> {
    pub names: VecRef<'h, GcLeaf<InternedString>>,
    pub exprs: VecRef<'h, Expr<'h>>,
    pub body: Expr<'h>
}

// Convert the linked list of a `<body>` to a vector; also splice in the
// contents of `(begin)` expressions nested within the `<body>`.
fn flatten_body<'h>(forms: Value<'h>, out: &mut Vec<Value<'h>>) -> Result<(), String> {
    for form_res in forms {
        let form = form_res?;
        if let Cons(ref pair) = form {
            if let Symbol(op) = pair.car() {
                if op.as_str() == "begin" {
                    flatten_body(pair.cdr(), out)?;
                    continue;
                }
            }
        }
        out.push(form);
    }
    Ok(())
}

fn is_definition<'h>(form: &Value<'h>) -> bool {
    if let Cons(ref pair) = *form {
        if let Symbol(op) = pair.car() {
            if op.as_str() == "define" {
                return true;
            }
        }
    }
    false
}

// Compile the body of a lambda or letrec*.
fn compile_body<'h>(
    hs: &mut GcHeapSession<'h>,
    body_list: Value<'h>,
) -> Result<Expr<'h>, String> {
    let mut forms = vec![];
    flatten_body(body_list, &mut forms)?;

    let mut names = vec![];
    let mut exprs = vec![];

    let mut i = 0;
    while i < forms.len() && is_definition(&forms[i]) {
        let (name, expr) = parse_define(hs, forms[i].clone())?;
        names.push(name);
        exprs.push(expr);
        i += 1;
    }

    if i == forms.len() {
        return Err("expression required".into());
    }

    let names = hs.alloc(names);
    let exprs = hs.alloc(exprs);
    let body_exprs: Result<Vec<Expr>, String> = forms
        .drain(i..)
        .map(|form| compile_expr(hs, form))
        .collect();
    let body = seq(hs, body_exprs?);
    Ok(Expr::Letrec(hs.alloc(Letrec {
        names,
        exprs,
        body,
    })))
}

fn seq<'h>(hs: &mut GcHeapSession<'h>, mut exprs: Vec<Expr<'h>>) -> Expr<'h> {
    if exprs.len() == 0 {
        Expr::Con(Value::Nil)
    } else if exprs.len() == 1 {
        exprs.pop().unwrap()
    } else {
        Expr::Seq(hs.alloc(exprs))
    }
}

/// On success, returns the two parts of a `(define)` that we care about: the
/// name to define and the compiled expression to populate it.
fn parse_define<'h>(hs: &mut GcHeapSession<'h>, mut defn: Value<'h>)
    -> Result<(GcLeaf<InternedString>, Expr<'h>), String>
{
    loop {
        let (define_symbol, tail) = defn.as_pair("internal error")?;
        let (pattern, rest) = tail.as_pair("(define) with no name")?;
        match pattern {
            Symbol(ident) => {
                let (expr, rest) = rest.as_pair("(define) with no value")?;
                match rest {
                    Nil => {}
                    _ => {
                        return Err(
                            "too many arguments in (define)".to_string(),
                        )
                    }
                };

                let value = compile_expr(hs, expr)?;
                return Ok((ident, value));
            }
            Cons(pair) => {
                // Build desugared definition and compile that.
                let name = pair.car();
                let formals = pair.cdr();

                // Transform `(define (,name ,@formals) ,@rest)
                // to        `(define ,name (lambda ,formals ,@rest))
                let lambda_cdr = Cons(hs.alloc(Pair {
                    car: formals,
                    cdr: rest,
                }));
                let lambda = Cons(hs.alloc(Pair {
                    car: Symbol(GcLeaf::new(InternedString::get("lambda"))),
                    cdr: lambda_cdr,
                }));
                let defn_cddr = Cons(hs.alloc(Pair {
                    car: lambda,
                    cdr: Nil,
                }));
                let defn_cdr = Cons(hs.alloc(Pair {
                    car: name,
                    cdr: defn_cddr,
                }));
                defn = Cons(hs.alloc(Pair {
                    car: define_symbol,
                    cdr: defn_cdr
                }));
            }
            _ => return Err("(define) with a non-symbol name".to_string())
        }
    }
}

pub fn compile_toplevel<'h>(
    hs: &mut GcHeapSession<'h>,
    expr: Value<'h>,
) -> Result<Expr<'h>, String> {
    // TODO: support (begin) here
    if is_definition(&expr) {
        let (name, value) = parse_define(hs, expr)?;
        Ok(Expr::Def(hs.alloc(Def { name, value })))
    } else {
        compile_expr(hs, expr)
    }
}

pub fn compile_expr<'h>(
    hs: &mut GcHeapSession<'h>,
    expr: Value<'h>,
) -> Result<Expr<'h>, String> {
    match expr {
        Symbol(s) => Ok(Expr::Var(s)),

        Cons(p) => {
            let f = p.car();
            if let Symbol(ref s) = f {
                if s.as_str() == "lambda" {
                    let (mut param_list, body_forms) = p.cdr().as_pair("syntax error in lambda")?;

                    let mut names = vec![];
                    while let Cons(pair) = param_list {
                        if let Symbol(s) = pair.car() {
                            names.push(s);
                        } else {
                            return Err("syntax error in lambda arguments".to_string());
                        }
                        param_list = pair.cdr();
                    }
                    let rest =
                        match param_list {
                            Nil => false,
                            Symbol(rest_name) => {
                                names.push(rest_name);
                                true
                            }
                            _ => return Err("syntax error in lambda arguments".to_string())
                        };

                    let params = hs.alloc(names);
                    let body = compile_body(hs, body_forms)?;
                    return Ok(Expr::Fun(hs.alloc(Code { params, rest, body })));
                } else if s.as_str() == "quote" {
                    let (datum, rest) = p.cdr().as_pair("(quote) with no arguments")?;
                    if !rest.is_nil() {
                        return Err("too many arguments to (quote)".to_string());
                    }
                    return Ok(Expr::Con(datum));
                } else if s.as_str() == "if" {
                    let (cond, rest) = p.cdr().as_pair("(if) with no arguments")?;
                    let cond = compile_expr(hs, cond)?;
                    let (tc, rest) = rest.as_pair("missing arguments after (if COND)")?;
                    let t_expr = compile_expr(hs, tc)?;
                    let f_expr =
                        if rest == Nil {
                            Expr::Con(Nil)
                        } else {
                            let (fc, rest) =
                                rest.as_pair("missing 'else' argument after (if COND X)")?;
                            if !rest.is_nil() {
                                return Err("too many arguments in (if) expression".to_string());
                            }
                            compile_expr(hs, fc)?
                        };
                    return Ok(Expr::If(hs.alloc(If { cond, t_expr, f_expr })));
                } else if s.as_str() == "begin" {
                    // In expression context, this is sequencing, not splicing.
                    let mut exprs = vec![];
                    for expr_result in p.cdr() {
                        let expr = expr_result?;
                        exprs.push(compile_expr(hs, expr)?);
                    }
                    return Ok(Expr::Seq(hs.alloc(exprs)));
                } else if s.as_str() == "define" {
                    // In expression context, definitions aren't allowed.
                    return Err("(define) is allowed only at toplevel or in the body \
                                of a function or let-form".into());
                } else if s.as_str() == "letrec" || s.as_str() == "letrec*" {
                    // Treat (letrec) forms just like (letrec*). Nonstandard in
                    // R6RS, which requires implementations to detect invalid
                    // references to letrec bindings before they're bound. But
                    // R5RS does not require this, and anyway well-behaved
                    // programs won't care.
                    let (bindings, body_forms) = p.cdr().as_pair("letrec*: bindings required")?;
                    let mut names = vec![];
                    let mut exprs = vec![];
                    for binding_result in bindings {
                        let binding = binding_result?;
                        let (name_v, rest) = binding.as_pair("letrec*: invalid binding")?;
                        let name = name_v.as_symbol("letrec*: name required")?;
                        let (expr, rest) = rest.as_pair("letrec*: value required for binding")?;
                        if !rest.is_nil() {
                            return Err("(letrec*): too many arguments".to_string());
                        }
                        names.push(GcLeaf::new(name));
                        exprs.push(compile_expr(hs, expr)?);
                    }
                    let names = hs.alloc(names);
                    let exprs = hs.alloc(exprs);
                    let body = compile_body(hs, body_forms)?;
                    return Ok(Expr::Letrec(hs.alloc(Letrec {
                        names,
                        exprs,
                        body,
                    })));
                } else if s.as_str() == "set!" {
                    let (first, rest) = p.cdr().as_pair("(set!) with no name")?;
                    let name = first.as_symbol("(set!) first argument must be a name")?;
                    let (expr, rest) = rest.as_pair("(set!) with no value")?;
                    if !rest.is_nil() {
                        return Err("(set!): too many arguments".to_string());
                    }
                    let value = compile_expr(hs, expr)?;
                    return Ok(Expr::Set(hs.alloc(Def {
                        name: GcLeaf::new(name),
                        value: value
                    })));
                }
            }

            let subexprs: Vec<Expr<'h>> =
                Cons(p)
                    .into_iter()
                    .map(|v| compile_expr(hs, v?))
                    .collect::<Result<_, String>>()?;
            Ok(Expr::App(hs.alloc(subexprs)))
        }

        // Self-evaluating values.
        Bool(v) => Ok(Expr::Con(Bool(v))),
        Int(v) => Ok(Expr::Con(Int(v))),
        ImmString(v) => Ok(Expr::Con(ImmString(v))),

        // Everything else is an error.
        _ => Err(format!("not an expression")),
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use aggregate::{Aggregate, AggregateCall};
use answer::Answer;
use data::Data;
use expr::Expr;
use query::{Query, SortDirection};
use row::Row;
use source::{Source, SourceError};

#[derive(Clone, Debug, PartialEq)]
pub enum ExecuteError {
    SourceError(String),
    InvalidOrderClause(Expr),
}

impl From<SourceError> for ExecuteError {
    fn from(e: SourceError) -> Self {
        ExecuteError::SourceError(e.description)
    }
}

struct Executor {
    query: Query,
    aggregate_calls: Vec<AggregateCall>,
    order_indices: Vec<(usize, SortDirection)>,
}

impl Executor {
    fn new(query: Query) -> Result<Self, ExecuteError> {
        let aggregates = query.select.iter()
            .filter_map(|expr| expr.get_aggregate_call())
            .collect();

        let mut order_indices = Vec::new();
        for sort_field in query.order.iter() {
            let position = query.select.iter().position(|select| select == &sort_field.expr);
            let index = match position {
                Some(i) => i,
                None => return Err(ExecuteError::InvalidOrderClause(sort_field.expr.clone())),
            };
            let direction = sort_field.direction.clone().unwrap_or(SortDirection::Asc);
            order_indices.push((index, direction));
        }

        Ok(Executor {
            query: query,
            aggregate_calls: aggregates,
            order_indices: order_indices,
        })
    }

    fn execute(&self, source: Source) -> Result<Answer, ExecuteError> {
        let mut source = self.apply_condition(source);
        source = self.compute_aggregates(source)?;

        let mut answer = self.apply_select(source)?;
        answer.sort(&self.order_indices);
        Ok(answer)
    }

    fn build_aggregates(&self,
                        source: Source)
                        -> Result<HashMap<Vec<Data>, Vec<Aggregate>>, ExecuteError> {
        let mut groups = HashMap::new();
        for row in source {
            let row = row?;
            if !self.passes_condition(&row) {
                continue;
            }

            let group_aggregates = groups
                .entry(self.get_group(&row))
                .or_insert_with(|| self.make_aggregates());

            for (i, aggregate) in group_aggregates.iter_mut().enumerate() {
                aggregate.apply(self.aggregate_calls[i].argument.eval(&row));
            }
        }

        Ok(groups)
    }

    fn aggregates_to_source(&self, aggregates: HashMap<Vec<Data>, Vec<Aggregate>>) -> Source {
        let mut rows = Vec::with_capacity(aggregates.len());
        for (group, aggregates) in aggregates {
            let mut row = Row::new();
            for (i, aggregate) in aggregates.into_iter().enumerate() {
                let call = self.aggregate_calls[i].clone();
                row.fields.insert(Expr::AggregateCall(call), aggregate.final_value());
            }
            for (index, val) in group.iter().enumerate() {
                row.fields.insert(self.query.group[index].clone(), val.clone());
            }
            rows.push(Ok(row));
        }

        Box::new(rows.into_iter())
    }

    fn apply_condition(&self, source: Source) -> Source {
        let condition = match self.query.condition {
            Some(ref cond) => cond.clone(),
            None => return source,
        };

        Box::new(source.filter(move |row| {
            match row {
                &Err(_) => true,
                &Ok(ref row) => condition.eval(row) == Data::Bool(true),
            }
        }))
    }

    fn compute_aggregates(&self, source: Source) -> Result<Source, ExecuteError> {
        if self.aggregate_calls.is_empty() {
            return Ok(source);
        }

        let aggregates = self.build_aggregates(source)?;
        Ok(self.aggregates_to_source(aggregates))
    }

    fn apply_select(&self, source: Source) -> Result<Answer, ExecuteError> {
        let mut rows = Vec::new();

        for row in source {
            let row = row?;
            let output_row = self.query
                .select
                .iter()
                .map(|field| field.eval(&row))
                .collect();
            rows.push(output_row);
        }

        Ok(Answer {
            columns: self.get_columns(),
            rows: rows,
        })
    }

    fn passes_condition(&self, row: &Row) -> bool {
        match self.query.condition {
            Some(ref cond) => cond.eval(row) == Data::Bool(true),
            None => true,
        }
    }

    fn get_columns(&self) -> Vec<String> {
        self.query.select.iter()
            .map(|field| format!("{}", field))
            .collect()
    }

    fn get_group(&self, row: &Row) -> Vec<Data> {
        self.query.group.iter()
            .map(|field| field.eval(row))
            .collect()
    }

    fn make_aggregates(&self) -> Vec<Aggregate> {
        self.aggregate_calls.iter()
            .map(|call| call.function.aggregate())
            .collect()
    }
}

pub fn execute(query: Query, source: Source) -> Result<Answer, ExecuteError> {
    Executor::new(query)?.execute(source)
}

#[cfg(test)]
mod tests {
    use super::*;
    use aggregate::{AggregateCall, AggregateFunction};
    use data::Data;
    use expr::Expr;
    use query::OrderField;
    use row::make_rows;

    #[test]
    fn aggregate_query() {
        let source = make_rows(
            vec!["a"],
            vec![
                data_vec![1],
                data_vec![2],
                data_vec![3],
                data_vec![4],
                data_vec![5],
            ],
        );

        let call = AggregateCall{
            function: AggregateFunction::Sum,
            argument: Box::new(Expr::Column(String::from("a"))),
        };

        let query = Query {
            select: vec![Expr::AggregateCall(call)],
            from: String::new(),
            condition: None,
            group: vec![],
            order: vec![],
        };

        let actual = execute(query, Box::new(source.into_iter())).unwrap();
        let expected = Answer {
            columns: vec![String::from("sum(a)")],
            rows: vec![data_vec![15]],
        };

        assert_eq!(expected, actual);
    }

    #[test]
    fn non_aggregate_query() {
        let source = make_rows(
            vec!["a"],
            vec![
                data_vec![1],
                data_vec![2],
                data_vec![3],
                data_vec![4],
                data_vec![5],
            ],
        );

        let query = Query {
            select: vec![Expr::Column(String::from("a"))],
            from: String::new(),
            condition: None,
            group: vec![],
            order: vec![],
        };

        let actual = execute(query, Box::new(source.clone().into_iter())).unwrap();
        let expected = Answer {
            columns: vec![String::from("a")],
            rows: vec![
                data_vec![1],
                data_vec![2],
                data_vec![3],
                data_vec![4],
                data_vec![5],
            ],
        };

        assert_eq!(expected, actual);
    }

    #[test]
    fn invalid_order_clause() {
        let source = make_rows(
            vec!["a"],
            vec![],
        );

        let query = Query {
            select: vec![],
            from: String::new(),
            condition: None,
            group: vec![],
            order: vec![OrderField {
                expr: Expr::Column(String::from("a")),
                direction: None,
            }],
        };
        let actual = execute(query, Box::new(source.clone().into_iter()));
        let expected = Err(ExecuteError::InvalidOrderClause(Expr::Column(String::from("a"))));
        assert_eq!(expected, actual);
    }
}
<commit_msg>Remove unnecessary where clause check<commit_after>use std::collections::HashMap;
use aggregate::{Aggregate, AggregateCall};
use answer::Answer;
use data::Data;
use expr::Expr;
use query::{Query, SortDirection};
use row::Row;
use source::{Source, SourceError};

#[derive(Clone, Debug, PartialEq)]
pub enum ExecuteError {
    SourceError(String),
    InvalidOrderClause(Expr),
}

impl From<SourceError> for ExecuteError {
    fn from(e: SourceError) -> Self {
        ExecuteError::SourceError(e.description)
    }
}

struct Executor {
    query: Query,
    aggregate_calls: Vec<AggregateCall>,
    order_indices: Vec<(usize, SortDirection)>,
}

impl Executor {
    fn new(query: Query) -> Result<Self, ExecuteError> {
        let aggregates = query.select.iter()
            .filter_map(|expr| expr.get_aggregate_call())
            .collect();

        let mut order_indices = Vec::new();
        for sort_field in query.order.iter() {
            let position = query.select.iter().position(|select| select == &sort_field.expr);
            let index = match position {
                Some(i) => i,
                None => return Err(ExecuteError::InvalidOrderClause(sort_field.expr.clone())),
            };
            let direction = sort_field.direction.clone().unwrap_or(SortDirection::Asc);
            order_indices.push((index, direction));
        }

        Ok(Executor {
            query: query,
            aggregate_calls: aggregates,
            order_indices: order_indices,
        })
    }

    fn execute(&self, source: Source) -> Result<Answer, ExecuteError> {
        let mut source = self.apply_condition(source);
        source = self.compute_aggregates(source)?;

        let mut answer = self.apply_select(source)?;
        answer.sort(&self.order_indices);
        Ok(answer)
    }

    fn build_aggregates(&self,
                        source: Source)
                        -> Result<HashMap<Vec<Data>, Vec<Aggregate>>, ExecuteError> {
        let mut groups = HashMap::new();
        for row in source {
            let row = row?;
            let group_aggregates = groups
                .entry(self.get_group(&row))
                .or_insert_with(|| self.make_aggregates());

            for (i, aggregate) in group_aggregates.iter_mut().enumerate() {
                aggregate.apply(self.aggregate_calls[i].argument.eval(&row));
            }
        }

        Ok(groups)
    }

    fn aggregates_to_source(&self, aggregates: HashMap<Vec<Data>, Vec<Aggregate>>) -> Source {
        let mut rows = Vec::with_capacity(aggregates.len());
        for (group, aggregates) in aggregates {
            let mut row = Row::new();
            for (i, aggregate) in aggregates.into_iter().enumerate() {
                let call = self.aggregate_calls[i].clone();
                row.fields.insert(Expr::AggregateCall(call), aggregate.final_value());
            }
            for (index, val) in group.iter().enumerate() {
                row.fields.insert(self.query.group[index].clone(), val.clone());
            }
            rows.push(Ok(row));
        }

        Box::new(rows.into_iter())
    }

    fn apply_condition(&self, source: Source) -> Source {
        let condition = match self.query.condition {
            Some(ref cond) => cond.clone(),
            None => return source,
        };

        Box::new(source.filter(move |row| {
            match row {
                &Err(_) => true,
                &Ok(ref row) => condition.eval(row) == Data::Bool(true),
            }
        }))
    }

    fn compute_aggregates(&self, source: Source) -> Result<Source, ExecuteError> {
        if self.aggregate_calls.is_empty() {
            return Ok(source);
        }

        let aggregates = self.build_aggregates(source)?;
        Ok(self.aggregates_to_source(aggregates))
    }

    fn apply_select(&self, source: Source) -> Result<Answer, ExecuteError> {
        let mut rows = Vec::new();

        for row in source {
            let row = row?;
            let output_row = self.query
                .select
                .iter()
                .map(|field| field.eval(&row))
                .collect();
            rows.push(output_row);
        }

        Ok(Answer {
            columns: self.get_columns(),
            rows: rows,
        })
    }

    fn get_columns(&self) -> Vec<String> {
        self.query.select.iter()
            .map(|field| format!("{}", field))
            .collect()
    }

    fn get_group(&self, row: &Row) -> Vec<Data> {
        self.query.group.iter()
            .map(|field| field.eval(row))
            .collect()
    }

    fn make_aggregates(&self) -> Vec<Aggregate> {
        self.aggregate_calls.iter()
            .map(|call| call.function.aggregate())
            .collect()
    }
}

pub fn execute(query: Query, source: Source) -> Result<Answer, ExecuteError> {
    Executor::new(query)?.execute(source)
}

#[cfg(test)]
mod tests {
    use super::*;
    use aggregate::{AggregateCall, AggregateFunction};
    use data::Data;
    use expr::Expr;
    use query::OrderField;
    use row::make_rows;

    #[test]
    fn aggregate_query() {
        let source = make_rows(
            vec!["a"],
            vec![
                data_vec![1],
                data_vec![2],
                data_vec![3],
                data_vec![4],
                data_vec![5],
            ],
        );

        let call = AggregateCall{
            function: AggregateFunction::Sum,
            argument: Box::new(Expr::Column(String::from("a"))),
        };

        let query = Query {
            select: vec![Expr::AggregateCall(call)],
            from: String::new(),
            condition: None,
            group: vec![],
            order: vec![],
        };

        let actual = execute(query, Box::new(source.into_iter())).unwrap();
        let expected = Answer {
            columns: vec![String::from("sum(a)")],
            rows: vec![data_vec![15]],
        };

        assert_eq!(expected, actual);
    }

    #[test]
    fn non_aggregate_query() {
        let source = make_rows(
            vec!["a"],
            vec![
                data_vec![1],
                data_vec![2],
                data_vec![3],
                data_vec![4],
                data_vec![5],
            ],
        );

        let query = Query {
            select: vec![Expr::Column(String::from("a"))],
            from: String::new(),
            condition: None,
            group: vec![],
            order: vec![],
        };

        let actual = execute(query, Box::new(source.clone().into_iter())).unwrap();
        let expected = Answer {
            columns: vec![String::from("a")],
            rows: vec![
                data_vec![1],
                data_vec![2],
                data_vec![3],
                data_vec![4],
                data_vec![5],
            ],
        };

        assert_eq!(expected, actual);
    }

    #[test]
    fn invalid_order_clause() {
        let source = make_rows(
            vec!["a"],
            vec![],
        );

        let query = Query {
            select: vec![],
            from: String::new(),
            condition: None,
            group: vec![],
            order: vec![OrderField {
                expr: Expr::Column(String::from("a")),
                direction: None,
            }],
        };
        let actual = execute(query, Box::new(source.clone().into_iter()));
        let expected = Err(ExecuteError::InvalidOrderClause(Expr::Column(String::from("a"))));
        assert_eq!(expected, actual);
    }
}
<|endoftext|>


<commit_before>use parser::combinators::{Parser, StrParser, ParseTo, Consumer, string, character};
use self::Token::{LParen, RParen, Whitespace, Identifier};

#[derive(Copy, Clone, Eq, Hash, Ord, PartialOrd, Debug)]
pub enum Token<'a> {
    LParen,
    RParen,
    Whitespace,
    Identifier(&'a str),
}

impl<'a,'b> PartialEq<Token<'b>> for Token<'a> {
    fn eq(&self, rhs: &Token<'b>) -> bool {
        match (*self, *rhs) {
            (LParen, LParen)                       => true,
            (RParen, RParen)                       => true,
            (Whitespace, Whitespace)               => true,
            (Identifier(ref x), Identifier(ref y)) => x == y,
            _                                      => false
        }
    }
}

impl<'a> From<Token<'a>> for String {
    fn from(tok: Token<'a>) -> String {
        String::from(match tok {
            LParen => "(",
            RParen => ")",
            Whitespace => "<space>",
            Identifier(x) => x,
        })
    }
}

pub trait LexerConsumer<D> where D: for<'a> Consumer<Token<'a>> {
    fn accept<L>(self, lexer: L) where L: for<'a> ParseTo<&'a str,D>;
}

fn mk_identifier<'a>(s: &'a str) -> Token<'a> { Identifier(s) }

#[allow(non_snake_case)]
pub fn lexer<C,D>(consumer: C) where C: LexerConsumer<D>, D: for<'a> Consumer<Token<'a>> {
    let LPAREN = string("(").map(|_| LParen);
    let RPAREN = string(")").map(|_| RParen);
    let WHITESPACE = character(char::is_whitespace).map(|_| Whitespace);
    let IDENTIFIER = character(char::is_alphabetic).and_then(character(char::is_alphanumeric).star())
                                                   .buffer().map(mk_identifier);
    let TOKEN = LPAREN.or_else(RPAREN).or_else(WHITESPACE).or_else(IDENTIFIER);
    consumer.accept(TOKEN.star())
}

#[test]
fn test_lexer() {
    impl<'a> Consumer<Token<'a>> for Vec<Token<'static>> {
        fn accept(&mut self, token: Token<'a>) {
            assert_eq!(self.remove(0), token);
        }
    }
    struct TestConsumer;
    impl<'a> LexerConsumer<Vec<Token<'static>>> for TestConsumer {
        fn accept<P>(self, mut lex: P) where P: ParseTo<&'a str,Vec<Token<'static>>> {
            let mut tokens = vec![LParen, Identifier("a123"), Whitespace, Whitespace, Identifier("bcd"), RParen];
            lex.push_to("(a123  bcd)", &mut tokens);
            assert_eq!(tokens, []);
        }
    }
    lexer(TestConsumer);
}

#[test]
fn test_partial_eq() {
    use std::fmt::Debug;
    fn foo<T,U>(lhs: T, rhs: U) where T: Debug+PartialEq<U>, U: Debug{
        assert_eq!(lhs, rhs)
    }
    fn bar<'b,T>(lhs: T, rhs: Token<'b>) where T: Debug+for<'a> PartialEq<Token<'a>> {
        foo(lhs, rhs)
    }
    let hi = String::from("hi");
    bar(Identifier("hi"),Identifier(&*hi));
    bar(Identifier(&*hi),Identifier("hi"));
}
<commit_msg>Rewrote unit test.<commit_after>use parser::combinators::{Parser, StrParser, ParseTo, Consumer, string, character};
use self::Token::{LParen, RParen, Whitespace, Identifier};

#[derive(Copy, Clone, Eq, Hash, Ord, PartialOrd, Debug)]
pub enum Token<'a> {
    LParen,
    RParen,
    Whitespace,
    Identifier(&'a str),
}

impl<'a,'b> PartialEq<Token<'b>> for Token<'a> {
    fn eq(&self, rhs: &Token<'b>) -> bool {
        match (*self, *rhs) {
            (LParen, LParen)                       => true,
            (RParen, RParen)                       => true,
            (Whitespace, Whitespace)               => true,
            (Identifier(ref x), Identifier(ref y)) => x == y,
            _                                      => false
        }
    }
}

impl<'a> From<Token<'a>> for String {
    fn from(tok: Token<'a>) -> String {
        String::from(match tok {
            LParen => "(",
            RParen => ")",
            Whitespace => "<space>",
            Identifier(x) => x,
        })
    }
}

pub trait LexerConsumer<D> where D: for<'a> Consumer<Token<'a>> {
    fn accept<L>(self, lexer: L) where L: for<'a> ParseTo<&'a str,D>;
}

fn mk_identifier<'a>(s: &'a str) -> Token<'a> { Identifier(s) }

#[allow(non_snake_case)]
pub fn lexer<C,D>(consumer: C) where C: LexerConsumer<D>, D: for<'a> Consumer<Token<'a>> {
    let LPAREN = string("(").map(|_| LParen);
    let RPAREN = string(")").map(|_| RParen);
    let WHITESPACE = character(char::is_whitespace).map(|_| Whitespace);
    let IDENTIFIER = character(char::is_alphabetic).and_then(character(char::is_alphanumeric).star())
                                                   .buffer().map(mk_identifier);
    let TOKEN = LPAREN.or_else(RPAREN).or_else(WHITESPACE).or_else(IDENTIFIER);
    consumer.accept(TOKEN.star())
}

#[test]
fn test_lexer() {
    struct TestConsumer(Vec<String>);
    impl<'a> Consumer<Token<'a>> for TestConsumer {
        fn accept(&mut self, tok: Token<'a>) {
            self.0.push(String::from(tok));
        }
    }
    impl LexerConsumer<TestConsumer> for TestConsumer {
        fn accept<L>(mut self, mut lex: L) where L: for<'a> ParseTo<&'a str,TestConsumer> {
            lex.push_to("(a123  bcd)", &mut self);
            assert_eq!(self.0, vec!["(", "a123", "<space>", "<space>", "bcd", ")"]);
        }
    }
    lexer(TestConsumer(Vec::new()));
}

#[test]
fn test_partial_eq() {
    use std::fmt::Debug;
    fn foo<T,U>(lhs: T, rhs: U) where T: Debug+PartialEq<U>, U: Debug{
        assert_eq!(lhs, rhs)
    }
    fn bar<'b,T>(lhs: T, rhs: Token<'b>) where T: Debug+for<'a> PartialEq<Token<'a>> {
        foo(lhs, rhs)
    }
    let hi = String::from("hi");
    bar(Identifier("hi"),Identifier(&*hi));
    bar(Identifier(&*hi),Identifier("hi"));
}
<|endoftext|>


<commit_before>use bits;
use consts;

/// Decodes symbol from sample at each symbol instant.
#[derive(Copy, Clone)]
pub struct Decoder {
    pos: usize,
    decider: Decider,
}

impl Decoder {
    /// Create a new Decoder with the given symbol decider.
    pub fn new(decider: Decider) -> Decoder {
        Decoder {
            // Decoder is created after first sample of first symbol after sync has
            // already been read.
            pos: 1,
            decider: decider,
        }
    }

    /// Examine the given sample and, based on the symbol clock, decode it a symbol or
    /// do nothing.
    pub fn feed(&mut self, s: f32) -> Option<bits::Dibit> {
        self.pos += 1;
        self.pos %= consts::PERIOD;

        if self.pos == 0 {
            Some(self.decider.decide(s))
        } else {
            None
        }
    }
}

/// Decides which symbol a sample represents with a threshold method.
#[derive(Copy, Clone)]
pub struct Decider {
    pthresh: f32,
    mthresh: f32,
    nthresh: f32,
}

impl Decider {
    /// Create a new Decider with the given positive threshold, mid threshold, and
    /// negative threshold.
    pub fn new(pthresh: f32, mthresh: f32, nthresh: f32) -> Decider {
        Decider {
            pthresh: pthresh,
            mthresh: mthresh,
            nthresh: nthresh,
        }
    }

    /// Decide with symbol the given sample looks closest to.
    pub fn decide(&self, sample: f32) -> bits::Dibit {
        if sample > self.pthresh {
            bits::Dibit::new(0b01)
        } else if sample > self.mthresh && sample <= self.pthresh {
            bits::Dibit::new(0b00)
        } else if sample <= self.mthresh && sample > self.nthresh {
            bits::Dibit::new(0b10)
        } else {
            bits::Dibit::new(0b11)
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_decider() {
        let d = Decider::new(-0.004, -0.1, -0.196);

        assert_eq!(d.decide(0.044).bits(), 0b01);
        assert_eq!(d.decide(-0.052).bits(), 0b00);
        assert_eq!(d.decide(-0.148).bits(), 0b10);
        assert_eq!(d.decide(-0.244).bits(), 0b11);
    }

    #[test]
    fn test_decoder() {
        let mut d = Decoder::new(Decider::new(0.0, 0.0, 0.0));

        assert!(d.feed(0.2099609375000000).is_none());
        assert!(d.feed(0.2165222167968750).is_none());
        assert!(d.feed(0.2179870605468750).is_none());
        assert!(d.feed(0.2152709960937500).is_none());
        assert!(d.feed(0.2094726562500000).is_none());
        assert!(d.feed(0.2018737792968750).is_none());
        assert!(d.feed(0.1937255859375000).is_none());
        assert!(d.feed(0.1861572265625000).is_none());
        assert!(d.feed(0.1799926757812500).is_some());

        assert!(d.feed(0.1752929687500000).is_none());
        assert!(d.feed(0.1726684570312500).is_none());
        assert!(d.feed(0.1720886230468750).is_none());
        assert!(d.feed(0.1732177734375000).is_none());
        assert!(d.feed(0.1754455566406250).is_none());
        assert!(d.feed(0.1780395507812500).is_none());
        assert!(d.feed(0.1803588867187500).is_none());
        assert!(d.feed(0.1817321777343750).is_none());
        assert!(d.feed(0.1816711425781250).is_none());
        assert!(d.feed(0.1799926757812500).is_some());
    }
}
<commit_msg>Add some more docs to baseband::decode module<commit_after>//! Utilities for decoding a C4FM signal into symbols.

use bits;
use consts;

/// Decodes symbol from sample at each symbol instant.
#[derive(Copy, Clone)]
pub struct Decoder {
    /// Sample index into current symbol period.
    pos: usize,
    /// Decider used for decoding symbol at each symbol instant.
    decider: Decider,
}

impl Decoder {
    /// Create a new `Decoder` with the given symbol decider, initialized to decode the
    /// first symbol after the frame sync has been detected.
    pub fn new(decider: Decider) -> Decoder {
        Decoder {
            // The frame sync sequence is detected one sample after its last symbol
            // instant (i.e., the first sample in the next symbol period after the
            // sequence), so take that sample into account.
            pos: 1,
            decider: decider,
        }
    }

    /// Examine the given sample and, based on the symbol clock, decode it a symbol or
    /// do nothing.
    pub fn feed(&mut self, s: f32) -> Option<bits::Dibit> {
        self.pos += 1;
        self.pos %= consts::PERIOD;

        if self.pos == 0 {
            Some(self.decider.decide(s))
        } else {
            None
        }
    }
}

/// Decides which symbol a sample represents with a threshold method.
#[derive(Copy, Clone)]
pub struct Decider {
    /// Upper threshold.
    pthresh: f32,
    /// Middle threshold.
    mthresh: f32,
    /// Lower threshold.
    nthresh: f32,
}

impl Decider {
    /// Create a new Decider with the given positive threshold, mid threshold, and
    /// negative threshold.
    pub fn new(pthresh: f32, mthresh: f32, nthresh: f32) -> Decider {
        Decider {
            pthresh: pthresh,
            mthresh: mthresh,
            nthresh: nthresh,
        }
    }

    /// Decide which symbol the given sample looks closest to.
    pub fn decide(&self, sample: f32) -> bits::Dibit {
        if sample > self.pthresh {
            bits::Dibit::new(0b01)
        } else if sample > self.mthresh && sample <= self.pthresh {
            bits::Dibit::new(0b00)
        } else if sample <= self.mthresh && sample > self.nthresh {
            bits::Dibit::new(0b10)
        } else {
            bits::Dibit::new(0b11)
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_decider() {
        let d = Decider::new(-0.004, -0.1, -0.196);

        assert_eq!(d.decide(0.044).bits(), 0b01);
        assert_eq!(d.decide(-0.052).bits(), 0b00);
        assert_eq!(d.decide(-0.148).bits(), 0b10);
        assert_eq!(d.decide(-0.244).bits(), 0b11);
    }

    #[test]
    fn test_decoder() {
        let mut d = Decoder::new(Decider::new(0.0, 0.0, 0.0));

        assert!(d.feed(0.2099609375000000).is_none());
        assert!(d.feed(0.2165222167968750).is_none());
        assert!(d.feed(0.2179870605468750).is_none());
        assert!(d.feed(0.2152709960937500).is_none());
        assert!(d.feed(0.2094726562500000).is_none());
        assert!(d.feed(0.2018737792968750).is_none());
        assert!(d.feed(0.1937255859375000).is_none());
        assert!(d.feed(0.1861572265625000).is_none());
        assert!(d.feed(0.1799926757812500).is_some());

        assert!(d.feed(0.1752929687500000).is_none());
        assert!(d.feed(0.1726684570312500).is_none());
        assert!(d.feed(0.1720886230468750).is_none());
        assert!(d.feed(0.1732177734375000).is_none());
        assert!(d.feed(0.1754455566406250).is_none());
        assert!(d.feed(0.1780395507812500).is_none());
        assert!(d.feed(0.1803588867187500).is_none());
        assert!(d.feed(0.1817321777343750).is_none());
        assert!(d.feed(0.1816711425781250).is_none());
        assert!(d.feed(0.1799926757812500).is_some());
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(optin_builtin_traits)]

// pp-exact

trait UnsafeTrait {
    fn foo(&self);
}

impl !UnsafeTrait for int {
    fn foo(&self) { }
}

pub fn main() { }
<commit_msg>fix pretty test fallout<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(optin_builtin_traits)]

// pp-exact

struct Test;

impl !Send for Test { }

pub fn main() { }
<|endoftext|>


<commit_before>//! This module initializes a project.

use std::{fs, io, error};

use git2::Repository;

#[derive(Debug)]
pub enum InitError<'a> {
    Io(io::Error),
    FolderNotEmpty(&'a str, usize),
    TodoErr
}

impl error::Error for InitError {
    fn description(&self) -> &str {
        match self {
            Io(err) => format!("IoError occurred: {}", err.description),
            FolderNotEmpty(root, count) => format!("{} was not empty: {} files exist", root, count),
            TodoErr => "TodoErr",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self {
            Io(err) => Some(err),
            FolderNotEmpty(_, _) => None,
            TodoErr => None,
        }
    }
}

/// Creates a folder. The folder must not exist or must be empty.
///
/// Impure.
pub fn make_project_folder(root: &str) -> Result<(), InitError> {
    // Make the folder - ignore error.
    let _ = fs::create_dir(root);

    // Check that the folder is empty
    fs::read_dir(root)
        .map_err(|err| InitError::Io(err))
        .and_then(|iter| {
            let count = iter.count();
            if count == 0 {
                Ok(())
            } else {
                Err(InitError::FolderNotEmpty(root, count))
            }
        })
}

/// Initializes a git repository at root.
///
/// Impure.
pub fn make_repository(root: &str) -> Result<Repository, InitError> {
    unimplemented!()
}<commit_msg>Revert "A bunch of error handling thats just too much"<commit_after>//! This module initializes a project.

use std::fs;
use std::io::{Result, Error, ErrorKind};

use git2::Repository;

/// Creates a folder. The folder must not exist or must be empty.
///
/// Impure.
pub fn make_project_folder(root: &str) -> Result<()> {
    // Make the folder - ignore error.
    let _ = fs::create_dir(root);

    // Check that the folder is empty
    fs::read_dir(root)
        .and_then(|iter| {
            let count = iter.count();
            if count == 0 {
                Ok(())
            } else {
                dir_not_empty_err(root, count)
            }
        })
}

fn dir_not_empty_err(root: &str, count: usize) -> Result<()> {
    Err(Error::new(ErrorKind::Other, format!("{} was not empty: {} files exist", root, count)))
}

/// Initializes a git repository at root.
///
/// Impure.
pub fn make_repository(root: &str) -> Result<()> {
    Ok(())
}<|endoftext|>