<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::str::CowString;
use super::{Token, NumericValue, Tokenizer, SourcePosition, SourceLocation};

pub struct Parser<'i: 't, 't> {
    tokenizer: &'t mut Tokenizer<'i>,
    parent_state: Option<&'t mut ParserState>,
    state: ParserState,
}

struct ParserState {
    nested_blocks: NestedBlockList,
    /// For block/function parsers that need to stop at the matching `)`, `]`, or `}`
    at_start_of: Option<BlockType>,
    /// For block/function parsers that need to stop at the matching `)`, `]`, or `}`
    stop_at_end_of: Option<BlockType>,
    /// For parsers from `parse_until`
    stop_before: Delimiters,
    exhausted: bool,
}

#[deriving(Copy, 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
        }
    }
}

type NestedBlockList = Option<Box<NestedBlockListItem>>;

struct NestedBlockListItem {
    next: NestedBlockList,
    block_type: BlockType,
}

trait NestedBlockListExt {
    fn push(&mut self, block_type: BlockType);
    fn consume(self, tokenizer: &mut Tokenizer) -> bool;
}

impl NestedBlockListExt for NestedBlockList {
    fn push(&mut self, block_type: BlockType) {
        debug_assert!(self.is_none());
        *self = Some(box NestedBlockListItem {
            next: self.take(),
            block_type: block_type,
        })
    }

    /// Return value indicates whether the end of the input was reached.
    fn consume(self, tokenizer: &mut Tokenizer) -> bool {
        if let Some(box NestedBlockListItem { block_type, next }) = self {
            // Recursion first: the inner-most item of the list
            // is for the inner-most nested block.
            next.consume(tokenizer) || consume_until_end_of_block(block_type, tokenizer)
        } else {
            false
        }
    }
}

#[unsafe_destructor] // FIXME What does this mean?
impl<'i, 't> Drop for Parser<'i, 't> {
    fn drop(&mut self) {
        if self.state.exhausted {
            // We’ve already reached the end of our delimited input:
            // nothing to inform the parent of.
            debug_assert!(self.state.nested_blocks.is_none());
            return
        }
        if let Some(parent_state) = self.parent_state.take() {
            // Inform our parent parser of what they need to consume.
            debug_assert!(parent_state.nested_blocks.is_none());
            parent_state.nested_blocks = self.state.nested_blocks.take();
            if let Some(block_type) = self.state.at_start_of {
                parent_state.nested_blocks.push(block_type)
            }
            // Don’t propagate stop_at_end_of back for delimited parsers:
            if self.state.stop_before.is_none() {
                debug_assert!(parent_state.at_start_of.is_none());
                parent_state.at_start_of = self.state.stop_at_end_of;
            }
        }
    }
}

#[deriving(Copy, 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 };
}

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 is_none(&self) -> bool {
        self.bits == 0
    }

    fn from_token(token: &Token) -> Delimiters {
        match *token {
            Token::Semicolon => Delimiter::Semicolon,
            Token::Comma  => Delimiter::Comma,
            Token::Delim('!') => Delimiter::Bang,
            Token::CurlyBracketBlock => Delimiter::CurlyBracketBlock,
            _ => Delimiter::None,
        }
    }
}

impl<'i, 't> Parser<'i, 't> {
    #[inline]
    pub fn new(tokenizer: &'t mut Tokenizer<'i>) -> Parser<'i, 't> {
        Parser {
            tokenizer: tokenizer,
            parent_state: None,
            state: ParserState {
                nested_blocks: None,
                at_start_of: None,
                stop_at_end_of: None,
                stop_before: Delimiter::None,
                exhausted: false,
            },
        }
    }

    #[inline]
    pub fn parse_str<T>(input: &str, parse: |&mut Parser| -> T) -> T {
        parse(&mut Parser::new(&mut Tokenizer::new(input.as_slice())))
    }

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

    #[inline]
    pub fn expect_exhausted(&mut self) -> Result<(), ()> {
        if self.is_exhausted() {
            Ok(())
        } else {
            Err(())
        }
    }

    #[inline]
    pub fn peek(&mut self) -> Result<&Token<'i>, ()> {
        // Consume whatever needs to be consumed (e.g. open blocks).
        let token = try!(self.next());
        self.push_back(token);

        self.tokenizer.peek()
    }

    #[inline]
    pub fn push_back(&mut self, token: Token<'i>) {
        if BlockType::opening(&token) == self.state.at_start_of {
            self.state.at_start_of = None;
        }
        self.tokenizer.push_back(token)
    }

    #[inline]
    pub fn push_back_result(&mut self, token_result: Result<Token<'i>, ()>) {
        if let Ok(token) = token_result {
            self.push_back(token)
        }
    }

    #[inline]
    pub fn unexpected<T>(&mut self, token: Token<'i>) -> Result<T, ()> {
        self.push_back(token);
        Err(())
    }

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

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

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

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

    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 self.state.exhausted {
            return Err(())
        }
        if self.state.nested_blocks.take().consume(self.tokenizer) {
            self.state.exhausted = true;
            return Err(())
        }
        if let Some(block_type) = self.state.at_start_of.take() {
            if consume_until_end_of_block(block_type, self.tokenizer) {
                self.state.exhausted = true;
                return Err(())
            }
        }
        match self.tokenizer.next() {
            Err(()) => {
                self.state.exhausted = true;
                Err(())
            },
            Ok(token) => {
                if self.state.stop_before.contains(Delimiters::from_token(&token)) {
                    self.tokenizer.push_back(token);
                    self.state.exhausted = true;
                    return Err(())
                }
                if self.state.stop_at_end_of.is_some() &&
                        BlockType::closing(&token) == self.state.stop_at_end_of {
                    self.state.exhausted = true;
                    return Err(())
                }
                if let Some(block_type) = BlockType::opening(&token) {
                    self.state.at_start_of = Some(block_type);
                }
                Ok(token)
            }
        }
    }

    #[inline]
    pub fn err_consume_until_after<T>(&mut self, stop_after: Delimiters) -> Result<T, ()> {
        self.consume_until_after(stop_after);
        Err(())
    }

    pub fn consume_until_after(&mut self, stop_after: Delimiters) {
        if self.state.exhausted {
            return
        }
        // FIXME: have a special-purpose tokenizer method for this that does less work.
        while let Ok(token) = self.tokenizer.next() {
            if stop_after.contains(Delimiters::from_token(&token)) {
                return
            }
            if self.state.stop_before.contains(Delimiters::from_token(&token)) {
                self.tokenizer.push_back(token);
                self.state.exhausted = true;
                return
            }
            if self.state.stop_at_end_of.is_some() &&
                    BlockType::closing(&token) == self.state.stop_at_end_of {
                self.state.exhausted = true;
                return
            }
            if let Some(block_type) = BlockType::opening(&token) {
                if consume_until_end_of_block(block_type, self.tokenizer) {
                    self.state.exhausted = true;
                    return
                }
            }
        }
        self.state.exhausted = true;
    }

    // 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_nested_block<'a>(&'a mut self) -> Parser<'i, 'a> {
        if let Some(block_type) = self.state.at_start_of.take() {
            debug_assert!(!self.state.exhausted);
            Parser {
                tokenizer: self.tokenizer,
                state: ParserState {
                    nested_blocks: self.state.nested_blocks.take(),
                    at_start_of: None,
                    stop_at_end_of: Some(block_type),
                    stop_before: Delimiter::None,
                    exhausted: false,
                },
                parent_state: Some(&mut self.state),
            }
        } else {
            panic!("\
                parse_block can only be called when a Function, \
                ParenthesisBlock, SquareBracketBlock, or CurlyBracketBlock \
                token was just consumed.\
            ");
        }
    }

    #[inline]
    pub fn parse_until_before<'a>(&'a mut self, stop_before: Delimiters) -> Parser<'i, 'a> {
        Parser {
            tokenizer: self.tokenizer,
            state: ParserState {
                nested_blocks: self.state.nested_blocks.take(),
                at_start_of: self.state.at_start_of.take(),
                stop_at_end_of: self.state.stop_at_end_of,
                stop_before: self.state.stop_before | stop_before,
                exhausted: self.state.exhausted,
            },
            parent_state: Some(&mut self.state),
        }
    }

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

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

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

    #[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),
            token => self.unexpected(token)
        }
    }

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

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

    #[inline]
    pub fn expect_percentage(&mut self) -> Result<f64, ()> {
        match try!(self.next()) {
            Token::Percentage(NumericValue { value, .. }) => Ok(value),
            token => self.unexpected(token)
        }
    }

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

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

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

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

/// Return value indicates whether the end of the input was reached.
fn consume_until_end_of_block(block_type: BlockType, tokenizer: &mut Tokenizer) -> bool {
    // 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 false
        }
        if let Some(block_type) = BlockType::opening(token) {
            if consume_until_end_of_block(block_type, tokenizer) {
                return true
            }
        }
    }
    true
}
<commit_msg>Add Parser::parse_comma_separated<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::str::CowString;
use super::{Token, NumericValue, Tokenizer, SourcePosition, SourceLocation};

pub struct Parser<'i: 't, 't> {
    tokenizer: &'t mut Tokenizer<'i>,
    parent_state: Option<&'t mut ParserState>,
    state: ParserState,
}

struct ParserState {
    nested_blocks: NestedBlockList,
    /// For block/function parsers that need to stop at the matching `)`, `]`, or `}`
    at_start_of: Option<BlockType>,
    /// For block/function parsers that need to stop at the matching `)`, `]`, or `}`
    stop_at_end_of: Option<BlockType>,
    /// For parsers from `parse_until`
    stop_before: Delimiters,
    exhausted: bool,
}

#[deriving(Copy, 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
        }
    }
}

type NestedBlockList = Option<Box<NestedBlockListItem>>;

struct NestedBlockListItem {
    next: NestedBlockList,
    block_type: BlockType,
}

trait NestedBlockListExt {
    fn push(&mut self, block_type: BlockType);
    fn consume(self, tokenizer: &mut Tokenizer) -> bool;
}

impl NestedBlockListExt for NestedBlockList {
    fn push(&mut self, block_type: BlockType) {
        debug_assert!(self.is_none());
        *self = Some(box NestedBlockListItem {
            next: self.take(),
            block_type: block_type,
        })
    }

