<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::ascii::AsciiExt;
use std::str::CowString;
use std::ops;
use tokenizer::{mod, Token, NumericValue, PercentageValue, Tokenizer, SourceLocation};

#[deriving(PartialEq, Eq, Show, Clone, Copy)]
pub struct SourcePosition {
    position: tokenizer::SourcePosition,
    at_start_of: Option<BlockType>,
}

/// Like std::borrow::Cow, except:
///
/// * The Owned variant is boxed
/// * The Borrowed variant contains a mutable reference.
enum MaybeOwned<'a, T: 'a> {
    Owned(Box<T>),
    Borrowed(&'a mut T),
}

impl<'a, T> ops::Deref<T> for MaybeOwned<'a, T> {
    fn deref<'a>(&'a self) -> &'a T {
        match *self {
            MaybeOwned::Owned(ref pointer) => &**pointer,
            MaybeOwned::Borrowed(ref pointer) => &**pointer,
        }
    }
}

impl<'a, T> ops::DerefMut<T> for MaybeOwned<'a, T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        match *self {
            MaybeOwned::Owned(ref mut pointer) => &mut **pointer,
            MaybeOwned::Borrowed(ref mut pointer) => &mut **pointer,
        }
    }
}

impl<'a, T> Clone for MaybeOwned<'a, T> where T: Clone {
    fn clone(&self) -> MaybeOwned<'a, T> {
        MaybeOwned::Owned(box() (**self).clone())
    }
}

#[deriving(Clone)]
pub struct Parser<'i: 't, 't> {
    tokenizer: MaybeOwned<'t, Tokenizer<'i>>,
    /// If `Some(_)`, .parse_nested_block() can be called.
    at_start_of: Option<BlockType>,
    /// For parsers from `parse_until` or `parse_nested_block`
    stop_before: Delimiters,
}

#[deriving(Copy, Clone, PartialEq, Eq, Show)]
enum BlockType {
    Parenthesis,
    SquareBracket,
    CurlyBracket,
}

impl BlockType {
    fn opening(token: &Token) -> Option<BlockType> {
        match *token {
            Token::Function(_) |
            Token::ParenthesisBlock => Some(BlockType::Parenthesis),
            Token::SquareBracketBlock => Some(BlockType::SquareBracket),
            Token::CurlyBracketBlock => Some(BlockType::CurlyBracket),
            _ => None
        }
    }

    fn closing(token: &Token) -> Option<BlockType> {
        match *token {
            Token::CloseParenthesis => Some(BlockType::Parenthesis),
            Token::CloseSquareBracket => Some(BlockType::SquareBracket),
            Token::CloseCurlyBracket => Some(BlockType::CurlyBracket),
            _ => None
        }
    }
}

#[deriving(Copy, Clone, PartialEq, Eq, Show)]
pub struct Delimiters {
    bits: u8,
}

#[allow(non_upper_case_globals, non_snake_case)]
pub mod Delimiter {
    use super::Delimiters;

    pub const None: Delimiters = Delimiters { bits: 0 };
    /// `{`
    pub const CurlyBracketBlock: Delimiters = Delimiters { bits: 1 << 1 };
    /// `;`
    pub const Semicolon: Delimiters = Delimiters { bits: 1 << 2 };
    /// `!`
    pub const Bang: Delimiters = Delimiters { bits: 1 << 3 };
    /// `,`
    pub const Comma: Delimiters = Delimiters { bits: 1 << 4 };
}

#[allow(non_upper_case_globals, non_snake_case)]
mod ClosingDelimiter {
    use super::Delimiters;

    pub const CloseCurlyBracket: Delimiters = Delimiters { bits: 1 << 5 };
    pub const CloseSquareBracket: Delimiters = Delimiters { bits: 1 << 6 };
    pub const CloseParenthesis: Delimiters = Delimiters { bits: 1 << 7 };
}

impl BitOr<Delimiters, Delimiters> for Delimiters {
    fn bitor(&self, other: &Delimiters) -> Delimiters {
        Delimiters { bits: self.bits | other.bits }
    }
}

impl Delimiters {
    fn contains(self, other: Delimiters) -> bool {
        (self.bits & other.bits) != 0
    }

    fn from_byte(byte: Option<u8>) -> Delimiters {
        match byte {
            Some(b';') => Delimiter::Semicolon,
            Some(b',') => Delimiter::Comma,
            Some(b'!') => Delimiter::Bang,
            Some(b'{') => Delimiter::CurlyBracketBlock,
            Some(b'}') => ClosingDelimiter::CloseCurlyBracket,
            Some(b']') => ClosingDelimiter::CloseSquareBracket,
            Some(b')') => ClosingDelimiter::CloseParenthesis,
            _ => Delimiter::None,
        }
    }
}

impl<'i, 't> Parser<'i, 't> {
    #[inline]
    pub fn new(input: &'i str) -> Parser<'i, 'i> {
        Parser {
            tokenizer: MaybeOwned::Owned(box Tokenizer::new(input)),
            at_start_of: None,
            stop_before: Delimiter::None,
        }
    }

    #[inline]
    pub fn is_exhausted(&mut self) -> bool {
        self.expect_exhausted().is_ok()
    }

    #[inline]
    pub fn expect_exhausted(&mut self) -> Result<(), ()> {
        let start_position = self.position();
        match self.next() {
            Err(()) => Ok(()),
            Ok(_) => {
                self.reset(start_position);
                Err(())
            }
        }
    }

    #[inline]
    pub fn position(&self) -> SourcePosition {
        SourcePosition {
            position: self.tokenizer.position(),
            at_start_of: self.at_start_of,
        }
    }

    #[inline]
    pub fn reset(&mut self, new_position: SourcePosition) {
        self.tokenizer.reset(new_position.position);
        self.at_start_of = new_position.at_start_of;
    }

    #[inline]
    pub fn try<T, E>(&mut self, thing: |&mut Parser| -> Result<T, E>) -> Result<T, E> {
        let start_position = self.position();
        let result = thing(self);
        if result.is_err() {
            self.reset(start_position)
        }
        result
    }

