1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

/// Using a modified, regular-expression-like syntax, repeatedly calls another parser the number of times specified.
///
/// ## Example
///
/// ```
/// just!(pub a { "a"; } );
/// 
/// repeat!(pub repeat_a_five_times { a; { 5 } } ); 
/// 
/// repeat!(pub repeat_a_at_least_five_times { a; { 5, } } ); 
///
/// repeat!(pub repeat_a_forever { a; { , } } ); 
///
/// ```
///
#[macro_export]
macro_rules! repeat {

    ($visibility:vis $name:ident { $to_repeat:ident; { $lower:expr , } } )=> { 

        repeat!($visibility $name { $to_repeat; { 1 , usize::MAX } } );

    };

    ($visibility:vis $name:ident { $to_repeat:ident; { , $upper:expr } } )=> { 

        repeat!($visibility $name { $to_repeat; { 0 , $upper }});

    };

    ($visibility:vis $name:ident { $to_repeat:ident; { , } } )=> { 

        repeat!($visibility $name { $to_repeat; { 0 , usize::MAX }});

    };

    ($visibility:vis $name:ident { $to_repeat:ident; { $amount:expr } } )=> { 

        repeat!($visibility $name { $to_repeat; { $amount , $amount }});

    };

    ($visibility:vis $name:ident { $to_repeat:ident; { $lower:expr , $upper:expr } } ) => { 

        $visibility fn $name ( string: String, index: usize ) -> $crate::parse_result::ParseResult {

            use $crate::Parser;
            use $crate::Progress;
            use $crate::ParseError;
            use $crate::Done;
            use std::rc::Rc;

            let lower: usize = $lower;
            let upper: usize = $upper;

            let to_repeat: Parser = $to_repeat;

            let name: &'static str = stringify!($name);

            let mut offset = 0;

            let mut children: Vec<Rc<Done>> = vec![];

            #[allow(unused_assignments)]
            let mut parse_error = ParseError {

                offset,
                
                name_stack: vec![],

                message: ""

            };
            
            loop {
                
                let result = to_repeat(string.clone(), index + offset);

                if let Ok(progress) = result {

                    children.push(Rc::from(progress.done));

                    offset += progress.offset;

                    continue;

                }

                if let Err(new_parse_error) = result {

                    parse_error = new_parse_error;

                    break;

                }

            }

            if children.len() < lower || children.len() > upper {
                
                let mut result = parse_error.clone();

                result.offset = offset;

                result.name_stack.push(name);

                result.message = concat!("Couldn't parse '", stringify!($name) ,"' enough times.");

                return Err(result.clone());

            }

            Ok( Progress { offset, done: Done::Nonterminal {
                
                name,

                children
            
            }})

        }

    };

}