    /// Return value indicates whether the end of the input was reached.
    fn consume(self, tokenizer: &mut Tokenizer) -> bool {
        if let Some(box NestedBlockListItem { block_type, next }) = self {
            // Recursion first: the inner-most item of the list
            // is for the inner-most nested block.
            next.consume(tokenizer) || consume_until_end_of_block(block_type, tokenizer)
        } else {
            false
        }
    }
}

#[unsafe_destructor] // FIXME What does this mean?
impl<'i, 't> Drop for Parser<'i, 't> {
    fn drop(&mut self) {
        if self.state.exhausted {
            // We’ve already reached the end of our delimited input:
            // nothing to inform the parent of.
            debug_assert!(self.state.nested_blocks.is_none());
            return
        }
        if let Some(parent_state) = self.parent_state.take() {
            // Inform our parent parser of what they need to consume.
            debug_assert!(parent_state.nested_blocks.is_none());
            parent_state.nested_blocks = self.state.nested_blocks.take();
            if let Some(block_type) = self.state.at_start_of {
                parent_state.nested_blocks.push(block_type)
            }
            // Don’t propagate stop_at_end_of back for delimited parsers:
            if self.state.stop_before.is_none() {
                debug_assert!(parent_state.at_start_of.is_none());
                parent_state.at_start_of = self.state.stop_at_end_of;
            }
        }
    }
}

#[deriving(Copy, 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 };
}

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 is_none(&self) -> bool {
        self.bits == 0
    }

    fn from_token(token: &Token) -> Delimiters {
        match *token {
            Token::Semicolon => Delimiter::Semicolon,
            Token::Comma  => Delimiter::Comma,
            Token::Delim('!') => Delimiter::Bang,
            Token::CurlyBracketBlock => Delimiter::CurlyBracketBlock,
            _ => Delimiter::None,
        }
    }
}

impl<'i, 't> Parser<'i, 't> {
    #[inline]
    pub fn new(tokenizer: &'t mut Tokenizer<'i>) -> Parser<'i, 't> {
        Parser {
            tokenizer: tokenizer,
            parent_state: None,
            state: ParserState {
                nested_blocks: None,
                at_start_of: None,
                stop_at_end_of: None,
                stop_before: Delimiter::None,
                exhausted: false,
            },
        }
    }

    #[inline]
    pub fn parse_str<T>(input: &str, parse: |&mut Parser| -> T) -> T {
        parse(&mut Parser::new(&mut Tokenizer::new(input.as_slice())))
    }

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

    #[inline]
    pub fn expect_exhausted(&mut self) -> Result<(), ()> {
        if self.is_exhausted() {
            Ok(())
        } else {
            Err(())
        }
    }

    #[inline]
    pub fn peek(&mut self) -> Result<&Token<'i>, ()> {
        // Consume whatever needs to be consumed (e.g. open blocks).
        let token = try!(self.next());
        self.push_back(token);

        self.tokenizer.peek()
    }

    #[inline]
    pub fn push_back(&mut self, token: Token<'i>) {
        if BlockType::opening(&token) == self.state.at_start_of {
            self.state.at_start_of = None;
        }
        self.tokenizer.push_back(token)
    }

    #[inline]
    pub fn push_back_result(&mut self, token_result: Result<Token<'i>, ()>) {
        if let Ok(token) = token_result {
            self.push_back(token)
        }
    }

    #[inline]
    pub fn unexpected<T>(&mut self, token: Token<'i>) -> Result<T, ()> {
        self.push_back(token);
        Err(())
    }

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

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

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

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

    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 self.state.exhausted {
            return Err(())
        }
        if self.state.nested_blocks.take().consume(self.tokenizer) {
            self.state.exhausted = true;
            return Err(())
        }
        if let Some(block_type) = self.state.at_start_of.take() {
            if consume_until_end_of_block(block_type, self.tokenizer) {
                self.state.exhausted = true;
                return Err(())
            }
        }
        match self.tokenizer.next() {
            Err(()) => {
                self.state.exhausted = true;
                Err(())
            },
            Ok(token) => {
                if self.state.stop_before.contains(Delimiters::from_token(&token)) {
                    self.tokenizer.push_back(token);
                    self.state.exhausted = true;
                    return Err(())
                }
                if self.state.stop_at_end_of.is_some() &&
                        BlockType::closing(&token) == self.state.stop_at_end_of {
                    self.state.exhausted = true;
                    return Err(())
                }
                if let Some(block_type) = BlockType::opening(&token) {
                    self.state.at_start_of = Some(block_type);
                }
                Ok(token)
            }
        }
    }

    #[inline]
    pub fn err_consume_until_after<T>(&mut self, stop_after: Delimiters) -> Result<T, ()> {
        self.consume_until_after(stop_after);
        Err(())
    }

    pub fn consume_until_after(&mut self, stop_after: Delimiters) {
        if self.state.exhausted {
            return
        }
        // FIXME: have a special-purpose tokenizer method for this that does less work.
        while let Ok(token) = self.tokenizer.next() {
            if stop_after.contains(Delimiters::from_token(&token)) {
                return
            }
            if self.state.stop_before.contains(Delimiters::from_token(&token)) {
                self.tokenizer.push_back(token);
                self.state.exhausted = true;
                return
            }
            if self.state.stop_at_end_of.is_some() &&
                    BlockType::closing(&token) == self.state.stop_at_end_of {
                self.state.exhausted = true;
                return
            }
            if let Some(block_type) = BlockType::opening(&token) {
                if consume_until_end_of_block(block_type, self.tokenizer) {
                    self.state.exhausted = true;
                    return
                }
            }
        }
        self.state.exhausted = true;
    }

    // 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![try!(self.parse_until_before(Delimiter::Comma)
                                       .parse_entirely(|parser| parse_one(parser)))];
        loop {
            match self.next() {
                Ok(Token::Comma) => {
                    values.push(try!(self.parse_until_before(Delimiter::Comma)
                                         .parse_entirely(|parser| parse_one(parser))))
                }
                Ok(token) => return self.unexpected(token),
                Err(()) => return Ok(values),
            }
        }
    }

    #[inline]
    pub fn parse_nested_block<'a>(&'a mut self) -> Parser<'i, 'a> {
        if let Some(block_type) = self.state.at_start_of.take() {
            debug_assert!(!self.state.exhausted);
            Parser {
                tokenizer: self.tokenizer,
                state: ParserState {
                    nested_blocks: self.state.nested_blocks.take(),
                    at_start_of: None,
                    stop_at_end_of: Some(block_type),
                    stop_before: Delimiter::None,
                    exhausted: false,
                },
                parent_state: Some(&mut self.state),
            }
        } else {
            panic!("\
                parse_block can only be called when a Function, \
                ParenthesisBlock, SquareBracketBlock, or CurlyBracketBlock \
                token was just consumed.\
            ");
        }
    }

    #[inline]
    pub fn parse_until_before<'a>(&'a mut self, stop_before: Delimiters) -> Parser<'i, 'a> {
        Parser {
            tokenizer: self.tokenizer,
            state: ParserState {
                nested_blocks: self.state.nested_blocks.take(),
                at_start_of: self.state.at_start_of.take(),
                stop_at_end_of: self.state.stop_at_end_of,
                stop_before: self.state.stop_before | stop_before,
                exhausted: self.state.exhausted,
            },
            parent_state: Some(&mut self.state),
        }
    }

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

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

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

    #[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),
            token => self.unexpected(token)
        }
    }

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

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

    #[inline]
    pub fn expect_percentage(&mut self) -> Result<f64, ()> {
        match try!(self.next()) {
            Token::Percentage(NumericValue { value, .. }) => Ok(value),
            token => self.unexpected(token)
        }
    }

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

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

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

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

/// Return value indicates whether the end of the input was reached.
fn consume_until_end_of_block(block_type: BlockType, tokenizer: &mut Tokenizer) -> bool {
    // 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 false
        }
        if let Some(block_type) = BlockType::opening(token) {
            if consume_until_end_of_block(block_type, tokenizer) {
                return true
            }
        }
    }
    true
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::iter;
use std::str;
use node;
use node::Node;

struct Lexer<'a> {
    input: iter::Peekable<str::Chars<'a>>,
}

impl<'a> Lexer<'a> {
    pub fn new(input: iter::Peekable<str::Chars<'a>>) -> Lexer<'a> {
        Lexer { input: input }
    }

    pub fn next(&mut self) -> Option<char> {
        self.input.next()
    }

    pub fn next_no_whitespace(&mut self) -> Option<char> {
        self.comsume_whitespace();
        self.input.next()
    }

    pub fn peek(&mut self) -> Option<char> {
        self.input.peek().map( |c| c.to_owned() )
    }

    // Need to remove side-effect ?
    pub fn peek_no_whitespace(&mut self) -> Option<char> {
        self.comsume_whitespace();
        self.input.peek().map( |c| c.to_owned() )
    }

    fn comsume_whitespace(&mut self) {
        while self.peek().map( |c| c.is_whitespace() ).unwrap_or(false) {
            self.input.next();
        }
    }
}

pub type ParseResult = Result<Node, ParseError>;

#[derive(Debug)]
pub enum ParseError {
    InvalidSyntax,
    UnmatchedParen
}

impl ParseError {
    pub fn to_str(&self) ->  &'static str {
        match *self {
            ParseError::InvalidSyntax => "Invalid Syntax",
            ParseError::UnmatchedParen => "Unmatched Paren"
        }
    }
}

fn read_quote(input: &mut Lexer) -> ParseResult {
    let v = try!(read(input));
    Ok(node::rcell(Node::Sym("quote".to_string()), v))
}

fn read_list(input: &mut Lexer) -> ParseResult {
    match input.peek_no_whitespace() {
        None => Err(ParseError::UnmatchedParen),
        Some(')') => Ok(Node::Nil),
        _ => {
            let car = try!(read(input));
            let cdr = try!(read_list(input));
            Ok(Node::Cell(Rc::new(car), Rc::new(cdr)))
        },
    }
}

fn read_int(c: char, input: &mut Lexer) -> ParseResult {
    let radix = 10;
    let v = &mut String::new();
    v.push(c);

    while let Some(n) = input.peek() {
        if !n.is_digit(radix) {
            break;
        }
        v.push(n);
        input.next();
    }

    Ok(Node::Int(i32::from_str_radix(&v, radix).unwrap()))
}

fn read_number(input: &mut Lexer, c: char) ->  ParseResult {
    read_int(c, input)
}

fn read_symbol(input: &mut Lexer, c: char) ->  ParseResult {
    let v = &mut String::new();
    v.push(c);

    while let Some(c) = input.peek() {
        if !is_ident(c) {
            break;
        }
        v.push(c);
        input.next();
    }

    Ok(Node::Sym(v.to_owned()))
}