    #[inline]
    pub fn slice_from(&self, start_position: SourcePosition) -> &'i str {
        self.tokenizer.slice_from(start_position.position)
    }

    #[inline]
    pub fn current_source_location(&self) -> SourceLocation {
        self.tokenizer.current_source_location()
    }

    #[inline]
    pub fn source_location(&self, target: SourcePosition) -> SourceLocation {
        self.tokenizer.source_location(target.position)
    }

    pub fn next(&mut self) -> Result<Token<'i>, ()> {
        loop {
            match self.next_including_whitespace() {
                Ok(Token::WhiteSpace) => {},
                result => return result
            }
        }
    }

    pub fn next_including_whitespace(&mut self) -> Result<Token<'i>, ()> {
        if let Some(block_type) = self.at_start_of.take() {
            consume_until_end_of_block(block_type, &mut *self.tokenizer);
        }
        if self.stop_before.contains(Delimiters::from_byte(self.tokenizer.next_byte())) {
            return Err(())
        }
        let token = try!(self.tokenizer.next());
        if let Some(block_type) = BlockType::opening(&token) {
            self.at_start_of = Some(block_type);
        }
        Ok(token)
    }

    // FIXME: Take an unboxed `FnOnce` closure.
    #[inline]
    pub fn parse_entirely<T>(&mut self, parse: |&mut Parser| -> Result<T, ()>)
                             -> Result<T, ()> {
        let result = parse(self);
        try!(self.expect_exhausted());
        result
    }

    #[inline]
    pub fn parse_comma_separated<T>(&mut self, parse_one: |&mut Parser| -> Result<T, ()>)
                                    -> Result<Vec<T>, ()> {
        let mut values = vec![];
        loop {
            values.push(try!(self.parse_until_before(Delimiter::Comma, |parser| parse_one(parser))));
            match self.next() {
                Err(()) => return Ok(values),
                Ok(Token::Comma) => continue,
                Ok(_) => unreachable!(),
            }
        }
    }

    #[inline]
    pub fn parse_nested_block<T>(&mut self, parse: |&mut Parser| -> Result<T, ()>)
                                 -> Result <T, ()> {
        let block_type = self.at_start_of.take().expect("\
            A nested parser can only be created when a Function, \
            ParenthesisBlock, SquareBracketBlock, or CurlyBracketBlock \
            token was just consumed.\
        ");
        let closing_delimiter = match block_type {
            BlockType::CurlyBracket => ClosingDelimiter::CloseCurlyBracket,
            BlockType::SquareBracket => ClosingDelimiter::CloseSquareBracket,
            BlockType::Parenthesis => ClosingDelimiter::CloseParenthesis,
        };
        let result;
        // Introduce a new scope to limit duration of nested_parser’s borrow
        {
            let mut nested_parser = Parser {
                tokenizer: MaybeOwned::Borrowed(&mut *self.tokenizer),
                at_start_of: None,
                stop_before: closing_delimiter,
            };
            result = nested_parser.parse_entirely(parse);
        }
        consume_until_end_of_block(block_type, &mut *self.tokenizer);
        result
    }

    #[inline]
    pub fn parse_until_before<T>(&mut self, delimiters: Delimiters,
                                 parse: |&mut Parser| -> Result<T, ()>)
                                 -> Result <T, ()> {
        let delimiters = self.stop_before | delimiters;
        let result;
        // Introduce a new scope to limit duration of nested_parser’s borrow
        {
            let mut delimited_parser = Parser {
                tokenizer: MaybeOwned::Borrowed(&mut *self.tokenizer),
                at_start_of: self.at_start_of.take(),
                stop_before: delimiters,
            };
            result = delimited_parser.parse_entirely(parse);
        }
        // FIXME: have a special-purpose tokenizer method for this that does less work.
        loop {
            if delimiters.contains(Delimiters::from_byte(self.tokenizer.next_byte())) {
                break
            }
            if let Ok(token) = self.tokenizer.next() {
                if let Some(block_type) = BlockType::opening(&token) {
                    consume_until_end_of_block(block_type, &mut *self.tokenizer);
                }
            } else {
                break
            }
        }
        result
    }

    #[inline]
    pub fn parse_until_after<T>(&mut self, delimiters: Delimiters,
                                parse: |&mut Parser| -> Result<T, ()>)
                                -> Result <T, ()> {
        let result = self.parse_until_before(delimiters, parse);
        let next_byte = self.tokenizer.next_byte();
        if next_byte.is_some() && !self.stop_before.contains(Delimiters::from_byte(next_byte)) {
            debug_assert!(delimiters.contains(Delimiters::from_byte(next_byte)));
            self.tokenizer.advance(1);
        }
        result
    }

    #[inline]
    pub fn expect_ident(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Ident(value) => Ok(value),
            _ => Err(())
        }
    }

    /// Expect an *ident* token whose value is an ASCII-insensitive match for the given value.
    #[inline]
    pub fn expect_ident_matching<'a>(&mut self, expected_value: &str) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Ident(ref value) if value.eq_ignore_ascii_case(expected_value) => Ok(()),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_string(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::QuotedString(value) => Ok(value),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_ident_or_string(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Ident(value) => Ok(value),
            Token::QuotedString(value) => Ok(value),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_url(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Url(value) => Ok(value),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_url_or_string(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Url(value) => Ok(value),
            Token::QuotedString(value) => Ok(value),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_number(&mut self) -> Result<f64, ()> {
        match try!(self.next()) {
            Token::Number(NumericValue { value, .. }) => Ok(value),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_integer(&mut self) -> Result<i64, ()> {
        match try!(self.next()) {
            Token::Number(NumericValue { int_value, .. }) => int_value.ok_or(()),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_percentage(&mut self) -> Result<f64, ()> {
        match try!(self.next()) {
            Token::Percentage(PercentageValue { unit_value, .. }) => Ok(unit_value),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_colon(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Colon => Ok(()),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_semicolon(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Semicolon => Ok(()),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_comma(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Comma => Ok(()),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_delim(&mut self, expected_value: char) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Delim(value) if value == expected_value => Ok(()),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_curly_bracket_block(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::CurlyBracketBlock => Ok(()),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_function(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Function(name) => Ok(name),
            _ => Err(())
        }
    }
}

/// Return value indicates whether the end of the input was reached.
fn consume_until_end_of_block(block_type: BlockType, tokenizer: &mut Tokenizer) {
    // FIXME: have a special-purpose tokenizer method for this that does less work.
    while let Ok(ref token) = tokenizer.next() {
        if BlockType::closing(token) == Some(block_type) {
            return
        }
        if let Some(block_type) = BlockType::opening(token) {
            consume_until_end_of_block(block_type, tokenizer);
        }
    }
}
<commit_msg>Enable Parser::try’s return value to borrow the input (e.g. be a token)<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::ascii::AsciiExt;
use std::str::CowString;
use std::ops;
use tokenizer::{mod, Token, NumericValue, PercentageValue, Tokenizer, SourceLocation};

#[deriving(PartialEq, Eq, Show, Clone, Copy)]
pub struct SourcePosition {
    position: tokenizer::SourcePosition,
    at_start_of: Option<BlockType>,
}

/// Like std::borrow::Cow, except:
///
/// * The Owned variant is boxed
/// * The Borrowed variant contains a mutable reference.
enum MaybeOwned<'a, T: 'a> {
    Owned(Box<T>),
    Borrowed(&'a mut T),
}

impl<'a, T> ops::Deref<T> for MaybeOwned<'a, T> {
    fn deref<'a>(&'a self) -> &'a T {
        match *self {
            MaybeOwned::Owned(ref pointer) => &**pointer,
            MaybeOwned::Borrowed(ref pointer) => &**pointer,
        }
    }
}

impl<'a, T> ops::DerefMut<T> for MaybeOwned<'a, T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        match *self {
            MaybeOwned::Owned(ref mut pointer) => &mut **pointer,
            MaybeOwned::Borrowed(ref mut pointer) => &mut **pointer,
        }
    }
}

impl<'a, T> Clone for MaybeOwned<'a, T> where T: Clone {
    fn clone(&self) -> MaybeOwned<'a, T> {
        MaybeOwned::Owned(box() (**self).clone())
    }
}

#[deriving(Clone)]
pub struct Parser<'i: 't, 't> {
    tokenizer: MaybeOwned<'t, Tokenizer<'i>>,
    /// If `Some(_)`, .parse_nested_block() can be called.
    at_start_of: Option<BlockType>,
    /// For parsers from `parse_until` or `parse_nested_block`
    stop_before: Delimiters,
}

#[deriving(Copy, Clone, PartialEq, Eq, Show)]
enum BlockType {
    Parenthesis,
    SquareBracket,
    CurlyBracket,
}

impl BlockType {
    fn opening(token: &Token) -> Option<BlockType> {
        match *token {
            Token::Function(_) |
            Token::ParenthesisBlock => Some(BlockType::Parenthesis),
            Token::SquareBracketBlock => Some(BlockType::SquareBracket),
            Token::CurlyBracketBlock => Some(BlockType::CurlyBracket),
            _ => None
        }
    }

    fn closing(token: &Token) -> Option<BlockType> {
        match *token {
            Token::CloseParenthesis => Some(BlockType::Parenthesis),
            Token::CloseSquareBracket => Some(BlockType::SquareBracket),
            Token::CloseCurlyBracket => Some(BlockType::CurlyBracket),
            _ => None
        }
    }
}

#[deriving(Copy, Clone, PartialEq, Eq, Show)]
pub struct Delimiters {
    bits: u8,
}

#[allow(non_upper_case_globals, non_snake_case)]
pub mod Delimiter {
    use super::Delimiters;

    pub const None: Delimiters = Delimiters { bits: 0 };
    /// `{`
    pub const CurlyBracketBlock: Delimiters = Delimiters { bits: 1 << 1 };
    /// `;`
    pub const Semicolon: Delimiters = Delimiters { bits: 1 << 2 };
    /// `!`
    pub const Bang: Delimiters = Delimiters { bits: 1 << 3 };
    /// `,`
    pub const Comma: Delimiters = Delimiters { bits: 1 << 4 };
}

#[allow(non_upper_case_globals, non_snake_case)]
mod ClosingDelimiter {
    use super::Delimiters;

    pub const CloseCurlyBracket: Delimiters = Delimiters { bits: 1 << 5 };
    pub const CloseSquareBracket: Delimiters = Delimiters { bits: 1 << 6 };
    pub const CloseParenthesis: Delimiters = Delimiters { bits: 1 << 7 };
}

impl BitOr<Delimiters, Delimiters> for Delimiters {
    fn bitor(&self, other: &Delimiters) -> Delimiters {
        Delimiters { bits: self.bits | other.bits }
    }
}

impl Delimiters {
    fn contains(self, other: Delimiters) -> bool {
        (self.bits & other.bits) != 0
    }

    fn from_byte(byte: Option<u8>) -> Delimiters {
        match byte {
            Some(b';') => Delimiter::Semicolon,
            Some(b',') => Delimiter::Comma,
            Some(b'!') => Delimiter::Bang,
            Some(b'{') => Delimiter::CurlyBracketBlock,
            Some(b'}') => ClosingDelimiter::CloseCurlyBracket,
            Some(b']') => ClosingDelimiter::CloseSquareBracket,
            Some(b')') => ClosingDelimiter::CloseParenthesis,
            _ => Delimiter::None,
        }
    }
}

impl<'i, 't> Parser<'i, 't> {
    #[inline]
    pub fn new(input: &'i str) -> Parser<'i, 'i> {
        Parser {
            tokenizer: MaybeOwned::Owned(box Tokenizer::new(input)),
            at_start_of: None,
            stop_before: Delimiter::None,
        }
    }

    #[inline]
    pub fn is_exhausted(&mut self) -> bool {
        self.expect_exhausted().is_ok()
    }

    #[inline]
    pub fn expect_exhausted(&mut self) -> Result<(), ()> {
        let start_position = self.position();
        match self.next() {
            Err(()) => Ok(()),
            Ok(_) => {
                self.reset(start_position);
                Err(())
            }
        }
    }

    #[inline]
    pub fn position(&self) -> SourcePosition {
        SourcePosition {
            position: self.tokenizer.position(),
            at_start_of: self.at_start_of,
        }
    }

    #[inline]
    pub fn reset(&mut self, new_position: SourcePosition) {
        self.tokenizer.reset(new_position.position);
        self.at_start_of = new_position.at_start_of;
    }

    #[inline]
    pub fn try<T, E>(&mut self, thing: |&mut Parser<'i, 't>| -> Result<T, E>) -> Result<T, E> {
        let start_position = self.position();
        let result = thing(self);
        if result.is_err() {
            self.reset(start_position)
        }
        result
    }

    #[inline]
    pub fn slice_from(&self, start_position: SourcePosition) -> &'i str {
        self.tokenizer.slice_from(start_position.position)
    }

    #[inline]
    pub fn current_source_location(&self) -> SourceLocation {
        self.tokenizer.current_source_location()
    }

    #[inline]
    pub fn source_location(&self, target: SourcePosition) -> SourceLocation {
        self.tokenizer.source_location(target.position)
    }

    pub fn next(&mut self) -> Result<Token<'i>, ()> {
        loop {
            match self.next_including_whitespace() {
                Ok(Token::WhiteSpace) => {},
                result => return result
            }
        }
    }

    pub fn next_including_whitespace(&mut self) -> Result<Token<'i>, ()> {
        if let Some(block_type) = self.at_start_of.take() {
            consume_until_end_of_block(block_type, &mut *self.tokenizer);
        }
        if self.stop_before.contains(Delimiters::from_byte(self.tokenizer.next_byte())) {
            return Err(())
        }
        let token = try!(self.tokenizer.next());
        if let Some(block_type) = BlockType::opening(&token) {
            self.at_start_of = Some(block_type);
        }
        Ok(token)
    }

    // FIXME: Take an unboxed `FnOnce` closure.
    #[inline]
    pub fn parse_entirely<T>(&mut self, parse: |&mut Parser| -> Result<T, ()>)
                             -> Result<T, ()> {
        let result = parse(self);
        try!(self.expect_exhausted());
        result
    }

    #[inline]
    pub fn parse_comma_separated<T>(&mut self, parse_one: |&mut Parser| -> Result<T, ()>)
                                    -> Result<Vec<T>, ()> {
        let mut values = vec![];
        loop {
            values.push(try!(self.parse_until_before(Delimiter::Comma, |parser| parse_one(parser))));
            match self.next() {
                Err(()) => return Ok(values),
                Ok(Token::Comma) => continue,
                Ok(_) => unreachable!(),
            }
        }
    }

    #[inline]
    pub fn parse_nested_block<T>(&mut self, parse: |&mut Parser| -> Result<T, ()>)
                                 -> Result <T, ()> {
        let block_type = self.at_start_of.take().expect("\
            A nested parser can only be created when a Function, \
            ParenthesisBlock, SquareBracketBlock, or CurlyBracketBlock \
            token was just consumed.\
        ");
        let closing_delimiter = match block_type {
            BlockType::CurlyBracket => ClosingDelimiter::CloseCurlyBracket,
            BlockType::SquareBracket => ClosingDelimiter::CloseSquareBracket,
            BlockType::Parenthesis => ClosingDelimiter::CloseParenthesis,
        };
        let result;
        // Introduce a new scope to limit duration of nested_parser’s borrow
        {
            let mut nested_parser = Parser {
                tokenizer: MaybeOwned::Borrowed(&mut *self.tokenizer),
                at_start_of: None,
                stop_before: closing_delimiter,
            };
            result = nested_parser.parse_entirely(parse);
        }
        consume_until_end_of_block(block_type, &mut *self.tokenizer);
        result
    }

    #[inline]
    pub fn parse_until_before<T>(&mut self, delimiters: Delimiters,
                                 parse: |&mut Parser| -> Result<T, ()>)
                                 -> Result <T, ()> {
        let delimiters = self.stop_before | delimiters;
        let result;
        // Introduce a new scope to limit duration of nested_parser’s borrow
        {
            let mut delimited_parser = Parser {
                tokenizer: MaybeOwned::Borrowed(&mut *self.tokenizer),
                at_start_of: self.at_start_of.take(),
                stop_before: delimiters,
            };
            result = delimited_parser.parse_entirely(parse);
        }
        // FIXME: have a special-purpose tokenizer method for this that does less work.
        loop {
            if delimiters.contains(Delimiters::from_byte(self.tokenizer.next_byte())) {
                break
            }
            if let Ok(token) = self.tokenizer.next() {
                if let Some(block_type) = BlockType::opening(&token) {
                    consume_until_end_of_block(block_type, &mut *self.tokenizer);
                }
            } else {
                break
            }
        }
        result
    }

    #[inline]
    pub fn parse_until_after<T>(&mut self, delimiters: Delimiters,
                                parse: |&mut Parser| -> Result<T, ()>)
                                -> Result <T, ()> {
        let result = self.parse_until_before(delimiters, parse);
        let next_byte = self.tokenizer.next_byte();
        if next_byte.is_some() && !self.stop_before.contains(Delimiters::from_byte(next_byte)) {
            debug_assert!(delimiters.contains(Delimiters::from_byte(next_byte)));
            self.tokenizer.advance(1);
        }
        result
    }

    #[inline]
    pub fn expect_ident(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Ident(value) => Ok(value),
            _ => Err(())
        }
    }

    /// Expect an *ident* token whose value is an ASCII-insensitive match for the given value.
    #[inline]
    pub fn expect_ident_matching<'a>(&mut self, expected_value: &str) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Ident(ref value) if value.eq_ignore_ascii_case(expected_value) => Ok(()),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_string(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::QuotedString(value) => Ok(value),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_ident_or_string(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Ident(value) => Ok(value),
            Token::QuotedString(value) => Ok(value),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_url(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Url(value) => Ok(value),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_url_or_string(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Url(value) => Ok(value),
            Token::QuotedString(value) => Ok(value),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_number(&mut self) -> Result<f64, ()> {
        match try!(self.next()) {
            Token::Number(NumericValue { value, .. }) => Ok(value),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_integer(&mut self) -> Result<i64, ()> {
        match try!(self.next()) {
            Token::Number(NumericValue { int_value, .. }) => int_value.ok_or(()),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_percentage(&mut self) -> Result<f64, ()> {
        match try!(self.next()) {
            Token::Percentage(PercentageValue { unit_value, .. }) => Ok(unit_value),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_colon(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Colon => Ok(()),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_semicolon(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Semicolon => Ok(()),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_comma(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Comma => Ok(()),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_delim(&mut self, expected_value: char) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Delim(value) if value == expected_value => Ok(()),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_curly_bracket_block(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::CurlyBracketBlock => Ok(()),
            _ => Err(())
        }
    }

    #[inline]
    pub fn expect_function(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Function(name) => Ok(name),
            _ => Err(())
        }
    }
}

/// Return value indicates whether the end of the input was reached.
fn consume_until_end_of_block(block_type: BlockType, tokenizer: &mut Tokenizer) {
    // FIXME: have a special-purpose tokenizer method for this that does less work.
    while let Ok(ref token) = tokenizer.next() {
        if BlockType::closing(token) == Some(block_type) {
            return
        }
        if let Some(block_type) = BlockType::opening(token) {
            consume_until_end_of_block(block_type, tokenizer);
        }
    }
}
<|endoftext|>


<commit_before>use std::str::from_utf8;
use nom::IResult;

#[derive(Debug,PartialEq,Eq)]
pub struct PosixHeader<'a> {
    pub name:     & 'a str,
    pub mode:     & 'a str,
    pub uid:      & 'a str,
    pub gid:      & 'a str,
    pub size:     & 'a str,
    pub mtime:    & 'a str,
    pub chksum:   & 'a str,
    pub typeflag: char,
    pub linkname: & 'a str,
    pub ustar:    Option<UStarHeader<'a>>
}

#[derive(Debug,PartialEq,Eq)]
pub struct UStarHeader<'a> {
    pub magic:    & 'a str,
    pub version:  & 'a str,
    pub uname:    & 'a str,
    pub gname:    & 'a str,
    pub devmajor: & 'a str,
    pub devminor: & 'a str,
    pub prefix:   & 'a str,
}

#[derive(Debug,PartialEq,Eq)]
pub struct TarEntry<'a> {
    pub header:   PosixHeader<'a>,
    pub contents: & 'a str
}

pub fn parse_header(i: &[u8]) -> IResult<&[u8], PosixHeader> {
    chain!(i,
        name:     map_res!(take!(100), from_utf8) ~
        mode:     map_res!(take!(8),   from_utf8) ~
        uid:      map_res!(take!(8),   from_utf8) ~
        gid:      map_res!(take!(8),   from_utf8) ~
        size:     map_res!(take!(12),  from_utf8) ~
        mtime:    map_res!(take!(12),  from_utf8) ~
        chksum:   map_res!(take!(8),   from_utf8) ~
        typeflag: take!(1)                        ~
        linkname: map_res!(take!(100), from_utf8),
        /* TODO: ustar */
        ||{
            PosixHeader {
                name:     name,
                mode:     mode,
                uid:      uid,
                gid:      gid,
                size:     size,
                mtime:    mtime,
                chksum:   chksum,
                typeflag: typeflag[0] as char,
                linkname: linkname,
                ustar:    None
            }
        }
    )
}

pub fn parse_entry(i: &[u8]) -> IResult<&[u8], TarEntry> {
    chain!(i,
        header: parse_header,
        /* TODO: contents */
        ||{
            TarEntry {
                header: header,
                contents: ""
            }
        }
    )
}

pub fn parse_tar(i: &[u8]) -> IResult<&[u8], Vec<TarEntry>> {
    many0!(i, parse_entry)
}
<commit_msg>mark internal fn private<commit_after>use std::str::from_utf8;
use nom::IResult;

#[derive(Debug,PartialEq,Eq)]
pub struct PosixHeader<'a> {
    pub name:     & 'a str,
    pub mode:     & 'a str,
    pub uid:      & 'a str,
    pub gid:      & 'a str,
    pub size:     & 'a str,
    pub mtime:    & 'a str,
    pub chksum:   & 'a str,
    pub typeflag: char,
    pub linkname: & 'a str,
    pub ustar:    Option<UStarHeader<'a>>
}

#[derive(Debug,PartialEq,Eq)]
pub struct UStarHeader<'a> {
    pub magic:    & 'a str,
    pub version:  & 'a str,
    pub uname:    & 'a str,
    pub gname:    & 'a str,
    pub devmajor: & 'a str,
    pub devminor: & 'a str,
    pub prefix:   & 'a str,
}

#[derive(Debug,PartialEq,Eq)]
pub struct TarEntry<'a> {
    pub header:   PosixHeader<'a>,
    pub contents: & 'a str
}

fn parse_header(i: &[u8]) -> IResult<&[u8], PosixHeader> {
    chain!(i,
        name:     map_res!(take!(100), from_utf8) ~
        mode:     map_res!(take!(8),   from_utf8) ~
        uid:      map_res!(take!(8),   from_utf8) ~
        gid:      map_res!(take!(8),   from_utf8) ~
        size:     map_res!(take!(12),  from_utf8) ~
        mtime:    map_res!(take!(12),  from_utf8) ~
        chksum:   map_res!(take!(8),   from_utf8) ~
        typeflag: take!(1)                        ~
        linkname: map_res!(take!(100), from_utf8),
        /* TODO: ustar */
        ||{
            PosixHeader {
                name:     name,
                mode:     mode,
                uid:      uid,
                gid:      gid,
                size:     size,
                mtime:    mtime,
                chksum:   chksum,
                typeflag: typeflag[0] as char,
                linkname: linkname,
                ustar:    None
            }
        }
    )
}

fn parse_entry(i: &[u8]) -> IResult<&[u8], TarEntry> {
    chain!(i,
        header: parse_header,
        /* TODO: contents */
        ||{
            TarEntry {
                header: header,
                contents: ""
            }
        }
    )
}

pub fn parse_tar(i: &[u8]) -> IResult<&[u8], Vec<TarEntry>> {
    many0!(i, parse_entry)
}
<|endoftext|>


<commit_before>use super::models::{LanguageModel, WordVec};
use self::Token::*;
use super::mayberef::MaybeRef::{self, Val, Ref};
use std::fmt::{Display, Formatter, Error};

pub fn parse(expr: &str, model: &LanguageModel) -> Result<WordVec, String> {
    expression(&mut Tokens::from(expr.chars()), model).map(|w| w.take())
}

#[derive(PartialEq, Eq, Debug, Clone)]
enum Token {
    RParen,
    LParen,
    Plus,
    Minus,
    Word(String),
    Invalid(char),
}

impl Display for Token {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        let invalid;
        fmt.write_str(match *self {
            RParen => ")",
            LParen => "(",
            Plus => "+",
            Minus => "-",
            Word(ref w) => &*w,
            Invalid(w) => {
                invalid = w.to_string();
                &*invalid
            },
        })
    }
}

fn expression<'a, I>(tokens: &mut Tokens<I>, model: &'a LanguageModel)
    -> Result<MaybeRef<'a, WordVec>, String>
    where I: Iterator<Item = char>
{
    let token = try!(tokens.next().ok_or("An expression may not be empty"));
    match token {
        LParen => {
            let vec = try!(expression(tokens, model));
            let rparen = try!(tokens.next().ok_or("Unbalanced parentheses"));
            if rparen != RParen {
                return Err(format!("Expected ')', found '{}'", rparen))
            }
            rhs(vec, tokens, model)
        },
        Word(word) => {
            let vec = try!(model.get(&*word).ok_or_else(||
                format!("'{}' is not present in the language model", &word)
            ));
            println!("{:?}", vec);
            rhs(Ref(vec), tokens, model)
        },
        _ => Err(format!("An expression may not start with '{}'", token)),
    }
}

fn rhs<'a, I>(lhs: MaybeRef<'a, WordVec>, tokens: &mut Tokens<I>, model: &LanguageModel)
    -> Result<MaybeRef<'a, WordVec>, String>
    where I: Iterator<Item = char>
{
    match tokens.peek() {
        Some(&RParen) | None => return Ok(lhs),
        _ => {}
    }

    let token = tokens.next().unwrap();
    match token {
        Plus => Ok(Val(lhs.take() + &*try!(expression(tokens, model)))),
        Minus => Ok(Val(lhs.take() - &*try!(expression(tokens, model)))),
        Word(_) | LParen => Err(format!("'{}' found in invalid position", token)),
        Invalid(s) => Err(format!("'{}' could not be tokenized", s)),
        RParen => unreachable!(),
    }
}

struct Tokens<I> {
    iter: I,
    next_char: Option<Option<char>>,
    next_token: Option<Option<Token>>
}

impl<I> Tokens<I> where I: Iterator<Item = char> {
    fn from(iter: I) -> Tokens<I> {
        Tokens {
            iter: iter,
            next_char: None,
            next_token: None,
        }
    }

    fn get_next_token(&mut self) -> Option<Token> {
        while let Some(' ') = self.peek_char() {
            self.take();
        }

        match self.peek_char() {
            Some('a'...'z') => return Some(self.word()),
            // Some('0'..'9') | Some('.') => return Some(self.number()),
            None => return None,
            _ => {}
        }

        Some(match self.take().unwrap() {
            '+' => Plus,
            '-' => Minus,
            '(' => LParen,
            ')' => RParen,
            c => Invalid(c),
        })
    }

    fn peek(&mut self) -> Option<&Token> {
        if let Some(ref t) = self.next_token {
            return t.as_ref();
        }

        self.next_token = Some(self.get_next_token());
        return self.next_token.as_ref().unwrap().as_ref();
    }

    fn peek_char(&mut self) -> Option<char> {
        match self.next_char {
            Some(x) => x,
            None => {
                let next = self.iter.next();
                self.next_char = Some(next);
                next
            }
        }
    }

    fn take(&mut self) -> Option<char> {
        self.peek_char();
        self.next_char.take().unwrap()
    }

    fn word(&mut self) -> Token {
        let mut token = String::new();
        while let Some('a'...'z') = self.peek_char() {
            token.push(self.take().unwrap());
        }

        Word(token)
    }

}

impl<I> Iterator for Tokens<I> where I: Iterator<Item = char> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.peek();
        self.next_token.take().unwrap()
    }
}

