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
use types::*;
use Parse;
use common::*;
use attribute::*;

/// Parses a list of argument. Ex: `double v1, double v2, double v3, optional double alpha`
pub type ArgumentList = Punctuated<Argument, term!(,)>;

/// Parses an argument. Ex: `double v1|double... v1s`
#[derive(Debug, PartialEq)]
pub enum Argument {
    Single(SingleArgument),
    Variadic(VariadicArgument)
}

impl Parse for Argument {
    named!(parse -> Self, alt!(
        weedle!(SingleArgument) => {|inner| Argument::Single(inner)} |
        weedle!(VariadicArgument) => {|inner| Argument::Variadic(inner)}
    ));
}

/// Parses `[attributes]? optional? type identifier ( = default )?`
///
/// Note: `= default` is only allowed if `optional` is present
#[derive(Debug, PartialEq)]
pub struct SingleArgument {
    pub attributes: Option<ExtendedAttributeList>,
    pub optional: Option<term!(optional)>,
    pub type_: Type,
    pub identifier: Identifier,
    pub default: Option<Default>
}

impl Parse for SingleArgument {
    named!(parse -> Self, do_parse!(
        attributes: weedle!(Option<ExtendedAttributeList>) >>
        optional: weedle!(Option<term!(optional)>) >>
        type_: weedle!(Type) >>
        identifier: weedle!(Identifier) >>
        default: opt_flat!(cond_reduce!(optional.is_some(), weedle!(Option<Default>))) >>
        (SingleArgument { attributes, optional, type_, identifier, default })
    ));
}

/// Parses `[attributes]? type... identifier`
#[derive(Debug, PartialEq)]
pub struct VariadicArgument {
    pub attributes: Option<ExtendedAttributeList>,
    pub type_: Type,
    pub ellipsis: term!(...),
    pub identifier: Identifier
}

impl Parse for VariadicArgument {
    named!(parse -> Self, do_parse!(
        attributes: weedle!(Option<ExtendedAttributeList>) >>
        type_: weedle!(Type) >>
        ellipsis: weedle!(term!(...)) >>
        identifier: weedle!(Identifier) >>
        (VariadicArgument { attributes, type_, ellipsis, identifier })
    ));
}

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

    test!(should_parse_single_argument { "optional short a" =>
        "";
        SingleArgument;
        attributes.is_none();
        optional.is_some();
        identifier.name == "a";
        default.is_none();
    });

    test!(should_parse_variadic_argument { "short... a" =>
        "";
        VariadicArgument;
        attributes.is_none();
        identifier.name == "a";
    });
}