fn is_ident(c: char) -> bool {
    match c {
        'a'...'z' | 'A'...'Z' | '0'...'9' | '=' | '<' | '>' |
        '+' | '-' | '/' | '%' => true,
        _ => false
    }
}

fn read(input: &mut Lexer) ->  ParseResult {
    match input.next_no_whitespace() {
        None => Ok(Node::Nil),
        Some(c) =>
            match c {
                '(' => read_list(input),
                '\'' => read_quote(input),
                '0'...'9' => read_number(input, c),
                _ => read_symbol(input, c)
            }
    }
}

pub fn parse<T: Into<String>>(input: T) -> ParseResult {
    read(&mut Lexer::new(input.into().chars().peekable()))
}
<commit_msg>Change uncorrective names<commit_after>use std::rc::Rc;
use std::iter;
use std::str;
use node;
use node::Node;

struct Lexer<'a> {
    input: iter::Peekable<str::Chars<'a>>,
}

impl<'a> Lexer<'a> {
    pub fn new(input: iter::Peekable<str::Chars<'a>>) -> Lexer<'a> {
        Lexer { input: input }
    }

    pub fn next(&mut self) -> Option<char> {
        self.input.next()
    }

    pub fn next_no_whitespace(&mut self) -> Option<char> {
        self.comsume_whitespace();
        self.input.next()
    }

    pub fn peek(&mut self) -> Option<char> {
        self.input.peek().map( |c| c.to_owned() )
    }

    // Need to remove side-effect ?
    pub fn peek_no_whitespace(&mut self) -> Option<char> {
        self.comsume_whitespace();
        self.input.peek().map( |c| c.to_owned() )
    }

    fn comsume_whitespace(&mut self) {
        while self.peek().map( |c| c.is_whitespace() ).unwrap_or(false) {
            self.input.next();
        }
    }
}

pub type ParseResult = Result<Node, ParseError>;

#[derive(Debug)]
pub enum ParseError {
    InvalidSyntax,
    UnmatchedParen
}

impl ParseError {
    pub fn to_str(&self) ->  &'static str {
        match *self {
            ParseError::InvalidSyntax => "Invalid Syntax",
            ParseError::UnmatchedParen => "Unmatched Paren"
        }
    }
}

fn read_quote(lexer: &mut Lexer) -> ParseResult {
    let v = try!(read(lexer));
    Ok(node::rcell(Node::Sym("quote".to_string()), v))
}

fn read_list(lexer: &mut Lexer) -> ParseResult {
    match lexer.peek_no_whitespace() {
        None => Err(ParseError::UnmatchedParen),
        Some(')') => Ok(Node::Nil),
        _ => {
            let car = try!(read(lexer));
            let cdr = try!(read_list(lexer));
            Ok(Node::Cell(Rc::new(car), Rc::new(cdr)))
        },
    }
}

fn read_int(c: char, lexer: &mut Lexer) -> ParseResult {
    let radix = 10;
    let v = &mut String::new();
    v.push(c);

    while let Some(n) = lexer.peek() {
        if !n.is_digit(radix) {
            break;
        }
        v.push(n);
        lexer.next();
    }

    Ok(Node::Int(i32::from_str_radix(&v, radix).unwrap()))
}

fn read_number(lexer: &mut Lexer, c: char) ->  ParseResult {
    read_int(c, lexer)
}

fn read_symbol(lexer: &mut Lexer, c: char) ->  ParseResult {
    let v = &mut String::new();
    v.push(c);

    while let Some(c) = lexer.peek() {
        if !is_ident(c) {
            break;
        }
        v.push(c);
        lexer.next();
    }

    Ok(Node::Sym(v.to_owned()))
}

fn is_ident(c: char) -> bool {
    match c {
        'a'...'z' | 'A'...'Z' | '0'...'9' | '=' | '<' | '>' |
        '+' | '-' | '/' | '%' => true,
        _ => false
    }
}

fn read(lexer: &mut Lexer) ->  ParseResult {
    match lexer.next_no_whitespace() {
        None => Ok(Node::Nil),
        Some(c) =>
            match c {
                '(' => read_list(lexer),
                '\'' => read_quote(lexer),
                '0'...'9' => read_number(lexer, c),
                _ => read_symbol(lexer, c)
            }
    }
}

pub fn parse<T: Into<String>>(input: T) -> ParseResult {
    read(&mut Lexer::new(input.into().chars().peekable()))
}
<|endoftext|>


<commit_before>use super::{Document,Root,RootChild,Element,ElementChild};

struct Parser;

struct ParsedElement<'a> {
    name: &'a str,
    attributes: Vec<ParsedAttribute<'a>>,
    children: Vec<ParsedElement<'a>>,
}

struct ParsedAttribute<'a> {
    name: &'a str,
    value: &'a str,
}

macro_rules! try_parse(
    ($e:expr) => ({
        match $e {
            None => return None,
            Some(x) => x,
        }
    })
)

// Pattern: 0-or-1
macro_rules! optional_parse(
    ($f:expr, $start:expr) => ({
        match $f {
            None => (None, $start),
            Some((value, next)) => (Some(value), next),
        }
    })
)

impl Parser {
    fn new() -> Parser {
        Parser
    }

    fn parse_preamble<'a>(&self, xml: &'a str) -> &'a str {
        // Parse the preamble
        let idx = xml.find_str("?>").expect("No preamble end");
        let end_of_preamble = idx + "?>".len();
        xml.slice_from(end_of_preamble)
    }

    fn optional_space<'a>(&self, xml: &'a str) -> &'a str {
        match xml.slice_space() {
            Some((_, next_xml)) => next_xml,
            None => xml,
        }
    }

    fn parse_attribute_value_quote<'a>(&self, xml: &'a str, quote: &str) -> Option<(&'a str, &'a str)> {
        let (_, xml) = match xml.slice_literal(quote) {
            None => return None,
            Some(x) => x,
        };
        // TODO: don't consume & or <
        let (value, xml) = xml.slice_until(quote).expect("No value");
        let (_, xml) = xml.slice_literal(quote).expect("No quote");

        Some((value, xml))
    }

    fn parse_attribute<'a>(&self, xml: &'a str) -> Option<(ParsedAttribute<'a>, &'a str)> {
        let (name, xml) = match xml.slice_name() {
            Some(x) => x,
            None => return None,
        };

        let xml = self.optional_space(xml);
        let (_, xml) = xml.slice_literal("=").expect("No equal sign");
        let xml = self.optional_space(xml);

        // Pattern: alternate
        let (value, xml) = match self.parse_attribute_value_quote(xml, "'") {
            Some(x) => x,
            None => match self.parse_attribute_value_quote(xml, "\"") {
                Some(x) => x,
                None => fail!("No attribute value"),
            },
        };

        Some((ParsedAttribute{name: name, value: value}, xml))
    }

    fn parse_attributes<'a>(&self, xml: &'a str) -> (Vec<ParsedAttribute<'a>>, &'a str) {
        let mut xml = xml;
        let mut attrs = Vec::new();

        // Pattern: zero-or-more
        // On failure, return the end of the last successful parse
        loop {
            let (_, after_space) = match xml.slice_space() {
                None => return (attrs, xml),
                Some(x) => x,
            };

            xml = match self.parse_attribute(after_space) {
                None => return (attrs, xml),
                Some((attr, after_attr)) => {
                    attrs.push(attr);
                    after_attr
                },
            };
        }
    }

    fn parse_empty_element<'a>(&self, xml: &'a str) -> Option<(ParsedElement<'a>, &'a str)> {
        let (_, xml) = try_parse!(xml.slice_literal("<"));
        let (name, xml) = try_parse!(xml.slice_name());
        let (attrs, xml) = self.parse_attributes(xml);
        let xml = self.optional_space(xml);
        let (_, xml) = try_parse!(xml.slice_literal("/>"));

        Some((ParsedElement{name: name, attributes: attrs, children: Vec::new()}, xml))
    }

    fn parse_element_start<'a>(&self, xml: &'a str) -> Option<(ParsedElement<'a>, &'a str)> {
        let (_, xml) = try_parse!(xml.slice_literal("<"));
        let (name, xml) = try_parse!(xml.slice_name());
        let (attrs, xml) = self.parse_attributes(xml);
        let xml = self.optional_space(xml);
        let (_, xml) = try_parse!(xml.slice_literal(">"));

        Some((ParsedElement{name: name, attributes: attrs, children: Vec::new()}, xml))
    }

    fn parse_element_end<'a>(&self, xml: &'a str) -> Option<(&'a str, &'a str)> {
        let (_, xml) = try_parse!(xml.slice_literal("</"));
        let (name, xml) = try_parse!(xml.slice_name());
        let xml = self.optional_space(xml);
        let (_, xml) = try_parse!(xml.slice_literal(">"));
        Some((name, xml))
    }

    fn parse_non_empty_element<'a>(&self, xml: &'a str) -> Option<(ParsedElement<'a>, &'a str)> {
        let (mut element, xml) = try_parse!(self.parse_element_start(xml));
        let (child, xml) = optional_parse!(self.parse_element(xml), xml);
        let (name, xml) = try_parse!(self.parse_element_end(xml));

        if element.name != name {
            fail!("tags do not match!");
        }

        child.map(|c| element.children.push(c));

        Some((element, xml))
    }

    fn parse_element<'a>(&self, xml: &'a str) -> Option<(ParsedElement<'a>, &'a str)> {
        // Pattern: alternate
        match self.parse_empty_element(xml) {
            Some(x) => Some(x),
            None => match self.parse_non_empty_element(xml) {
                Some(x) => Some(x),
                None => None,
            },
        }
    }

    fn hydrate_parsed_data(&self, element_data: ParsedElement) -> Document {
        let doc = Document::new();

        let element = doc.new_element(element_data.name.to_string());
        for attr in element_data.attributes.iter() {
            element.set_attribute(attr.name.to_string(), attr.value.to_string());
        }
        for child in element_data.children.iter() {
            let c = doc.new_element(child.name.to_string());//attrs; recursive
            element.append_child(c);
        }
        doc.root().append_child(element);

        doc
    }

    fn parse(&self, xml: &str) -> Document {
        let after_preamble = self.parse_preamble(xml);

        let (element, _tail) = self.parse_element(after_preamble).expect("no element");

        self.hydrate_parsed_data(element)
    }
}