mod test {
    use super::Tokens;
    use super::Token::*;

    #[test]
    fn single_character() {
        let c = Tokens::from("a".chars()).next().unwrap();
        assert_eq!(c, Word("a".to_string()));
    }

    #[test]
    fn single_token() {
        let s = Tokens::from("abc".chars()).next().unwrap();
        assert_eq!(s, Word("abc".to_string()));
    }

    #[test]
    fn two_tokens() {
        let s = Tokens::from("abc def".chars()).collect::<Vec<_>>();
        assert_eq!(s, vec![Word("abc".to_string()), Word("def".to_string())]);
    }

    #[test]
    fn plus_tokens() {
        let s = Tokens::from("   abc  +def".chars()).collect::<Vec<_>>();
        assert_eq!(s, vec![Word("abc".to_string()), Plus, Word("def".to_string())]);
    }

    #[test]
    fn bracket_tokens() {
        let s = Tokens::from(" ()  (abc  +)def".chars()).collect::<Vec<_>>();
        assert_eq!(s, vec![LParen, RParen, LParen, Word("abc".to_string()),
            Plus, RParen, Word("def".to_string())]);
    }

    #[test]
    fn test_associativity() {
        use super::parse;
        use super::super::models::{WordVec, LanguageModel, LanguageModelBuilder};

        let words = vec!("a".to_string(), "b".to_string(), "c".to_string());
        let mut builder = LanguageModelBuilder::new(1, words);

        {
            let mut acc = builder.new_file();
            let text = "x x a a b a c b x x";
            for word in text.split(' ') {
                acc.add_word(word.to_string());
            }
        }

        let model = builder.build();
        assert_eq!(parse("a - b + c", &model).unwrap(), parse("(a - b) + c", &model).unwrap());
    }
}<commit_msg>Remove errant println.<commit_after>use super::models::{LanguageModel, WordVec};
use self::Token::*;
use super::mayberef::MaybeRef::{self, Val, Ref};
use std::fmt::{Display, Formatter, Error};

