use super::{Expression, ParseState, ParseResult};
macro_rules! star( ( $ex:expr ) => ( &base::Star::new( $ex ) ); );
pub struct Star<'a> {
expr: &'a ( Expression + 'a )
}
impl<'b> Star<'b> {
pub fn new( expr: &Expression ) -> Star {
Star { expr: expr }
}
}
impl<'b> Expression for Star<'b> {
fn apply<'a>( &self, parse_state: &ParseState<'a> ) ->
Option< ParseResult<'a> > {
let mut final_result = ParseResult::fromParseState( *parse_state );
loop {
match self.expr.apply( &final_result.parse_state ) {
Some( result ) => {
final_result.parse_state = result.parse_state;
final_result.nodes.extend( result.nodes.into_iter() );
}
_ => break
}
}
Some( final_result )
}
}
#[cfg(test)]
mod tests {
use base;
use base::{Node, ParseResult, Expression, Data};
#[test]
fn Star_Match() {
let orig_state = input_state!( "aaa" );
match star!( lit!( "a" ) ).apply( &orig_state ) {
Some( ParseResult{ nodes, parse_state } ) => {
assert_eq!( nodes[ 0 ],
Node::withoutName( 0, 1, Data( b"a" ) ) );
assert_eq!( nodes[ 1 ],
Node::withoutName( 1, 2, Data( b"a" ) ) );
assert_eq!( nodes[ 2 ],
Node::withoutName( 2, 3, Data( b"a" ) ) );
assert_eq!( parse_state, orig_state.advanceTo( 3 ) );
}
_ => panic!( "No match." )
}
}
#[test]
fn Star_Match_JustOne() {
let orig_state = input_state!( "abb" );
match star!( lit!( "a" ) ).apply( &orig_state ) {
Some( ParseResult{ nodes, parse_state } ) => {
assert_eq!( nodes[ 0 ],
Node::withoutName( 0, 1, Data( b"a" ) ) );
assert_eq!( parse_state, orig_state.advanceTo( 1 ) );
}
_ => panic!( "No match." )
}
}
#[test]
fn Star_Match_Empty() {
let orig_state = input_state!( "y" );
match star!( lit!( "x" ) ).apply( &orig_state ) {
Some( ParseResult{ nodes, parse_state } ) => {
assert!( nodes.is_empty() );
assert_eq!( parse_state, orig_state );
}
_ => panic!( "No match." )
}
}
}