trait XmlStr<'a> {
    fn slice_at(&self, position: uint) -> (&'a str, &'a str);
    fn slice_until(&self, s: &str) -> Option<(&'a str, &'a str)>;
    fn slice_literal(&self, expected: &str) -> Option<(&'a str, &'a str)>;
    fn slice_start_rest(&self, is_first: |char| -> bool, is_rest: |char| -> bool) -> Option<(&'a str, &'a str)>;
    fn slice_name(&self) -> Option<(&'a str, &'a str)>;
    fn slice_space(&self) -> Option<(&'a str, &'a str)>;
}

impl<'a> XmlStr<'a> for &'a str {
    fn slice_at(&self, position: uint) -> (&'a str, &'a str) {
        (self.slice_to(position), self.slice_from(position))
    }

    fn slice_until(&self, s: &str) -> Option<(&'a str, &'a str)> {
        match self.find_str(s) {
            Some(position) => Some(self.slice_at(position)),
            None => None
        }
    }

    fn slice_literal(&self, expected: &str) -> Option<(&'a str, &'a str)> {
        if self.starts_with(expected) {
            Some(self.slice_at(expected.len()))
        } else {
            None
        }
    }

    fn slice_start_rest(&self,
                        is_first: |char| -> bool,
                        is_rest: |char| -> bool)
                        -> Option<(&'a str, &'a str)>
    {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if is_first(c) => (),
            Some((_, _)) => return None,
            None => return None,
        };

        let mut positions = positions.skip_while(|&(_, c)| is_rest(c));
        match positions.next() {
            Some((offset, _)) => Some(self.slice_at(offset)),
            None => Some((self.clone(), "")),
        }
    }

    fn slice_name(&self) -> Option<(&'a str, &'a str)> {
        self.slice_start_rest(|c| c.is_name_start_char(), |c| c.is_name_char())
    }

    fn slice_space(&self) -> Option<(&'a str, &'a str)> {
        self.slice_start_rest(|c| c.is_space_char(), |c| c.is_space_char())
    }
}

trait XmlChar {
    fn is_name_start_char(&self) -> bool;
    fn is_name_char(&self) -> bool;
    fn is_space_char(&self) -> bool;
}

impl XmlChar for char {
    fn is_name_start_char(&self) -> bool {
        match *self {
            ':'                        |
            'A'..'Z'                   |
            '_'                        |
            'a'..'z'                   |
            '\U000000C0'..'\U000000D6' |
            '\U000000D8'..'\U000000F6' |
            '\U000000F8'..'\U000002FF' |
            '\U00000370'..'\U0000037D' |
            '\U0000037F'..'\U00001FFF' |
            '\U0000200C'..'\U0000200D' |
            '\U00002070'..'\U0000218F' |
            '\U00002C00'..'\U00002FEF' |
            '\U00003001'..'\U0000D7FF' |
            '\U0000F900'..'\U0000FDCF' |
            '\U0000FDF0'..'\U0000FFFD' |
            '\U00010000'..'\U000EFFFF' => true,
            _ => false,
        }
    }

    fn is_name_char(&self) -> bool {
        if self.is_name_start_char() { return true; }
        match *self {
            '-'                |
            '.'                |
            '0'..'9'           |
            '\u00B7'           |
            '\u0300'..'\u036F' |
            '\u203F'..'\u2040' => true,
            _ => false
        }
    }

    fn is_space_char(&self) -> bool {
        match *self {
            '\x20' |
            '\x09' |
            '\x0D' |
            '\x0A' => true,
            _ => false,
        }
    }
}

trait Hax {
    fn first_child(&self) -> Option<RootChild>;
}

impl Hax for Root {
    fn first_child(&self) -> Option<RootChild> {
        self.children().remove(0)
    }
}

trait Hax2 {
    fn first_child(&self) -> Option<ElementChild>;
}

impl Hax2 for Element {
    fn first_child(&self) -> Option<ElementChild> {
        self.children().remove(0)
    }
}

#[test]
fn parses_a_document_with_a_single_element() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello />");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.name().as_slice(), "hello");
}

#[test]
fn parses_an_element_with_an_attribute() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello scope='world'/>");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.get_attribute("scope").unwrap().as_slice(), "world");
}

#[test]
fn parses_an_element_with_an_attribute_using_double_quotes() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello scope=\"world\"/>");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.get_attribute("scope").unwrap().as_slice(), "world");
}

#[test]
fn parses_an_element_with_multiple_attributes() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello scope=\"world\" happy='true'/>");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.get_attribute("scope").unwrap().as_slice(), "world");
    assert_eq!(top.get_attribute("happy").unwrap().as_slice(), "true");
}

#[test]
fn parses_an_element_that_is_not_self_closing() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello></hello>");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.name().as_slice(), "hello");
}

#[test]
fn parses_nested_elements() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello><world/></hello>");
    let nested = doc.root().first_child().unwrap().element().unwrap().first_child().unwrap().element().unwrap();

    assert_eq!(nested.name().as_slice(), "world");
}
<commit_msg>Parse nested elements and attributes on those elements<commit_after>use super::{Document,Root,RootChild,Element,ElementChild};

struct Parser;

struct ParsedElement<'a> {
    name: &'a str,
    attributes: Vec<ParsedAttribute<'a>>,
    children: Vec<ParsedElement<'a>>,
}

struct ParsedAttribute<'a> {
    name: &'a str,
    value: &'a str,
}

macro_rules! try_parse(
    ($e:expr) => ({
        match $e {
            None => return None,
            Some(x) => x,
        }
    })
)

// Pattern: 0-or-1
macro_rules! optional_parse(
    ($f:expr, $start:expr) => ({
        match $f {
            None => (None, $start),
            Some((value, next)) => (Some(value), next),
        }
    })
)

impl Parser {
    fn new() -> Parser {
        Parser
    }

    fn parse_preamble<'a>(&self, xml: &'a str) -> &'a str {
        // Parse the preamble
        let idx = xml.find_str("?>").expect("No preamble end");
        let end_of_preamble = idx + "?>".len();
        xml.slice_from(end_of_preamble)
    }

    fn optional_space<'a>(&self, xml: &'a str) -> &'a str {
        match xml.slice_space() {
            Some((_, next_xml)) => next_xml,
            None => xml,
        }
    }

    fn parse_attribute_value_quote<'a>(&self, xml: &'a str, quote: &str) -> Option<(&'a str, &'a str)> {
        let (_, xml) = match xml.slice_literal(quote) {
            None => return None,
            Some(x) => x,
        };
        // TODO: don't consume & or <
        let (value, xml) = xml.slice_until(quote).expect("No value");
        let (_, xml) = xml.slice_literal(quote).expect("No quote");

        Some((value, xml))
    }

    fn parse_attribute<'a>(&self, xml: &'a str) -> Option<(ParsedAttribute<'a>, &'a str)> {
        let (name, xml) = match xml.slice_name() {
            Some(x) => x,
            None => return None,
        };

        let xml = self.optional_space(xml);
        let (_, xml) = xml.slice_literal("=").expect("No equal sign");
        let xml = self.optional_space(xml);

        // Pattern: alternate
        let (value, xml) = match self.parse_attribute_value_quote(xml, "'") {
            Some(x) => x,
            None => match self.parse_attribute_value_quote(xml, "\"") {
                Some(x) => x,
                None => fail!("No attribute value"),
            },
        };

        Some((ParsedAttribute{name: name, value: value}, xml))
    }

    fn parse_attributes<'a>(&self, xml: &'a str) -> (Vec<ParsedAttribute<'a>>, &'a str) {
        let mut xml = xml;
        let mut attrs = Vec::new();

        // Pattern: zero-or-more
        // On failure, return the end of the last successful parse
        loop {
            let (_, after_space) = match xml.slice_space() {
                None => return (attrs, xml),
                Some(x) => x,
            };

            xml = match self.parse_attribute(after_space) {
                None => return (attrs, xml),
                Some((attr, after_attr)) => {
                    attrs.push(attr);
                    after_attr
                },
            };
        }
    }

    fn parse_empty_element<'a>(&self, xml: &'a str) -> Option<(ParsedElement<'a>, &'a str)> {
        let (_, xml) = try_parse!(xml.slice_literal("<"));
        let (name, xml) = try_parse!(xml.slice_name());
        let (attrs, xml) = self.parse_attributes(xml);
        let xml = self.optional_space(xml);
        let (_, xml) = try_parse!(xml.slice_literal("/>"));

        Some((ParsedElement{name: name, attributes: attrs, children: Vec::new()}, xml))
    }

    fn parse_element_start<'a>(&self, xml: &'a str) -> Option<(ParsedElement<'a>, &'a str)> {
        let (_, xml) = try_parse!(xml.slice_literal("<"));
        let (name, xml) = try_parse!(xml.slice_name());
        let (attrs, xml) = self.parse_attributes(xml);
        let xml = self.optional_space(xml);
        let (_, xml) = try_parse!(xml.slice_literal(">"));

        Some((ParsedElement{name: name, attributes: attrs, children: Vec::new()}, xml))
    }

    fn parse_element_end<'a>(&self, xml: &'a str) -> Option<(&'a str, &'a str)> {
        let (_, xml) = try_parse!(xml.slice_literal("</"));
        let (name, xml) = try_parse!(xml.slice_name());
        let xml = self.optional_space(xml);
        let (_, xml) = try_parse!(xml.slice_literal(">"));
        Some((name, xml))
    }

    fn parse_non_empty_element<'a>(&self, xml: &'a str) -> Option<(ParsedElement<'a>, &'a str)> {
        let (mut element, xml) = try_parse!(self.parse_element_start(xml));
        let (child, xml) = optional_parse!(self.parse_element(xml), xml);
        let (name, xml) = try_parse!(self.parse_element_end(xml));

        if element.name != name {
            fail!("tags do not match!");
        }

        child.map(|c| element.children.push(c));

        Some((element, xml))
    }

    fn parse_element<'a>(&self, xml: &'a str) -> Option<(ParsedElement<'a>, &'a str)> {
        // Pattern: alternate
        match self.parse_empty_element(xml) {
            Some(x) => Some(x),
            None => match self.parse_non_empty_element(xml) {
                Some(x) => Some(x),
                None => None,
            },
        }
    }

    fn hydrate_element(&self, doc: Document, element_data: ParsedElement) -> Element {
        let element = doc.new_element(element_data.name.to_string());
        for attr in element_data.attributes.iter() {
            element.set_attribute(attr.name.to_string(), attr.value.to_string());
        }
        for child in element_data.children.move_iter() {
            element.append_child(self.hydrate_element(doc.clone(), child));
        }
        element
    }

    fn hydrate_parsed_data(&self, element_data: ParsedElement) -> Document {
        let doc = Document::new();

        doc.root().append_child(self.hydrate_element(doc.clone(), element_data));

        doc
    }

    fn parse(&self, xml: &str) -> Document {
        let after_preamble = self.parse_preamble(xml);

        let (element, _tail) = self.parse_element(after_preamble).expect("no element");

        self.hydrate_parsed_data(element)
    }
}