pub fn parse(expr: &str, model: &LanguageModel) -> Result<WordVec, String> {
    expression(&mut Tokens::from(expr.chars()), model).map(|w| w.take())
}

#[derive(PartialEq, Eq, Debug, Clone)]
enum Token {
    RParen,
    LParen,
    Plus,
    Minus,
    Word(String),
    Invalid(char),
}

impl Display for Token {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        let invalid;
        fmt.write_str(match *self {
            RParen => ")",
            LParen => "(",
            Plus => "+",
            Minus => "-",
            Word(ref w) => &*w,
            Invalid(w) => {
                invalid = w.to_string();
                &*invalid
            },
        })
    }
}

fn expression<'a, I>(tokens: &mut Tokens<I>, model: &'a LanguageModel)
    -> Result<MaybeRef<'a, WordVec>, String>
    where I: Iterator<Item = char>
{
    let token = try!(tokens.next().ok_or("An expression may not be empty"));
    match token {
        LParen => {
            let vec = try!(expression(tokens, model));
            let rparen = try!(tokens.next().ok_or("Unbalanced parentheses"));
            if rparen != RParen {
                return Err(format!("Expected ')', found '{}'", rparen))
            }
            rhs(vec, tokens, model)
        },
        Word(word) => {
            let vec = try!(model.get(&*word).ok_or_else(||
                format!("'{}' is not present in the language model", &word)
            ));
            rhs(Ref(vec), tokens, model)
        },
        _ => Err(format!("An expression may not start with '{}'", token)),
    }
}

fn rhs<'a, I>(lhs: MaybeRef<'a, WordVec>, tokens: &mut Tokens<I>, model: &LanguageModel)
    -> Result<MaybeRef<'a, WordVec>, String>
    where I: Iterator<Item = char>
{
    match tokens.peek() {
        Some(&RParen) | None => return Ok(lhs),
        _ => {}
    }

    let token = tokens.next().unwrap();
    match token {
        Plus => Ok(Val(lhs.take() + &*try!(expression(tokens, model)))),
        Minus => Ok(Val(lhs.take() - &*try!(expression(tokens, model)))),
        Word(_) | LParen => Err(format!("'{}' found in invalid position", token)),
        Invalid(s) => Err(format!("'{}' could not be tokenized", s)),
        RParen => unreachable!(),
    }
}

struct Tokens<I> {
    iter: I,
    next_char: Option<Option<char>>,
    next_token: Option<Option<Token>>
}

impl<I> Tokens<I> where I: Iterator<Item = char> {
    fn from(iter: I) -> Tokens<I> {
        Tokens {
            iter: iter,
            next_char: None,
            next_token: None,
        }
    }

    fn get_next_token(&mut self) -> Option<Token> {
        while let Some(' ') = self.peek_char() {
            self.take();
        }

        match self.peek_char() {
            Some('a'...'z') => return Some(self.word()),
            // Some('0'..'9') | Some('.') => return Some(self.number()),
            None => return None,
            _ => {}
        }

        Some(match self.take().unwrap() {
            '+' => Plus,
            '-' => Minus,
            '(' => LParen,
            ')' => RParen,
            c => Invalid(c),
        })
    }

    fn peek(&mut self) -> Option<&Token> {
        if let Some(ref t) = self.next_token {
            return t.as_ref();
        }

        self.next_token = Some(self.get_next_token());
        return self.next_token.as_ref().unwrap().as_ref();
    }

    fn peek_char(&mut self) -> Option<char> {
        match self.next_char {
            Some(x) => x,
            None => {
                let next = self.iter.next();
                self.next_char = Some(next);
                next
            }
        }
    }

    fn take(&mut self) -> Option<char> {
        self.peek_char();
        self.next_char.take().unwrap()
    }

    fn word(&mut self) -> Token {
        let mut token = String::new();
        while let Some('a'...'z') = self.peek_char() {
            token.push(self.take().unwrap());
        }

        Word(token)
    }

}

impl<I> Iterator for Tokens<I> where I: Iterator<Item = char> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.peek();
        self.next_token.take().unwrap()
    }
}

mod test {
    use super::Tokens;
    use super::Token::*;

    #[test]
    fn single_character() {
        let c = Tokens::from("a".chars()).next().unwrap();
        assert_eq!(c, Word("a".to_string()));
    }

    #[test]
    fn single_token() {
        let s = Tokens::from("abc".chars()).next().unwrap();
        assert_eq!(s, Word("abc".to_string()));
    }

    #[test]
    fn two_tokens() {
        let s = Tokens::from("abc def".chars()).collect::<Vec<_>>();
        assert_eq!(s, vec![Word("abc".to_string()), Word("def".to_string())]);
    }

    #[test]
    fn plus_tokens() {
        let s = Tokens::from("   abc  +def".chars()).collect::<Vec<_>>();
        assert_eq!(s, vec![Word("abc".to_string()), Plus, Word("def".to_string())]);
    }

    #[test]
    fn bracket_tokens() {
        let s = Tokens::from(" ()  (abc  +)def".chars()).collect::<Vec<_>>();
        assert_eq!(s, vec![LParen, RParen, LParen, Word("abc".to_string()),
            Plus, RParen, Word("def".to_string())]);
    }

    #[test]
    fn test_associativity() {
        use super::parse;
        use super::super::models::{WordVec, LanguageModel, LanguageModelBuilder};

        let words = vec!("a".to_string(), "b".to_string(), "c".to_string());
        let mut builder = LanguageModelBuilder::new(1, words);

        {
            let mut acc = builder.new_file();
            let text = "x x a a b a c b x x";
            for word in text.split(' ') {
                acc.add_word(word.to_string());
            }
        }

        let model = builder.build();
        assert_eq!(parse("a - b + c", &model).unwrap(), parse("(a - b) + c", &model).unwrap());
    }
}<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{
    BufReader,
    BufRead,
};

use regex::{
    Regex,
    RegexBuilder,
};

use super::Error;
use super::Result;

use types::*;

pub enum State {
    Init,
    FeatureAndTags,
    Feature,
    FeatureWithBackground,
    FeatureWithDescription,
    FeatureWithLanguage,
    FeatureWithTags,
}

pub fn parse(filename: &str) -> Result<Feature> {
    let file = try!(File::open(filename));

    let mut feature = Feature {
        filename: filename.to_owned(),
        name: None,
        description: None,
        background: None,
        items: Vec::new(),
    };
    let mut state = State::Init;

    for line in BufReader::new(file).lines() {
        let line = try!(line);

        match state {
            State::Init => {
                lazy_static! {
                    static ref RE: Regex = try!(prepare_regex(&[FEATURE_RE, LANGUAGE_RE, TAGS_RE], true).compile());
                }

                match try!(parse_line(&line, &RE)) {
                    _ =>
                        unimplemented!()
                }
            }

            _ => {
                return Err(Error::from_str("unhandled state"));
            }
        }
    }

    Ok(feature)
}

// nay be used only once and we ignore it
static LANGUAGE_RE: &'static str = r"(Language:\s*(?P<language>\S+))";

static TAGS_RE: &'static str = r"(?P<tags>@\w+(\s+@\w+)*)";

static FEATURE_RE: &'static str = r"(Feature:\s*(?P<feature>.*))";
static BACKGROUND_RE: &'static str = r"(Background:\s*(?P<background>.*))";
static SCENARIO_RE: &'static str = r"(Scenario:\s*(?P<scenario>.*))";
static SCENARIO_OUTLINE_RE: &'static str = r"(Scenario Outline:\s*(?P<outline>.*))";
static GIVEN_STEP_RE: &'static str = r"(Given\s+(?P<given>.*))";
static WHEN_STEP_RE: &'static str = r"(When\s+(?P<when>.*))";
static THEN_STEP_RE: &'static str = r"(Then\s+(?P<then>.*))";
static AND_STEP_RE: &'static str = r"(And\s+(?P<and>.*))";
static BUT_STEP_RE: &'static str = r"(But\s+(?P<but>.*))";
static EXAMPLES_RE: &'static str = r"(Examples:\s*(?P<examples>.*))";

static TABLE_RE: &'static str = r"(?P<table>\|.*\|)";
static DOCSTRING_RE: &'static str = "(?P<docstring>\"\"\"|''')";

static OTHER_RE: &'static str = "(?P<other>[^#]*)";

static INDENT_RE: &'static str = r"(?P<indent>\s*)";
static COMMENT_RE: &'static str = r"\s*(#\s*(?P<comment>.*))?";

fn prepare_regex(bits: &[&str], detect_comment: bool) -> RegexBuilder {
    let actual_bits = &bits.join("|");
    let mut pattern: Vec<&str> = vec!("^",
                                      INDENT_RE,
                                      "(",
                                      &actual_bits,
                                      ")");
    if detect_comment {
        pattern.push(COMMENT_RE);
    }

    pattern.push("$");

    RegexBuilder::new(&pattern.join(r""))
                 .case_insensitive(true)
                 .ignore_whitespace(true)
}

enum LineKind {
    EmptyLine,
    Tags,
    Feature,
    Background,
    Scenario,
    ScenarioOutline,
    GivenStep,
    WhenStep,
    ThenStep,
    AndStep,
    ButStep,
    Examples,
    Table,
    DocString,
    Other,
}

struct Line {
    pub kind: LineKind,
    pub value: Option<String>,
    pub indent: usize,
    pub comment: Option<String>,
}

fn parse_line(line: &str, regex: &Regex) -> Result<Line> {
    let mut kind: Option<String> = None;
    let mut value: Option<String> = None;
    let mut indent: usize = 0;
    let mut comment: Option<String> = None;

    match regex.captures(line) {
        None => {
            return Err(Error::from_str(&format!("Can't parse: {}", line)));
        }

        Some(captures) => {
            for (name, actual_value) in captures.iter_named() {
                match name {
                    "indent" => {
                        indent = actual_value.map_or(0, |value| value.len());
                    }

                    "comment" => {
                        comment = actual_value.map(|value| value.to_owned());
                    }

                    _ => {
                        match actual_value {
                            None => {
                                kind = Some(name.to_owned());
                                value = actual_value.map(|value| value.to_owned());
                            }

                            Some(other) => {
                                return Err(Error::from_str(&format!("Double match: {} and {}", other, name)));
                            }
                        }
                    }
                }
            }
        }
    }

    match kind {
        None => {
            unimplemented!()
        }

        Some(kind) => {
            let kind = match kind.as_str() {
                "tags" =>
                    LineKind::Tags,

                "feature" =>
                    LineKind::Feature,

                "background" =>
                    LineKind::Background,

                "scenario" =>
                    LineKind::Scenario,

                "outline" =>
                    LineKind::ScenarioOutline,

                "given" =>
                    LineKind::GivenStep,

                "when" =>
                   LineKind::WhenStep,

                "then" =>
                    LineKind::ThenStep,

                "and" =>
                    LineKind::AndStep,

                "but" =>
                    LineKind::ButStep,

                "examples" =>
                    LineKind::Examples,

                "table" =>
                    LineKind::Table,

                "docstring" =>
                    LineKind::DocString,

                "other" =>
                    LineKind::Other,

                _ => {
                    return Err(Error::from_str(&format!("Unknown match: {}", kind)));
                }
            };

            Ok(Line{
                kind: kind,
                value: value,
                indent: indent,
                comment: comment
            })
        }
    }
}
<commit_msg>simplify usage of regex.captures<commit_after>use std::fs::File;
use std::io::{
    BufReader,
    BufRead,
};

use regex::{
    Regex,
    RegexBuilder,
};

use super::Error;
use super::Result;

use types::*;

pub enum State {
    Init,
    FeatureAndTags,
    Feature,
    FeatureWithBackground,
    FeatureWithDescription,
    FeatureWithLanguage,
    FeatureWithTags,
}

pub fn parse(filename: &str) -> Result<Feature> {
    let file = try!(File::open(filename));

    let mut feature = Feature {
        filename: filename.to_owned(),
        name: None,
        description: None,
        background: None,
        items: Vec::new(),
    };
    let mut state = State::Init;

    for line in BufReader::new(file).lines() {
        let line = try!(line);

        match state {
            State::Init => {
                lazy_static! {
                    static ref RE: Regex = prepare_regex(&[FEATURE_RE, LANGUAGE_RE, TAGS_RE], true);
                }

                match try!(parse_line(&line, &RE)) {
                    _ =>
                        unimplemented!()
                }
            }

            _ => {
                return Err(Error::from_str("unhandled state"));
            }
        }
    }

    Ok(feature)
}