trait XmlStr<'a> {
    fn slice_at(&self, position: uint) -> (&'a str, &'a str);
    fn slice_until(&self, s: &str) -> Option<(&'a str, &'a str)>;
    fn slice_literal(&self, expected: &str) -> Option<(&'a str, &'a str)>;
    fn slice_start_rest(&self, is_first: |char| -> bool, is_rest: |char| -> bool) -> Option<(&'a str, &'a str)>;
    fn slice_name(&self) -> Option<(&'a str, &'a str)>;
    fn slice_space(&self) -> Option<(&'a str, &'a str)>;
}

impl<'a> XmlStr<'a> for &'a str {
    fn slice_at(&self, position: uint) -> (&'a str, &'a str) {
        (self.slice_to(position), self.slice_from(position))
    }

    fn slice_until(&self, s: &str) -> Option<(&'a str, &'a str)> {
        match self.find_str(s) {
            Some(position) => Some(self.slice_at(position)),
            None => None
        }
    }

    fn slice_literal(&self, expected: &str) -> Option<(&'a str, &'a str)> {
        if self.starts_with(expected) {
            Some(self.slice_at(expected.len()))
        } else {
            None
        }
    }

    fn slice_start_rest(&self,
                        is_first: |char| -> bool,
                        is_rest: |char| -> bool)
                        -> Option<(&'a str, &'a str)>
    {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if is_first(c) => (),
            Some((_, _)) => return None,
            None => return None,
        };

        let mut positions = positions.skip_while(|&(_, c)| is_rest(c));
        match positions.next() {
            Some((offset, _)) => Some(self.slice_at(offset)),
            None => Some((self.clone(), "")),
        }
    }

    fn slice_name(&self) -> Option<(&'a str, &'a str)> {
        self.slice_start_rest(|c| c.is_name_start_char(), |c| c.is_name_char())
    }

    fn slice_space(&self) -> Option<(&'a str, &'a str)> {
        self.slice_start_rest(|c| c.is_space_char(), |c| c.is_space_char())
    }
}

trait XmlChar {
    fn is_name_start_char(&self) -> bool;
    fn is_name_char(&self) -> bool;
    fn is_space_char(&self) -> bool;
}

impl XmlChar for char {
    fn is_name_start_char(&self) -> bool {
        match *self {
            ':'                        |
            'A'..'Z'                   |
            '_'                        |
            'a'..'z'                   |
            '\U000000C0'..'\U000000D6' |
            '\U000000D8'..'\U000000F6' |
            '\U000000F8'..'\U000002FF' |
            '\U00000370'..'\U0000037D' |
            '\U0000037F'..'\U00001FFF' |
            '\U0000200C'..'\U0000200D' |
            '\U00002070'..'\U0000218F' |
            '\U00002C00'..'\U00002FEF' |
            '\U00003001'..'\U0000D7FF' |
            '\U0000F900'..'\U0000FDCF' |
            '\U0000FDF0'..'\U0000FFFD' |
            '\U00010000'..'\U000EFFFF' => true,
            _ => false,
        }
    }

    fn is_name_char(&self) -> bool {
        if self.is_name_start_char() { return true; }
        match *self {
            '-'                |
            '.'                |
            '0'..'9'           |
            '\u00B7'           |
            '\u0300'..'\u036F' |
            '\u203F'..'\u2040' => true,
            _ => false
        }
    }

    fn is_space_char(&self) -> bool {
        match *self {
            '\x20' |
            '\x09' |
            '\x0D' |
            '\x0A' => true,
            _ => false,
        }
    }
}

trait Hax {
    fn first_child(&self) -> Option<RootChild>;
}

impl Hax for Root {
    fn first_child(&self) -> Option<RootChild> {
        self.children().remove(0)
    }
}

trait Hax2 {
    fn first_child(&self) -> Option<ElementChild>;
}

impl Hax2 for Element {
    fn first_child(&self) -> Option<ElementChild> {
        self.children().remove(0)
    }
}

#[test]
fn parses_a_document_with_a_single_element() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello />");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.name().as_slice(), "hello");
}

#[test]
fn parses_an_element_with_an_attribute() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello scope='world'/>");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.get_attribute("scope").unwrap().as_slice(), "world");
}

#[test]
fn parses_an_element_with_an_attribute_using_double_quotes() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello scope=\"world\"/>");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.get_attribute("scope").unwrap().as_slice(), "world");
}

#[test]
fn parses_an_element_with_multiple_attributes() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello scope=\"world\" happy='true'/>");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.get_attribute("scope").unwrap().as_slice(), "world");
    assert_eq!(top.get_attribute("happy").unwrap().as_slice(), "true");
}

#[test]
fn parses_an_element_that_is_not_self_closing() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello></hello>");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.name().as_slice(), "hello");
}

#[test]
fn parses_nested_elements() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello><world/></hello>");
    let nested = doc.root().first_child().unwrap().element().unwrap().first_child().unwrap().element().unwrap();

    assert_eq!(nested.name().as_slice(), "world");
}

#[test]
fn parses_multiply_nested_elements() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello><awesome><world/></awesome></hello>");
    let hello = doc.root().first_child().unwrap().element().unwrap();
    let awesome = hello.first_child().unwrap().element().unwrap();
    let world = awesome.first_child().unwrap().element().unwrap();

    assert_eq!(world.name().as_slice(), "world");
}

#[test]
fn parses_nested_elements_with_attributes() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello><world name='Earth'/></hello>");
    let hello = doc.root().first_child().unwrap().element().unwrap();
    let world = hello.first_child().unwrap().element().unwrap();

    assert_eq!(world.get_attribute("name").unwrap().as_slice(), "Earth");
}
<|endoftext|>


<commit_before>use std::iter::FromIterator;

use super::term::{Primitive, Term};

use combine::{Parser, ParserExt, State, ParseResult, ParseError, between, sep_by, letter, spaces, char, digit, many, many1, alpha_num, parser};
use combine::primitives::{Stream};

fn token_left_paren<I: Stream<Item=char>>(input: State<I>) -> ParseResult<(), I> {
    char('(').map(|_| ()).skip(spaces()).parse_state(input)
}

fn token_right_paren<I: Stream<Item=char>>(input: State<I>) -> ParseResult<(), I> {
    char(')').map(|_| ()).skip(spaces()).parse_state(input)
}

fn token_left_brace<I: Stream<Item=char>>(input: State<I>) -> ParseResult<(), I> {
    char('{').map(|_| ()).skip(spaces()).parse_state(input)
}

fn token_right_brace<I: Stream<Item=char>>(input: State<I>) -> ParseResult<(), I> {
    char('}').map(|_| ()).skip(spaces()).parse_state(input)
}

fn token_bar<I: Stream<Item=char>>(input: State<I>) -> ParseResult<(), I> {
    char('|').map(|_| ()).skip(spaces()).parse_state(input)
}

fn token_comma<I: Stream<Item=char>>(input: State<I>) -> ParseResult<(), I> {
    char(',').map(|_| ()).skip(spaces()).parse_state(input)
}

fn token_integer<I: Stream<Item=char>>(input: State<I>) -> ParseResult<i64, I> {
    many1::<Vec<char>, _>(digit()).map(|s| {
        let string: String = FromIterator::from_iter(s);
        string.parse().unwrap()
    }).skip(spaces()).parse_state(input)
}

fn token_identifier<I: Stream<Item=char>>(input: State<I>) -> ParseResult<String, I> {
    many1::<Vec<char>, _>(letter().or(char('-'))).map(|s| {
        FromIterator::from_iter(s)
    }).skip(spaces()).parse_state(input)
}

#[test]
fn test_parse_token_left_paren() {
    let result = parser(token_left_paren).parse("(");
    assert_eq!(result, Result::Ok(((), "")));
}

#[test]
fn test_parse_token_right_paren() {
    let result = parser(token_right_paren).parse(")");
    assert_eq!(result, Result::Ok(((), "")));
}

#[test]
fn test_parse_token_left_brace() {
    let result = parser(token_left_brace).parse("{");
    assert_eq!(result, Result::Ok(((), "")));
}

#[test]
fn test_parse_token_right_brace() {
    let result = parser(token_right_brace).parse("}");
    assert_eq!(result, Result::Ok(((), "")));
}

#[test]
fn test_parse_token_bar() {
    let result = parser(token_bar).parse("|");
    assert_eq!(result, Result::Ok(((), "")));
}

#[test]
fn test_parse_token_integer() {
    let result = parser(token_integer).parse("42");
    assert_eq!(result, Result::Ok((42, "")));
}

pub fn primitive<I: Stream<Item=char>>(input: State<I>) -> ParseResult<Primitive, I> {
    parser(token_integer).map(|i| Primitive::Integer(i)).parse_state(input)
}

fn term_val<I: Stream<Item=char>>(input: State<I>) -> ParseResult<Term, I> {
    parser(primitive).map(|val| Term::Val(val)).parse_state(input)
}

fn term_ref<I: Stream<Item=char>>(input: State<I>) -> ParseResult<Term, I> {
    parser(token_identifier).map(|id| Term::Ref(id)).parse_state(input)
}

fn term_app<I: Stream<Item=char>>(input: State<I>) -> ParseResult<Term, I> {
    between(
        parser(token_left_brace), parser(token_right_brace),
        (
            parser(term),
            parser(term),
            sep_by(
                parser(term),
                spaces()
            )
        )
    ).map(|(fun, first_arg, many_args)| {
        Term::app_many(fun, first_arg, many_args)
    }).parse_state(input)
}

fn term_fun<I: Stream<Item=char>>(input: State<I>) -> ParseResult<Term, I> {
    (
        between(
            parser(token_bar), parser(token_bar),
            (
                parser(token_identifier),
                sep_by(
                    parser(token_identifier),
                    spaces()
                )
            )
        ),
        parser(term)
    ).map(|((first_id, many_ids), term)| {
        Term::fun_many(first_id, many_ids, term)
    }).parse_state(input)
}