// nay be used only once and we ignore it
static LANGUAGE_RE: &'static str = r"(Language:\s*(?P<language>\S+))";

static TAGS_RE: &'static str = r"(?P<tags>@\w+(\s+@\w+)*)";

static FEATURE_RE: &'static str = r"(Feature:\s*(?P<feature>.*))";
static BACKGROUND_RE: &'static str = r"(Background:\s*(?P<background>.*))";
static SCENARIO_RE: &'static str = r"(Scenario:\s*(?P<scenario>.*))";
static SCENARIO_OUTLINE_RE: &'static str = r"(Scenario Outline:\s*(?P<outline>.*))";
static GIVEN_STEP_RE: &'static str = r"(Given\s+(?P<given>.*))";
static WHEN_STEP_RE: &'static str = r"(When\s+(?P<when>.*))";
static THEN_STEP_RE: &'static str = r"(Then\s+(?P<then>.*))";
static AND_STEP_RE: &'static str = r"(And\s+(?P<and>.*))";
static BUT_STEP_RE: &'static str = r"(But\s+(?P<but>.*))";
static EXAMPLES_RE: &'static str = r"(Examples:\s*(?P<examples>.*))";

static TABLE_RE: &'static str = r"(?P<table>\|.*\|)";
static DOCSTRING_RE: &'static str = "(?P<docstring>\"\"\"|''')";

static OTHER_RE: &'static str = "(?P<other>[^#]*)";

static INDENT_RE: &'static str = r"(?P<indent>\s*)";
static COMMENT_RE: &'static str = r"\s*(#\s*(?P<comment>.*))?";

fn prepare_regex(bits: &[&str], detect_comment: bool) -> Regex {
    let actual_bits = &bits.join("|");
    let mut pattern: Vec<&str> = vec!("^",
                                      INDENT_RE,
                                      "(",
                                      &actual_bits,
                                      ")");
    if detect_comment {
        pattern.push(COMMENT_RE);
    }

    pattern.push("$");

    RegexBuilder::new(&pattern.join(r""))
                 .case_insensitive(true)
                 .ignore_whitespace(true)
                 .compile()
                 .unwrap()
}

enum LineKind {
    EmptyLine,
    Tags,
    Feature,
    Background,
    Scenario,
    ScenarioOutline,
    GivenStep,
    WhenStep,
    ThenStep,
    AndStep,
    ButStep,
    Examples,
    Table,
    DocString,
    Other,
}

struct Line {
    pub kind: LineKind,
    pub value: Option<String>,
    pub indent: usize,
    pub comment: Option<String>,
}

fn parse_line(line: &str, regex: &Regex) -> Result<Line> {
    let mut kind: Option<String> = None;
    let mut value: Option<String> = None;
    let mut indent: usize = 0;
    let mut comment: Option<String> = None;

    let captures = try!(regex.captures(line)
                             .ok_or_else(|| Error::from_str(&format!("Can't parse: {}", line))));

    for (name, actual_value) in captures.iter_named() {
        match name {
            "indent" => {
                indent = actual_value.map_or(0, |value| value.len());
            }

            "comment" => {
                comment = actual_value.map(|value| value.to_owned());
            }

            _ => {
                match actual_value {
                    None => {
                        kind = Some(name.to_owned());
                        value = actual_value.map(|value| value.to_owned());
                    }

                    Some(other) => {
                        return Err(Error::from_str(&format!("Double match: {} and {}", other, name)));
                    }
                }
            }
        }
    }

    match kind {
        None => {
            unimplemented!()
        }

        Some(kind) => {
            let kind = match kind.as_str() {
                "tags" =>
                    LineKind::Tags,

                "feature" =>
                    LineKind::Feature,

                "background" =>
                    LineKind::Background,

                "scenario" =>
                    LineKind::Scenario,

                "outline" =>
                    LineKind::ScenarioOutline,

                "given" =>
                    LineKind::GivenStep,

                "when" =>
                   LineKind::WhenStep,

                "then" =>
                    LineKind::ThenStep,

                "and" =>
                    LineKind::AndStep,

                "but" =>
                    LineKind::ButStep,

                "examples" =>
                    LineKind::Examples,

                "table" =>
                    LineKind::Table,

                "docstring" =>
                    LineKind::DocString,

                "other" =>
                    LineKind::Other,

                _ => {
                    return Err(Error::from_str(&format!("Unknown match: {}", kind)));
                }
            };

            Ok(Line{
                kind: kind,
                value: value,
                indent: indent,
                comment: comment
            })
        }
    }
}
<|endoftext|>


<commit_before>//! The parser is based on the following grammar
//!
//! Expression ==> "let" Name "=" Equation
//!             |  Equation
//!
//! Equation   ==> Product { "+" Product }
//!             |  Product { "-" Product }
//!
//! Product    ==> Factor { "*" Factor }
//!             |  Factor { "/" Factor }
//!
//! Factor     ==> "-" Factor
//!             |  Exponent { "^" Factor }
//!
//! Exponent   ==> Number { "!" }
//!
//! Number     ==> Function "(" Equation ")"
//!             |  Constant
//!             |  Name
//!             |  "ans"
//!             |  "(" Equation ")"
//!             |  "|" Equation "|"
//!             |  NumLiteral
//!
//! Function   ==> "sin" | "cos" | "tan" | "asin" | "acos" | "atan" | "sqrt" | "abs" | "exp"
//!             |  "ln" | "log"
//!
//! Constant   ==> "pi" | "π" | "e" | "phi" | "ϕ" | "ans"

use std::vec::IntoIter;
use std::iter::Peekable;
use errors::{CalcrResult, CalcrError};
use ast::Ast;
use ast::AstVal;
use ast::AstBranch::*;
use ast::FuncKind::*;
use ast::ConstKind::*;
use ast::OpKind::*;
use token::Token;
use token::TokVal;
use token::TokVal::*;
use token::KeywordKind::*;

pub fn parse_tokens(tokens: Vec<Token>) -> CalcrResult<Ast> {
    let end_pos = tokens.last().and_then(|tok| Some(tok.span.1)).unwrap_or(0);
    let mut parser = Parser {
        iter: tokens.into_iter().peekable(),
        paren_level: 0,
        abs_level: 0,
        end_pos: end_pos,
    };
    parser.parse_expression()
}

fn get_builtin_name(name: &String) -> Option<AstVal> {
    match name.as_ref() {
        "ans" => Some(AstVal::LastResult),
        "pi" | "π" => Some(AstVal::Const(Pi)),
        "e" => Some(AstVal::Const(E)),
        "phi" | "ϕ" => Some(AstVal::Const(Phi)),
        "cos" => Some(AstVal::Func(Cos)),
        "sin" => Some(AstVal::Func(Sin)),
        "tan" => Some(AstVal::Func(Tan)),
        "asin" => Some(AstVal::Func(Asin)),
        "acos" => Some(AstVal::Func(Acos)),
        "atan" => Some(AstVal::Func(Atan)),
        "sqrt" | "√" => Some(AstVal::Func(Sqrt)),
        "abs" => Some(AstVal::Func(Abs)),
        "exp" => Some(AstVal::Func(Exp)),
        "ln" => Some(AstVal::Func(Ln)),
        "log" => Some(AstVal::Func(Log)),
        _ => None
    }
}

pub struct Parser {
    iter: Peekable<IntoIter<Token>>,
    paren_level: u32,
    abs_level: u32,
    end_pos: usize,
}

impl Parser {
    fn parse_expression(&mut self) -> CalcrResult<Ast> {
        if self.next_tok_is(Keyword(Let)) {
            self.consume_tok();
            if !self.toks_empty() {
                let Token { val: tok_val, span: tok_span } = self.consume_tok();
                match tok_val {
                    Name(ref name) if get_builtin_name(name).is_none() => {
                        if self.next_tok_is(Op(Assign)) {
                            let assign_tok = self.consume_tok();
                            let eq = try!(self.parse_equation());
                            let name_ast = Ast {
                                val: AstVal::Name(name.clone()),
                                span: tok_span,
                                branches: Leaf,
                            };
                            Ok(Ast {
                                val: AstVal::Op(Assign),
                                span: assign_tok.span,
                                branches: Binary(Box::new(name_ast), Box::new(eq)),
                            })
                        } else {
                            Err(CalcrError {
                                desc: "Expected assignment operator '=' after name".to_string(),
                                span: Some(tok_span),
                            })
                        }
                    },
                    Name(ref name) => Err(CalcrError {
                        desc: format!("Cannot assign to builtin name '{}'", name),
                        span: Some(tok_span),
                    }),
                    _ => Err(CalcrError {
                        desc: "Expected name to assign to".to_string(),
                        span: Some(tok_span),
                    }),
                }
            } else {
                Err(CalcrError {
                    desc: "Expected name to assign to".to_string(),
                    span: Some((self.end_pos, self.end_pos)),
                })
            }

        } else {
            self.parse_equation()
        }
    }

    fn parse_equation(&mut self) -> CalcrResult<Ast> {
        let mut lhs = try!(self.parse_product());
        while self.next_tok_matches(|val| *val == Op(Plus) || *val == Op(Minus)) {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            let rhs = try!(self.parse_product());
            lhs = Ast {
                val: AstVal::Op(tok_val.op().unwrap()),
                span: tok_span,
                branches: Binary(Box::new(lhs), Box::new(rhs)),
            }
        }
        if self.next_tok_is(ParenClose) && self.paren_level < 1 {
            let Token { val: _, span: tok_span } = self.consume_tok();
            Err(CalcrError {
                desc: format!("Missing opening parentheses"),
                span: Some(tok_span),
            })
        } else if self.next_tok_is(AbsDelim) && self.abs_level < 1 {
            let Token { val: _, span: tok_span } = self.consume_tok();
            Err(CalcrError {
                desc: format!("Missing opening abs delimiter"),
                span: Some(tok_span),
            })
        } else {
            Ok(lhs)
        }
    }

    fn parse_product(&mut self) -> CalcrResult<Ast> {
        let mut lhs = try!(self.parse_factor());
        while self.next_tok_matches(|val| *val == Op(Mult) || *val == Op(Div)) {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            let rhs = try!(self.parse_factor());
            lhs = Ast {
                val: AstVal::Op(tok_val.op().unwrap()),
                span: tok_span,
                branches: Binary(Box::new(lhs), Box::new(rhs)),
            };
        }
        Ok(lhs)
    }

    fn parse_factor(&mut self) -> CalcrResult<Ast> {
        // when we lex we only store `Minus`s since we do not have any context there,
        // however we know if we see a `Minus` now, then it is a `Neg`.
        if self.next_tok_is(Op(Minus)) {
            let tok_span = self.consume_tok().span;
            let rhs = try!(self.parse_factor());
            Ok(Ast {
                val: AstVal::Op(Neg),
                span: tok_span,
                branches: Unary(Box::new(rhs)),
            })
        } else {
            let lhs = try!(self.parse_exponent());
            if self.next_tok_is(Op(Pow)) {
                let tok_span = self.consume_tok().span;
                let rhs = try!(self.parse_factor());
                Ok(Ast {
                    val: AstVal::Op(Pow),
                    span: tok_span,
                    branches: Binary(Box::new(lhs), Box::new(rhs)),
                })
            } else {
                Ok(lhs)
            }
        }
    }

    fn parse_exponent(&mut self) -> CalcrResult<Ast> {
        let mut out = try!(self.parse_number());

        while self.next_tok_is(Op(Fact)) {
            let tok_span = self.consume_tok().span;
            out = Ast {
                val: AstVal::Op(Fact),
                span: tok_span,
                branches: Unary(Box::new(out)),
            };
        }
        Ok(out)
    }

    fn parse_number(&mut self) -> CalcrResult<Ast> {
        if self.toks_empty() {
            Err(CalcrError {
                desc: format!("Expected number or constant"),
                span: Some((self.end_pos, self.end_pos)),
            })
        } else {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            match tok_val {
                Name(ref name) => {
                    let val = match get_builtin_name(name) {
                        Some(val) => val,
                        None => AstVal::Name(name.clone()),
                    };
                    if let AstVal::Func(_) = val {
                        // it's a function so we need to grab its argument
                        if self.next_tok_is(ParenOpen) {
                            // since we know the next token is an open paren, we use
                            // this function to get its AST
                            let arg = try!(self.parse_equation());
                            Ok(Ast {
                                val: val,
                                span: tok_span,
                                branches: Unary(Box::new(arg)),
                            })
                        } else {
                            Err(CalcrError {
                                desc: "Missing opening parentheses after function".to_string(),
                                span: Some(tok_span),
                            })
                        }
                    } else {
                        Ok(Ast {
                            val: val,
                            span: tok_span,
                            branches: Leaf,
                        })
                    }
                },
                ParenOpen => {
                    self.paren_level += 1;
                    let eq = try!(self.parse_equation());
                    if !self.next_tok_is(ParenClose) {
                        Err(CalcrError {
                            desc: "Missing closing parentheses".to_string(),
                            span: Some(tok_span),
                        })
                    } else {
                        self.paren_level -= 1;
                        let close_paren_span = self.consume_tok().span;
                        Ok(Ast {
                            val: AstVal::Paren,
                            span: (tok_span.0, close_paren_span.1),
                            branches: Unary(Box::new(eq)),
                        })
                    }
                },
                AbsDelim => {
                    self.abs_level += 1;
                    let eq = try!(self.parse_equation());
                    if !self.next_tok_is(AbsDelim) {
                        Err(CalcrError {
                            desc: "Missing closing abs delimiter".to_string(),
                            span: Some(tok_span),
                        })
                    } else {
                        self.abs_level -= 1;
                        let close_delim_span = self.consume_tok().span;
                        Ok(Ast {
                            val: AstVal::Func(Abs),
                            span: (tok_span.0, close_delim_span.1),
                            branches: Unary(Box::new(eq)),
                        })
                    }
                },
                Num(num) => {
                    Ok(Ast {
                        val: AstVal::Num(num),
                        span: tok_span,
                        branches: Leaf,
                    })
                },
                _ => Err(CalcrError {
                    desc: format!("Expected number or constant"),
                    span: Some(tok_span),
                }),
            }
        }
    }

    /// Peeks at the next token and check whether its values is equal to `val`
    fn next_tok_is(&mut self, val: TokVal) -> bool {
        self.next_tok_matches(|v| *v == val)
    }

    /// Peeks at the next token and checks whether its value makes `pred` true
    fn next_tok_matches<F>(&mut self, pred: F) -> bool where F: FnOnce(&TokVal) -> bool {
        self.iter.peek().map_or(false, |ref tok| pred(&tok.val))
    }

    /// Checks if we have run out of `Token`s to parse
    fn toks_empty(&mut self) -> bool {
        self.iter.peek().is_none()
    }

    /// Consumes a `Token` - thereby advanding `pos` - and returns it
    ///
    /// # Panics
    /// This function panics if there are no more `Token`s to consume
    fn consume_tok(&mut self) -> Token {
        let tok = self.iter.next();
        tok.unwrap()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::Token;
    use token::TokVal;
    use ast::Ast;
    use ast::AstVal;
    use ast::AstBranch;
    use ast::ConstKind::*;

    #[test]
    fn single_num() {
        let toks = vec!(Token { val: TokVal::Num(2.0), span: (0, 1) });
        let ast = parse_equation(toks);
        assert_eq!(ast, Ok(Ast { val: AstVal::Num(2.0), span: (0, 1), branches: AstBranch::Leaf }));
    }

    #[test]
    fn constants() {
        assert_eq!(parse_equation(vec!(Token { val: TokVal::Name("pi".to_string()), span: (0, 2)})),
                   Ok(Ast { val: AstVal::Const(Pi), span: (0, 2), branches: AstBranch::Leaf }));

        assert_eq!(parse_equation(vec!(Token { val: TokVal::Name("π".to_string()), span: (0, 1)})),
                   Ok(Ast { val: AstVal::Const(Pi), span: (0, 1), branches: AstBranch::Leaf }));

        assert_eq!(parse_equation(vec!(Token { val: TokVal::Name("e".to_string()), span: (0, 1)})),
                   Ok(Ast { val: AstVal::Const(E), span: (0, 1), branches: AstBranch::Leaf }));

        assert_eq!(parse_equation(vec!(Token { val: TokVal::Name("phi".to_string()), span: (0, 3)})),
                   Ok(Ast { val: AstVal::Const(Phi), span: (0, 3), branches: AstBranch::Leaf }));

        assert_eq!(parse_equation(vec!(Token { val: TokVal::Name("ϕ".to_string()), span: (0, 1)})),
                   Ok(Ast { val: AstVal::Const(Phi), span: (0, 1), branches: AstBranch::Leaf }));
    }

    #[test]
    fn empty() {
        let toks = vec!();
        let err = parse_equation(toks);
        assert!(err.is_err());
    }
}<commit_msg>Fix parser tests to use the new function<commit_after>//! The parser is based on the following grammar
//!
//! Expression ==> "let" Name "=" Equation
//!             |  Equation
//!
//! Equation   ==> Product { "+" Product }
//!             |  Product { "-" Product }
//!
//! Product    ==> Factor { "*" Factor }
//!             |  Factor { "/" Factor }
//!
//! Factor     ==> "-" Factor
//!             |  Exponent { "^" Factor }
//!
//! Exponent   ==> Number { "!" }
//!
//! Number     ==> Function "(" Equation ")"
//!             |  Constant
//!             |  Name
//!             |  "ans"
//!             |  "(" Equation ")"
//!             |  "|" Equation "|"
//!             |  NumLiteral
//!
//! Function   ==> "sin" | "cos" | "tan" | "asin" | "acos" | "atan" | "sqrt" | "abs" | "exp"
//!             |  "ln" | "log"
//!
//! Constant   ==> "pi" | "π" | "e" | "phi" | "ϕ" | "ans"

use std::vec::IntoIter;
use std::iter::Peekable;
use errors::{CalcrResult, CalcrError};
use ast::Ast;
use ast::AstVal;
use ast::AstBranch::*;
use ast::FuncKind::*;
use ast::ConstKind::*;
use ast::OpKind::*;
use token::Token;
use token::TokVal;
use token::TokVal::*;
use token::KeywordKind::*;

pub fn parse_tokens(tokens: Vec<Token>) -> CalcrResult<Ast> {
    let end_pos = tokens.last().and_then(|tok| Some(tok.span.1)).unwrap_or(0);
    let mut parser = Parser {
        iter: tokens.into_iter().peekable(),
        paren_level: 0,
        abs_level: 0,
        end_pos: end_pos,
    };
    parser.parse_expression()
}

fn get_builtin_name(name: &String) -> Option<AstVal> {
    match name.as_ref() {
        "ans" => Some(AstVal::LastResult),
        "pi" | "π" => Some(AstVal::Const(Pi)),
        "e" => Some(AstVal::Const(E)),
        "phi" | "ϕ" => Some(AstVal::Const(Phi)),
        "cos" => Some(AstVal::Func(Cos)),
        "sin" => Some(AstVal::Func(Sin)),
        "tan" => Some(AstVal::Func(Tan)),
        "asin" => Some(AstVal::Func(Asin)),
        "acos" => Some(AstVal::Func(Acos)),
        "atan" => Some(AstVal::Func(Atan)),
        "sqrt" | "√" => Some(AstVal::Func(Sqrt)),
        "abs" => Some(AstVal::Func(Abs)),
        "exp" => Some(AstVal::Func(Exp)),
        "ln" => Some(AstVal::Func(Ln)),
        "log" => Some(AstVal::Func(Log)),
        _ => None
    }
}

pub struct Parser {
    iter: Peekable<IntoIter<Token>>,
    paren_level: u32,
    abs_level: u32,
    end_pos: usize,
}

impl Parser {
    fn parse_expression(&mut self) -> CalcrResult<Ast> {
        if self.next_tok_is(Keyword(Let)) {
            self.consume_tok();
            if !self.toks_empty() {
                let Token { val: tok_val, span: tok_span } = self.consume_tok();
                match tok_val {
                    Name(ref name) if get_builtin_name(name).is_none() => {
                        if self.next_tok_is(Op(Assign)) {
                            let assign_tok = self.consume_tok();
                            let eq = try!(self.parse_equation());
                            let name_ast = Ast {
                                val: AstVal::Name(name.clone()),
                                span: tok_span,
                                branches: Leaf,
                            };
                            Ok(Ast {
                                val: AstVal::Op(Assign),
                                span: assign_tok.span,
                                branches: Binary(Box::new(name_ast), Box::new(eq)),
                            })
                        } else {
                            Err(CalcrError {
                                desc: "Expected assignment operator '=' after name".to_string(),
                                span: Some(tok_span),
                            })
                        }
                    },
                    Name(ref name) => Err(CalcrError {
                        desc: format!("Cannot assign to builtin name '{}'", name),
                        span: Some(tok_span),
                    }),
                    _ => Err(CalcrError {
                        desc: "Expected name to assign to".to_string(),
                        span: Some(tok_span),
                    }),
                }
            } else {
                Err(CalcrError {
                    desc: "Expected name to assign to".to_string(),
                    span: Some((self.end_pos, self.end_pos)),
                })
            }

        } else {
            self.parse_equation()
        }
    }