pub fn term<I: Stream<Item=char>>(input: State<I>) -> ParseResult<Term, I> {
    between(parser(token_left_paren), parser(token_right_paren), parser(term))
    .or(parser(term_val))
    .or(parser(term_ref))
    .or(parser(term_app))
    .or(parser(term_fun))
    .parse_state(input)
}

#[test]
fn test_term_val_int() {
    let result = parser(term).parse("42");
    assert_eq!(result, Result::Ok((Term::val_int(42), "")));
}

#[test]
fn test_term_ref() {
    let result = parser(term).parse("x");
    let expr = Term::id("x".to_string());
    assert_eq!(result, Result::Ok((expr, "")));
}

#[test]
fn test_term_app() {
    let result = parser(term).parse("{a b}");
    let expr = Term::app(
        Term::id("a".to_string()),
        Term::id("b".to_string())
    );
    assert_eq!(result, Result::Ok((expr, "")));
}

#[test]
fn test_term_fun() {
    let result = parser(term).parse("|a| b");
    let expr = Term::fun(
        "a".to_string(),
        Term::id("b".to_string())
    );
    assert_eq!(result, Result::Ok((expr, "")));
}

pub fn parse_string(s: &String) -> Result<(Term, &str), ParseError<&str>> {
    parser(term).parse(s)
}
<commit_msg>fix parser warnings<commit_after>use std::iter::FromIterator;

use super::term::{Primitive, Term};

use combine::{Parser, ParserExt, State, ParseResult, ParseError, between, sep_by, letter, spaces, char, digit, many1, parser};
use combine::primitives::{Stream};

fn token_left_paren<I: Stream<Item=char>>(input: State<I>) -> ParseResult<(), I> {
    char('(').map(|_| ()).skip(spaces()).parse_state(input)
}

fn token_right_paren<I: Stream<Item=char>>(input: State<I>) -> ParseResult<(), I> {
    char(')').map(|_| ()).skip(spaces()).parse_state(input)
}

fn token_left_brace<I: Stream<Item=char>>(input: State<I>) -> ParseResult<(), I> {
    char('{').map(|_| ()).skip(spaces()).parse_state(input)
}

fn token_right_brace<I: Stream<Item=char>>(input: State<I>) -> ParseResult<(), I> {
    char('}').map(|_| ()).skip(spaces()).parse_state(input)
}

fn token_bar<I: Stream<Item=char>>(input: State<I>) -> ParseResult<(), I> {
    char('|').map(|_| ()).skip(spaces()).parse_state(input)
}

fn token_integer<I: Stream<Item=char>>(input: State<I>) -> ParseResult<i64, I> {
    many1::<Vec<char>, _>(digit()).map(|s| {
        let string: String = FromIterator::from_iter(s);
        string.parse().unwrap()
    }).skip(spaces()).parse_state(input)
}

fn token_identifier<I: Stream<Item=char>>(input: State<I>) -> ParseResult<String, I> {
    many1::<Vec<char>, _>(letter().or(char('-'))).map(|s| {
        FromIterator::from_iter(s)
    }).skip(spaces()).parse_state(input)
}

#[test]
fn test_parse_token_left_paren() {
    let result = parser(token_left_paren).parse("(");
    assert_eq!(result, Result::Ok(((), "")));
}

#[test]
fn test_parse_token_right_paren() {
    let result = parser(token_right_paren).parse(")");
    assert_eq!(result, Result::Ok(((), "")));
}

#[test]
fn test_parse_token_left_brace() {
    let result = parser(token_left_brace).parse("{");
    assert_eq!(result, Result::Ok(((), "")));
}

#[test]
fn test_parse_token_right_brace() {
    let result = parser(token_right_brace).parse("}");
    assert_eq!(result, Result::Ok(((), "")));
}

#[test]
fn test_parse_token_bar() {
    let result = parser(token_bar).parse("|");
    assert_eq!(result, Result::Ok(((), "")));
}

#[test]
fn test_parse_token_integer() {
    let result = parser(token_integer).parse("42");
    assert_eq!(result, Result::Ok((42, "")));
}

pub fn primitive<I: Stream<Item=char>>(input: State<I>) -> ParseResult<Primitive, I> {
    parser(token_integer).map(|i| Primitive::Integer(i)).parse_state(input)
}

fn term_val<I: Stream<Item=char>>(input: State<I>) -> ParseResult<Term, I> {
    parser(primitive).map(|val| Term::Val(val)).parse_state(input)
}

fn term_ref<I: Stream<Item=char>>(input: State<I>) -> ParseResult<Term, I> {
    parser(token_identifier).map(|id| Term::Ref(id)).parse_state(input)
}

fn term_app<I: Stream<Item=char>>(input: State<I>) -> ParseResult<Term, I> {
    between(
        parser(token_left_brace), parser(token_right_brace),
        (
            parser(term),
            parser(term),
            sep_by(
                parser(term),
                spaces()
            )
        )
    ).map(|(fun, first_arg, many_args)| {
        Term::app_many(fun, first_arg, many_args)
    }).parse_state(input)
}

fn term_fun<I: Stream<Item=char>>(input: State<I>) -> ParseResult<Term, I> {
    (
        between(
            parser(token_bar), parser(token_bar),
            (
                parser(token_identifier),
                sep_by(
                    parser(token_identifier),
                    spaces()
                )
            )
        ),
        parser(term)
    ).map(|((first_id, many_ids), term)| {
        Term::fun_many(first_id, many_ids, term)
    }).parse_state(input)
}

#[allow(unconditional_recursion)]
pub fn term<I: Stream<Item=char>>(input: State<I>) -> ParseResult<Term, I> {
    between(parser(token_left_paren), parser(token_right_paren), parser(term))
    .or(parser(term_val))
    .or(parser(term_ref))
    .or(parser(term_app))
    .or(parser(term_fun))
    .parse_state(input)
}

#[test]
fn test_term_val_int() {
    let result = parser(term).parse("42");
    assert_eq!(result, Result::Ok((Term::val_int(42), "")));
}

#[test]
fn test_term_ref() {
    let result = parser(term).parse("x");
    let expr = Term::id("x".to_string());
    assert_eq!(result, Result::Ok((expr, "")));
}

#[test]
fn test_term_app() {
    let result = parser(term).parse("{a b}");
    let expr = Term::app(
        Term::id("a".to_string()),
        Term::id("b".to_string())
    );
    assert_eq!(result, Result::Ok((expr, "")));
}

#[test]
fn test_term_fun() {
    let result = parser(term).parse("|a| b");
    let expr = Term::fun(
        "a".to_string(),
        Term::id("b".to_string())
    );
    assert_eq!(result, Result::Ok((expr, "")));
}

pub fn parse_string(s: &String) -> Result<(Term, &str), ParseError<&str>> {
    parser(term).parse(s)
}
<|endoftext|>