    fn parse_equation(&mut self) -> CalcrResult<Ast> {
        let mut lhs = try!(self.parse_product());
        while self.next_tok_matches(|val| *val == Op(Plus) || *val == Op(Minus)) {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            let rhs = try!(self.parse_product());
            lhs = Ast {
                val: AstVal::Op(tok_val.op().unwrap()),
                span: tok_span,
                branches: Binary(Box::new(lhs), Box::new(rhs)),
            }
        }
        if self.next_tok_is(ParenClose) && self.paren_level < 1 {
            let Token { val: _, span: tok_span } = self.consume_tok();
            Err(CalcrError {
                desc: format!("Missing opening parentheses"),
                span: Some(tok_span),
            })
        } else if self.next_tok_is(AbsDelim) && self.abs_level < 1 {
            let Token { val: _, span: tok_span } = self.consume_tok();
            Err(CalcrError {
                desc: format!("Missing opening abs delimiter"),
                span: Some(tok_span),
            })
        } else {
            Ok(lhs)
        }
    }

    fn parse_product(&mut self) -> CalcrResult<Ast> {
        let mut lhs = try!(self.parse_factor());
        while self.next_tok_matches(|val| *val == Op(Mult) || *val == Op(Div)) {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            let rhs = try!(self.parse_factor());
            lhs = Ast {
                val: AstVal::Op(tok_val.op().unwrap()),
                span: tok_span,
                branches: Binary(Box::new(lhs), Box::new(rhs)),
            };
        }
        Ok(lhs)
    }

    fn parse_factor(&mut self) -> CalcrResult<Ast> {
        // when we lex we only store `Minus`s since we do not have any context there,
        // however we know if we see a `Minus` now, then it is a `Neg`.
        if self.next_tok_is(Op(Minus)) {
            let tok_span = self.consume_tok().span;
            let rhs = try!(self.parse_factor());
            Ok(Ast {
                val: AstVal::Op(Neg),
                span: tok_span,
                branches: Unary(Box::new(rhs)),
            })
        } else {
            let lhs = try!(self.parse_exponent());
            if self.next_tok_is(Op(Pow)) {
                let tok_span = self.consume_tok().span;
                let rhs = try!(self.parse_factor());
                Ok(Ast {
                    val: AstVal::Op(Pow),
                    span: tok_span,
                    branches: Binary(Box::new(lhs), Box::new(rhs)),
                })
            } else {
                Ok(lhs)
            }
        }
    }

    fn parse_exponent(&mut self) -> CalcrResult<Ast> {
        let mut out = try!(self.parse_number());

        while self.next_tok_is(Op(Fact)) {
            let tok_span = self.consume_tok().span;
            out = Ast {
                val: AstVal::Op(Fact),
                span: tok_span,
                branches: Unary(Box::new(out)),
            };
        }
        Ok(out)
    }

    fn parse_number(&mut self) -> CalcrResult<Ast> {
        if self.toks_empty() {
            Err(CalcrError {
                desc: format!("Expected number or constant"),
                span: Some((self.end_pos, self.end_pos)),
            })
        } else {
            let Token { val: tok_val, span: tok_span } = self.consume_tok();
            match tok_val {
                Name(ref name) => {
                    let val = match get_builtin_name(name) {
                        Some(val) => val,
                        None => AstVal::Name(name.clone()),
                    };
                    if let AstVal::Func(_) = val {
                        // it's a function so we need to grab its argument
                        if self.next_tok_is(ParenOpen) {
                            // since we know the next token is an open paren, we use
                            // this function to get its AST
                            let arg = try!(self.parse_equation());
                            Ok(Ast {
                                val: val,
                                span: tok_span,
                                branches: Unary(Box::new(arg)),
                            })
                        } else {
                            Err(CalcrError {
                                desc: "Missing opening parentheses after function".to_string(),
                                span: Some(tok_span),
                            })
                        }
                    } else {
                        Ok(Ast {
                            val: val,
                            span: tok_span,
                            branches: Leaf,
                        })
                    }
                },
                ParenOpen => {
                    self.paren_level += 1;
                    let eq = try!(self.parse_equation());
                    if !self.next_tok_is(ParenClose) {
                        Err(CalcrError {
                            desc: "Missing closing parentheses".to_string(),
                            span: Some(tok_span),
                        })
                    } else {
                        self.paren_level -= 1;
                        let close_paren_span = self.consume_tok().span;
                        Ok(Ast {
                            val: AstVal::Paren,
                            span: (tok_span.0, close_paren_span.1),
                            branches: Unary(Box::new(eq)),
                        })
                    }
                },
                AbsDelim => {
                    self.abs_level += 1;
                    let eq = try!(self.parse_equation());
                    if !self.next_tok_is(AbsDelim) {
                        Err(CalcrError {
                            desc: "Missing closing abs delimiter".to_string(),
                            span: Some(tok_span),
                        })
                    } else {
                        self.abs_level -= 1;
                        let close_delim_span = self.consume_tok().span;
                        Ok(Ast {
                            val: AstVal::Func(Abs),
                            span: (tok_span.0, close_delim_span.1),
                            branches: Unary(Box::new(eq)),
                        })
                    }
                },
                Num(num) => {
                    Ok(Ast {
                        val: AstVal::Num(num),
                        span: tok_span,
                        branches: Leaf,
                    })
                },
                _ => Err(CalcrError {
                    desc: format!("Expected number or constant"),
                    span: Some(tok_span),
                }),
            }
        }
    }

    /// Peeks at the next token and check whether its values is equal to `val`
    fn next_tok_is(&mut self, val: TokVal) -> bool {
        self.next_tok_matches(|v| *v == val)
    }

    /// Peeks at the next token and checks whether its value makes `pred` true
    fn next_tok_matches<F>(&mut self, pred: F) -> bool where F: FnOnce(&TokVal) -> bool {
        self.iter.peek().map_or(false, |ref tok| pred(&tok.val))
    }

    /// Checks if we have run out of `Token`s to parse
    fn toks_empty(&mut self) -> bool {
        self.iter.peek().is_none()
    }

    /// Consumes a `Token` - thereby advanding `pos` - and returns it
    ///
    /// # Panics
    /// This function panics if there are no more `Token`s to consume
    fn consume_tok(&mut self) -> Token {
        let tok = self.iter.next();
        tok.unwrap()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::Token;
    use token::TokVal;
    use ast::Ast;
    use ast::AstVal;
    use ast::AstBranch;
    use ast::ConstKind::*;

    #[test]
    fn single_num() {
        let toks = vec!(Token { val: TokVal::Num(2.0), span: (0, 1) });
        let ast = parse_tokens(toks);
        assert_eq!(ast, Ok(Ast { val: AstVal::Num(2.0), span: (0, 1), branches: AstBranch::Leaf }));
    }

    #[test]
    fn constants() {
        assert_eq!(parse_tokens(vec!(Token { val: TokVal::Name("pi".to_string()), span: (0, 2)})),
                   Ok(Ast { val: AstVal::Const(Pi), span: (0, 2), branches: AstBranch::Leaf }));

        assert_eq!(parse_tokens(vec!(Token { val: TokVal::Name("π".to_string()), span: (0, 1)})),
                   Ok(Ast { val: AstVal::Const(Pi), span: (0, 1), branches: AstBranch::Leaf }));

        assert_eq!(parse_tokens(vec!(Token { val: TokVal::Name("e".to_string()), span: (0, 1)})),
                   Ok(Ast { val: AstVal::Const(E), span: (0, 1), branches: AstBranch::Leaf }));

        assert_eq!(parse_tokens(vec!(Token { val: TokVal::Name("phi".to_string()), span: (0, 3)})),
                   Ok(Ast { val: AstVal::Const(Phi), span: (0, 3), branches: AstBranch::Leaf }));

        assert_eq!(parse_tokens(vec!(Token { val: TokVal::Name("ϕ".to_string()), span: (0, 1)})),
                   Ok(Ast { val: AstVal::Const(Phi), span: (0, 1), branches: AstBranch::Leaf }));
    }

    #[test]
    fn empty() {
        let toks = vec!();
        let err = parse_tokens(toks);
        assert!(err.is_err());
    }
}<|endoftext|>