<commit_before>use ast::{Token, Expr};
use ast::{BlockExpr, ConstExpr, ThrowExpr, ReturnExpr, CallExpr, ConstructExpr, IfExpr, WhileLoopExpr, SwitchExpr, FunctionDeclExpr, LocalExpr, ArrayDeclExpr, ObjectDeclExpr, GetConstFieldExpr, GetFieldExpr, NumOpExpr, ConstExpr};
use ast::{CBool, CNull, CUndefined, CString, CNum};
use ast::{TIdent, TNumber, TString, TSemicolon, TColon, TDot, TEqual, TOpenParen, TCloseParen, TComma, TOpenBlock, TCloseBlock, TOpenArray, TCloseArray, TQuestion, TNumOp};
use collections::treemap::TreeMap;
use std::fmt;
use std::vec::Vec;
#[deriving(Clone)]
#[deriving(Eq)]
/// An error encountered during parsing an expression
pub enum ParseError {
	/// When it expected a certain kind of token, but got another
	Expected(Vec<Token>, Token),
	/// When it expected a certain expression, but got another
	ExpectedExpr(~str, Expr)
}
impl fmt::Show for ParseError {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		return match *self {
			Expected(ref wanted, ref got) if wanted.len() == 0 => write!(f.buf, "Expected expression, got {}", got),
			Expected(ref wanted, ref got) => {
				try!(write!(f.buf, "Expected "));
				let last = wanted.last().unwrap();
				for wanted_token in wanted.iter() {
					match write!(f.buf, "'{}'{}", wanted_token, if wanted_token == last {""} else {", "}) {
						Err(err) => return Err(err),
						Ok(_) => ()
					}
				}
				write!(f.buf, ", got {}", got)
			},
			ExpectedExpr(ref wanted, ref got) => {
				write!(f.buf, "Expected {}, got {}", wanted, got)
			}
		}
	}
}
/// A result which gives a pretty-printed error if it fails
pub trait VerboseResult<T> {
	/// Unwrap the value if it's Ok and if not pretty-print the error
	fn v_unwrap(&self) -> T;
}
impl<T : Clone, E : fmt::Show> VerboseResult<T> for Result<T, E> {
	fn v_unwrap(&self) -> T {
		match *self {
			Ok(ref val) => val.clone(),
			Err(ref err) => fail!("{}", err)
		}
	}
}
pub type ParseResult = Result<~Expr, ParseError>;
pub type ParseStructResult = Result<Option<~Expr>, ParseError>;
/// A Javascript parser
pub struct Parser {
	/// The tokens being input
	tokens: Vec<Token>,
	/// The current position within the tokens
	pos: uint
}
impl Parser {
	/// Creates a new parser, using [tokens] as input
	pub fn new(tokens: Vec<Token>) -> ~Parser {
		return ~Parser {tokens: tokens, pos: 0};
	}
	/// Parse all expressions in the token array
	pub fn parse_all(&mut self) -> ParseResult {
		let mut exprs = Vec::new();
		while self.pos < self.tokens.len() {
			let result = try!(self.parse());
			exprs.push(result);
		}
		return Ok(~BlockExpr(exprs));
	}
	fn parse_struct(&mut self, name:&str) -> ParseStructResult {
		match name {
			"true" => Ok(Some(~ConstExpr(CBool(true)))),
			"false" => Ok(Some(~ConstExpr(CBool(false)))),
			"null" => Ok(Some(~ConstExpr(CNull))),
			"undefined" => Ok(Some(~ConstExpr(CUndefined))),
			"throw" => {
				let thrown = try!(self.parse());
				Ok(Some(~ThrowExpr(thrown)))
			},
			"return" => Ok(Some(~ReturnExpr(Some(try!(self.parse()))))),
			"new" => {
				let call = try!(self.parse());
				print!("new {}", call);
				match *call {
					CallExpr(ref func, ref args) => Ok(Some(~ConstructExpr(func.clone(), args.clone()))),
					_ => Err(ExpectedExpr(~"constructor", *call))
				}
			}
			"if" => {
				try!(self.expect(TOpenParen));
				let cond = try!(self.parse());
				try!(self.expect(TCloseParen));
				let expr = try!(self.parse());
				let next = self.tokens.get(self.pos + 1).clone();
				Ok(Some(~IfExpr(cond, expr, if next == TIdent(~"else") {
					self.pos += 2;
					Some(try!(self.parse()))
				} else {
					None
				})))
			},
			"while" => {
				try!(self.expect(TOpenParen));
				let cond = try!(self.parse());
				try!(self.expect(TCloseParen));
				let expr = try!(self.parse());
				Ok(Some(~WhileLoopExpr(cond, expr)))
			},
			"switch" => {
				try!(self.expect(TOpenParen));
				let value = self.parse();
				try!(self.expect(TCloseParen));
				try!(self.expect(TOpenBlock));
				let mut cases = Vec::new();
				let mut default = None;
				while self.pos + 1 < self.tokens.len() {
					let tok = self.tokens.get(self.pos).clone();
					self.pos += 1;
					match tok {
						TIdent(ref id) if *id == ~"case" => {
							let cond = self.parse();
							let mut block = Vec::new();
							try!(self.expect(TColon));
							loop {
								match self.tokens.get(self.pos).clone() {
									TIdent(ref id) if *id == ~"case" || *id == ~"default" => break,
									TCloseBlock => break,
									_ => block.push(try!(self.parse()))
								}
							}
							cases.push((cond.unwrap(), block));
						},
						TIdent(ref id) if *id == ~"default" => {
							let mut block = Vec::new();
							try!(self.expect(TColon));
							loop {
								match self.tokens.get(self.pos).clone() {
									TIdent(ref id) if *id == ~"case" || *id == ~"default" => break,
									TCloseBlock => break,
									_ => block.push(try!(self.parse()))
								}
							}
							default = Some(~BlockExpr(block));
						},
						TCloseBlock => break,
						_ => fail!("Expected 'case', 'default' or '{}', not '{}'", '}', tok)
					}
				}
				try!(self.expect(TCloseBlock));
				Ok(Some(~SwitchExpr(value.unwrap(), cases, default)))
			},
			"function" => {
				let tk = self.tokens.get(self.pos).clone();
				let name : Option<~str> = match tk {
					TIdent(ref name) => {
						self.pos += 1;
						Some(name.clone())
					},
					TOpenParen => None,
					_ => return Err(Expected(vec!(TIdent(~"identifier")), tk.clone()))
				};
				try!(self.expect(TOpenParen));
				let mut args:Vec<~str> = Vec::new();
				let mut tk = self.tokens.get(self.pos).clone();
				while tk != TCloseParen {
					match tk {
						TIdent(ref id) => args.push(id.to_owned()),
						_ => return Err(Expected(vec!(TIdent(~"identifier")), tk))
					}
					self.pos += 1;
					if *self.tokens.get(self.pos) == TComma {
						self.pos += 1;
					}
					tk = self.tokens.get(self.pos).clone();
				}
				self.pos += 1;
				let block = try!(self.parse());
				Ok(Some(~FunctionDeclExpr(name, args, block)))
			},
			_ => Ok(None)
		}
	}
	/// Parse a single expression
	pub fn parse(&mut self) -> ParseResult {
		let token = self.tokens.get(self.pos).clone();
		self.pos += 1;
		let expr : ~Expr = match token {
			TSemicolon => try!(self.parse()),
			TIdent(ref s) => {
				let structure = try!(self.parse_struct(s.clone()));
				match structure {
					Some(v) => v,
					None => ~LocalExpr(s.to_owned())
				}
			},
			TString(ref s) => ~ConstExpr(CString(s.to_owned())),
			TOpenParen => {
				let nexte = try!(self.parse());
				try!(self.expect(TCloseParen));
				nexte
			},
			TOpenArray => {
				let mut array = Vec::new();
				let mut expect_comma_or_end = *self.tokens.get(self.pos) == TCloseArray;
				loop {
					let token = self.tokens.get(self.pos).clone();
					if token == TCloseArray && expect_comma_or_end {
						self.pos += 1;
						break;
					} else if token == TComma && expect_comma_or_end {
						expect_comma_or_end = false;
					} else if expect_comma_or_end {
						return Err(Expected(vec!(TComma, TCloseArray), token));
					} else {
						let parsed = try!(self.parse());
						self.pos -= 1;
						array.push(parsed);
						expect_comma_or_end = true;
					}
					self.pos += 1;
				}
				~ArrayDeclExpr(array)
			},
			TOpenBlock if self.tokens.get(self.pos) == &TCloseBlock => {
				self.pos += 1;
				~ObjectDeclExpr(~TreeMap::new())
			},
			TOpenBlock if self.tokens.get(self.pos + 1) == &TColon => {
				let mut map = ~TreeMap::new();
				while self.tokens.get(self.pos - 1) == &TComma || map.len() == 0 {
					let tk = self.tokens.get(self.pos).clone();
					let name = match tk {
						TIdent(ref id) => id,
						TString(ref str) => str,
						_ => return Err(Expected(vec!(TIdent(~"identifier"), TString(~"string")), tk))
					};
					self.pos += 1;
					try!(self.expect(TColon));
					let value = try!(self.parse());
					map.insert(name.to_owned(), value);
					self.pos += 1;
				}
				~ObjectDeclExpr(map)
			},
			TOpenBlock => {
				let mut exprs = Vec::new();
				loop {
					if *self.tokens.get(self.pos) == TCloseBlock {
						break;
					} else {
						exprs.push(try!(self.parse()));
					}
				}
				self.pos += 1;
				~BlockExpr(exprs)
			},
			TNumber(num) => ~ConstExpr(CNum(num)),
			_ => return Err(Expected(Vec::new(), token.clone()))
		};
		return if self.pos >= self.tokens.len() { Ok(expr) } else {self.parse_next(expr)};
	}
	fn parse_next(&mut self, expr:~Expr) -> ParseResult {
		let next = self.tokens.get(self.pos).clone();
		let mut carry_on = true;
		let mut result = expr.clone();
		match next {
			TDot => {
				self.pos += 1;
				let tk = self.tokens.get(self.pos).clone();
				match tk {
					TIdent(ref s) => result = ~GetConstFieldExpr(expr, s.to_owned()),
					_ => return Err(Expected(vec!(TIdent(~"identifier")), next))
				}
				self.pos += 1;
			},
			TOpenParen => {
				let mut args = Vec::new();
				let mut expect_comma_or_end = *self.tokens.get(self.pos + 1) == TCloseParen;
				loop {
					self.pos += 1;
					let token = self.tokens.get(self.pos).clone();
					if token == TCloseParen && expect_comma_or_end {
						self.pos += 1;
						break;
					} else if token == TComma && expect_comma_or_end {
						expect_comma_or_end = false;
					} else if expect_comma_or_end {
						return Err(Expected(vec!(TComma, TCloseParen), token));
					} else {
						let parsed = try!(self.parse());
						self.pos -= 1;
						args.push(parsed);
						expect_comma_or_end = true;
					}
				}
				result = ~CallExpr(expr, args);
			},
			TQuestion => {
				self.pos += 1;
				let if_e = try!(self.parse());
				try!(self.expect(TColon));
				let else_e = try!(self.parse());
				result = ~IfExpr(expr, if_e, Some(else_e));
			},
			TOpenArray => {
				self.pos += 1;
				let index = try!(self.parse());
				try!(self.expect(TCloseArray));
				result = ~GetFieldExpr(expr, index);
			},
			TSemicolon => {
				self.pos += 1;
			},
			TNumOp(op) => {
				self.pos += 1;
				let next = try!(self.parse());
				result = ~NumOpExpr(op, expr, next);
			},
			_ => carry_on = false
		};
		return if carry_on && self.pos < self.tokens.len() { self.parse_next(result) } else {Ok(result)};
	}
	/// Returns an error if the next symbol is not [tk]
	fn expect(&mut self, tk:Token) -> Result<(), ParseError> {
		self.pos += 1;
		let curr_tk = self.tokens.get(self.pos - 1).clone();
		return if curr_tk != tk {
			Err(Expected(vec!(tk), curr_tk))
		} else {
			Ok(())
		};
	}
}<commit_msg>Re-implement support for empty array items<commit_after>use ast::{Token, Expr};
use ast::{BlockExpr, ConstExpr, ThrowExpr, ReturnExpr, CallExpr, ConstructExpr, IfExpr, WhileLoopExpr, SwitchExpr, FunctionDeclExpr, LocalExpr, ArrayDeclExpr, ObjectDeclExpr, GetConstFieldExpr, GetFieldExpr, NumOpExpr, ConstExpr};
use ast::{CBool, CNull, CUndefined, CString, CNum};
use ast::{TIdent, TNumber, TString, TSemicolon, TColon, TDot, TEqual, TOpenParen, TCloseParen, TComma, TOpenBlock, TCloseBlock, TOpenArray, TCloseArray, TQuestion, TNumOp};
use collections::treemap::TreeMap;
use std::fmt;
use std::vec::Vec;
#[deriving(Clone)]
#[deriving(Eq)]
/// An error encountered during parsing an expression
pub enum ParseError {
	/// When it expected a certain kind of token, but got another
	Expected(Vec<Token>, Token),
	/// When it expected a certain expression, but got another
	ExpectedExpr(~str, Expr)
}
impl fmt::Show for ParseError {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		return match *self {
			Expected(ref wanted, ref got) if wanted.len() == 0 => write!(f.buf, "Expected expression, got {}", got),
			Expected(ref wanted, ref got) => {
				try!(write!(f.buf, "Expected "));
				let last = wanted.last().unwrap();
				for wanted_token in wanted.iter() {
					match write!(f.buf, "'{}'{}", wanted_token, if wanted_token == last {""} else {", "}) {
						Err(err) => return Err(err),
						Ok(_) => ()
					}
				}
				write!(f.buf, ", got {}", got)
			},
			ExpectedExpr(ref wanted, ref got) => {
				write!(f.buf, "Expected {}, got {}", wanted, got)
			}
		}
	}
}
/// A result which gives a pretty-printed error if it fails
pub trait VerboseResult<T> {
	/// Unwrap the value if it's Ok and if not pretty-print the error
	fn v_unwrap(&self) -> T;
}
impl<T : Clone, E : fmt::Show> VerboseResult<T> for Result<T, E> {
	fn v_unwrap(&self) -> T {
		match *self {
			Ok(ref val) => val.clone(),
			Err(ref err) => fail!("{}", err)
		}
	}
}
pub type ParseResult = Result<~Expr, ParseError>;
pub type ParseStructResult = Result<Option<~Expr>, ParseError>;
/// A Javascript parser
pub struct Parser {
	/// The tokens being input
	tokens: Vec<Token>,
	/// The current position within the tokens
	pos: uint
}
impl Parser {
	/// Creates a new parser, using [tokens] as input
	pub fn new(tokens: Vec<Token>) -> ~Parser {
		return ~Parser {tokens: tokens, pos: 0};
	}
	/// Parse all expressions in the token array
	pub fn parse_all(&mut self) -> ParseResult {
		let mut exprs = Vec::new();
		while self.pos < self.tokens.len() {
			let result = try!(self.parse());
			exprs.push(result);
		}
		return Ok(~BlockExpr(exprs));
	}
	fn parse_struct(&mut self, name:&str) -> ParseStructResult {
		match name {
			"true" => Ok(Some(~ConstExpr(CBool(true)))),
			"false" => Ok(Some(~ConstExpr(CBool(false)))),
			"null" => Ok(Some(~ConstExpr(CNull))),
			"undefined" => Ok(Some(~ConstExpr(CUndefined))),
			"throw" => {
				let thrown = try!(self.parse());
				Ok(Some(~ThrowExpr(thrown)))
			},
			"return" => Ok(Some(~ReturnExpr(Some(try!(self.parse()))))),
			"new" => {
				let call = try!(self.parse());
				print!("new {}", call);
				match *call {
					CallExpr(ref func, ref args) => Ok(Some(~ConstructExpr(func.clone(), args.clone()))),
					_ => Err(ExpectedExpr(~"constructor", *call))
				}
			}
			"if" => {
				try!(self.expect(TOpenParen));
				let cond = try!(self.parse());
				try!(self.expect(TCloseParen));
				let expr = try!(self.parse());
				let next = self.tokens.get(self.pos + 1).clone();
				Ok(Some(~IfExpr(cond, expr, if next == TIdent(~"else") {
					self.pos += 2;
					Some(try!(self.parse()))
				} else {
					None
				})))
			},
			"while" => {
				try!(self.expect(TOpenParen));
				let cond = try!(self.parse());
				try!(self.expect(TCloseParen));
				let expr = try!(self.parse());
				Ok(Some(~WhileLoopExpr(cond, expr)))
			},
			"switch" => {
				try!(self.expect(TOpenParen));
				let value = self.parse();
				try!(self.expect(TCloseParen));
				try!(self.expect(TOpenBlock));
				let mut cases = Vec::new();
				let mut default = None;
				while self.pos + 1 < self.tokens.len() {
					let tok = self.tokens.get(self.pos).clone();
					self.pos += 1;
					match tok {
						TIdent(ref id) if *id == ~"case" => {
							let cond = self.parse();
							let mut block = Vec::new();
							try!(self.expect(TColon));
							loop {
								match self.tokens.get(self.pos).clone() {
									TIdent(ref id) if *id == ~"case" || *id == ~"default" => break,
									TCloseBlock => break,
									_ => block.push(try!(self.parse()))
								}
							}
							cases.push((cond.unwrap(), block));
						},
						TIdent(ref id) if *id == ~"default" => {
							let mut block = Vec::new();
							try!(self.expect(TColon));
							loop {
								match self.tokens.get(self.pos).clone() {
									TIdent(ref id) if *id == ~"case" || *id == ~"default" => break,
									TCloseBlock => break,
									_ => block.push(try!(self.parse()))
								}
							}
							default = Some(~BlockExpr(block));
						},
						TCloseBlock => break,
						_ => fail!("Expected 'case', 'default' or '{}', not '{}'", '}', tok)
					}
				}
				try!(self.expect(TCloseBlock));
				Ok(Some(~SwitchExpr(value.unwrap(), cases, default)))
			},
			"function" => {
				let tk = self.tokens.get(self.pos).clone();
				let name : Option<~str> = match tk {
					TIdent(ref name) => {
						self.pos += 1;
						Some(name.clone())
					},
					TOpenParen => None,
					_ => return Err(Expected(vec!(TIdent(~"identifier")), tk.clone()))
				};
				try!(self.expect(TOpenParen));
				let mut args:Vec<~str> = Vec::new();
				let mut tk = self.tokens.get(self.pos).clone();
				while tk != TCloseParen {
					match tk {
						TIdent(ref id) => args.push(id.to_owned()),
						_ => return Err(Expected(vec!(TIdent(~"identifier")), tk))
					}
					self.pos += 1;
					if *self.tokens.get(self.pos) == TComma {
						self.pos += 1;
					}
					tk = self.tokens.get(self.pos).clone();
				}
				self.pos += 1;
				let block = try!(self.parse());
				Ok(Some(~FunctionDeclExpr(name, args, block)))
			},
			_ => Ok(None)
		}
	}
	/// Parse a single expression
	pub fn parse(&mut self) -> ParseResult {
		let token = self.tokens.get(self.pos).clone();
		self.pos += 1;
		let expr : ~Expr = match token {
			TSemicolon => try!(self.parse()),
			TIdent(ref s) => {
				let structure = try!(self.parse_struct(s.clone()));
				match structure {
					Some(v) => v,
					None => ~LocalExpr(s.to_owned())
				}
			},
			TString(ref s) => ~ConstExpr(CString(s.to_owned())),
			TOpenParen => {
				let nexte = try!(self.parse());
				try!(self.expect(TCloseParen));
				nexte
			},
			TOpenArray => {
				let mut array = Vec::new();
				let mut expect_comma_or_end = *self.tokens.get(self.pos) == TCloseArray;
				loop {
					let token = self.tokens.get(self.pos).clone();
					if token == TCloseArray && expect_comma_or_end {
						self.pos += 1;
						break;
					} else if token == TComma && expect_comma_or_end {
						expect_comma_or_end = false;
					} else if token == TComma && !expect_comma_or_end {
						array.push(~ConstExpr(CNull));
						expect_comma_or_end = false;
					} else if expect_comma_or_end {
						return Err(Expected(vec!(TComma, TCloseArray), token));
					} else {
						let parsed = try!(self.parse());
						self.pos -= 1;
						array.push(parsed);
						expect_comma_or_end = true;
					}
					self.pos += 1;
				}
				~ArrayDeclExpr(array)
			},
			TOpenBlock if self.tokens.get(self.pos) == &TCloseBlock => {
				self.pos += 1;
				~ObjectDeclExpr(~TreeMap::new())
			},
			TOpenBlock if self.tokens.get(self.pos + 1) == &TColon => {
				let mut map = ~TreeMap::new();
				while self.tokens.get(self.pos - 1) == &TComma || map.len() == 0 {
					let tk = self.tokens.get(self.pos).clone();
					let name = match tk {
						TIdent(ref id) => id,
						TString(ref str) => str,
						_ => return Err(Expected(vec!(TIdent(~"identifier"), TString(~"string")), tk))
					};
					self.pos += 1;
					try!(self.expect(TColon));
					let value = try!(self.parse());
					map.insert(name.to_owned(), value);
					self.pos += 1;
				}
				~ObjectDeclExpr(map)
			},
			TOpenBlock => {
				let mut exprs = Vec::new();
				loop {
					if *self.tokens.get(self.pos) == TCloseBlock {
						break;
					} else {
						exprs.push(try!(self.parse()));
					}
				}
				self.pos += 1;
				~BlockExpr(exprs)
			},
			TNumber(num) => ~ConstExpr(CNum(num)),
			_ => return Err(Expected(Vec::new(), token.clone()))
		};
		return if self.pos >= self.tokens.len() { Ok(expr) } else {self.parse_next(expr)};
	}
	fn parse_next(&mut self, expr:~Expr) -> ParseResult {
		let next = self.tokens.get(self.pos).clone();
		let mut carry_on = true;
		let mut result = expr.clone();
		match next {
			TDot => {
				self.pos += 1;
				let tk = self.tokens.get(self.pos).clone();
				match tk {
					TIdent(ref s) => result = ~GetConstFieldExpr(expr, s.to_owned()),
					_ => return Err(Expected(vec!(TIdent(~"identifier")), next))
				}
				self.pos += 1;
			},
			TOpenParen => {
				let mut args = Vec::new();
				let mut expect_comma_or_end = *self.tokens.get(self.pos + 1) == TCloseParen;
				loop {
					self.pos += 1;
					let token = self.tokens.get(self.pos).clone();
					if token == TCloseParen && expect_comma_or_end {
						self.pos += 1;
						break;
					} else if token == TComma && expect_comma_or_end {
						expect_comma_or_end = false;
					} else if expect_comma_or_end {
						return Err(Expected(vec!(TComma, TCloseParen), token));
					} else {
						let parsed = try!(self.parse());
						self.pos -= 1;
						args.push(parsed);
						expect_comma_or_end = true;
					}
				}
				result = ~CallExpr(expr, args);
			},
			TQuestion => {
				self.pos += 1;
				let if_e = try!(self.parse());
				try!(self.expect(TColon));
				let else_e = try!(self.parse());
				result = ~IfExpr(expr, if_e, Some(else_e));
			},
			TOpenArray => {
				self.pos += 1;
				let index = try!(self.parse());
				try!(self.expect(TCloseArray));
				result = ~GetFieldExpr(expr, index);
			},
			TSemicolon => {
				self.pos += 1;
			},
			TNumOp(op) => {
				self.pos += 1;
				let next = try!(self.parse());
				result = ~NumOpExpr(op, expr, next);
			},
			_ => carry_on = false
		};
		return if carry_on && self.pos < self.tokens.len() { self.parse_next(result) } else {Ok(result)};
	}
	/// Returns an error if the next symbol is not [tk]
	fn expect(&mut self, tk:Token) -> Result<(), ParseError> {
		self.pos += 1;
		let curr_tk = self.tokens.get(self.pos - 1).clone();
		return if curr_tk != tk {
			Err(Expected(vec!(tk), curr_tk))
		} else {
			Ok(())
		};
	}
}<|endoftext|>