shadowplay/puppet_parser/
class.rs

1use crate::puppet_parser::common::{space0_delimimited, spaced_word};
2use crate::puppet_parser::{range::Range, IResult, ParseError, Span};
3use nom::{
4    bytes::complete::tag,
5    combinator::{map, opt},
6    sequence::{pair, preceded, tuple},
7};
8use crate::puppet_lang::{
9    argument::Argument,
10    identifier::LowerIdentifier,
11    toplevel::{Class, Definition, Plan},
12};
13
14type Header = (
15    LowerIdentifier<Range>,
16    crate::puppet_lang::List<Range, Argument<Range>>,
17);
18
19pub fn parse_header(input: Span) -> IResult<Header> {
20    let arguments_parser = map(
21        opt(crate::puppet_parser::common::round_parens_delimimited(
22            crate::puppet_parser::common::comma_separated_list0_with_last_comment(crate::puppet_parser::argument::parse),
23        )),
24        |v: Option<(Span, crate::puppet_lang::List<Range, Argument<Range>>, Span)>| {
25            v.map(|v| v.1).unwrap_or_else(crate::puppet_lang::List::default)
26        },
27    );
28
29    tuple((
30        ParseError::protect(
31            |_| "Invalid name".to_owned(),
32            crate::puppet_parser::identifier::identifier_with_toplevel,
33        ),
34        preceded(super::common::separator0, arguments_parser),
35    ))(input)
36}
37
38pub fn parse_class(input: Span) -> IResult<Class<Range>> {
39    let mut parser = map(
40        tuple((
41            spaced_word("class"),
42            space0_delimimited(ParseError::protect(
43                |_| "Failed to parse class header".to_owned(),
44                parse_header,
45            )),
46            ParseError::protect(
47                |_| "'{' or 'inherits' expected".to_string(),
48                pair(
49                    space0_delimimited(opt(preceded(
50                        tag("inherits"),
51                        ParseError::protect(
52                            |_| "Failed to parse what class is inherited".to_owned(),
53                            space0_delimimited(crate::puppet_parser::identifier::identifier_with_toplevel),
54                        ),
55                    ))),
56                    crate::puppet_parser::statement::parse_statement_block,
57                ),
58            ),
59        )),
60        |(kw, (identifier, arguments), (inherits, (_left_bracket, body, right_bracket)))| Class {
61            identifier,
62            arguments,
63            body,
64            inherits,
65            extra: (kw, right_bracket).into(),
66        },
67    );
68
69    parser(input)
70}
71
72pub fn parse_definition(input: Span) -> IResult<Definition<Range>> {
73    map(
74        tuple((
75            spaced_word("define"),
76            space0_delimimited(ParseError::protect(
77                |_| "Failed to parse definition header".to_owned(),
78                parse_header,
79            )),
80            space0_delimimited(ParseError::protect(
81                |_| "'{' expected".to_string(),
82                crate::puppet_parser::statement::parse_statement_block,
83            )),
84        )),
85        |(kw, (identifier, arguments), (_left_bracket, body, right_bracket))| Definition {
86            identifier,
87            arguments,
88            body,
89            extra: (kw, right_bracket).into(),
90        },
91    )(input)
92}
93
94pub fn parse_plan(input: Span) -> IResult<Plan<Range>> {
95    map(
96        tuple((
97            spaced_word("plan"),
98            space0_delimimited(ParseError::protect(
99                |_| "Failed to parse plan header".to_owned(),
100                parse_header,
101            )),
102            space0_delimimited(ParseError::protect(
103                |_| "'{' expected".to_string(),
104                crate::puppet_parser::statement::parse_statement_block,
105            )),
106        )),
107        |(kw, (identifier, arguments), (_left_bracket, body, right_bracket))| Plan {
108            identifier,
109            arguments,
110            body,
111            extra: (kw, right_bracket).into(),
112        },
113    )(input)
114}
115
116#[test]
117fn test_class() {
118    assert_eq!(
119        parse_class(Span::new("class  abc::def () {\n  }\n"))
120            .unwrap()
121            .1,
122        Class {
123            identifier: LowerIdentifier {
124                name: vec!["abc".to_owned(), "def".to_owned()],
125                is_toplevel: false,
126                extra: Range::new(7, 1, 8, 14, 1, 15),
127            },
128            arguments: crate::puppet_lang::List::default(),
129            body: crate::puppet_lang::List::default(),
130            inherits: None,
131            extra: Range::new(0, 1, 1, 23, 2, 3),
132        }
133    );
134
135    assert!(parse_class(Span::new(
136        "class  ab__c::de11f ( String[1,10] $a, Stdlib::Unixpath $b  ,  $c) inherits aa::bb { }"
137    ))
138    .is_ok());
139
140    assert!(parse_class(Span::new("class a ( $a = ,) {}")).is_err());
141
142    assert!(parse_class(Span::new("class a () { &&&&& UNKNOWN((STATEMENT}")).is_err())
143}
144
145#[test]
146fn test_body_tag() {
147    assert_eq!(
148        parse_class(Span::new(
149            "class  abc::def () {\n tag aaa, 'bbb', \"ccc\" }\n"
150        ))
151        .unwrap()
152        .1,
153        Class {
154            identifier: LowerIdentifier {
155                name: vec!["abc".to_owned(), "def".to_owned()],
156                is_toplevel: false,
157                extra: Range::new(7, 1, 8, 14, 1, 15),
158            },
159            arguments: crate::puppet_lang::List::default(),
160            body: crate::puppet_lang::List {
161                last_comment: vec![],
162                value: vec![crate::puppet_lang::statement::Statement {
163                    value: crate::puppet_lang::statement::StatementVariant::Expression(
164                        crate::puppet_lang::expression::Expression {
165                            accessor: None,
166                            comment: vec![],
167                            value: crate::puppet_lang::expression::ExpressionVariant::BuiltinFunction(
168                                crate::puppet_lang::builtin::BuiltinVariant::Tag(
169                                    crate::puppet_lang::builtin::Many1 {
170                                        lambda: None,
171                                        args: vec![
172                                            crate::puppet_lang::expression::Expression {
173                                                accessor: None,
174                                                comment: vec![],
175                                                value: crate::puppet_lang::expression::ExpressionVariant::Term(
176                                                    crate::puppet_lang::expression::Term {
177                                                        value: crate::puppet_lang::expression::TermVariant::String(
178                                                            crate::puppet_lang::string::StringExpr {
179                                                                data:
180                                                                crate::puppet_lang::string::StringVariant::SingleQuoted(
181                                                                    vec![
182                                                                        crate::puppet_lang::string::StringFragment::Literal(
183                                                                            crate::puppet_lang::string::Literal {
184                                                                            data: "aaa".to_owned(),
185                                                                                extra: Range::new(26, 2, 6, 28, 2, 8)
186                                                                            }
187                                                                        )
188                                                                    ]
189                                                                ),
190                                                                extra: Range::new(26, 2, 6, 28, 2, 8)
191                                                            },
192                                                        ),
193                                                        extra: Range::new(26, 2, 6, 28, 2, 8)
194                                                    }
195                                                ),
196                                                extra: Range::new(26, 2, 6, 28, 2, 8)
197                                            },
198                                            crate::puppet_lang::expression::Expression {
199                                                accessor: None,
200                                                comment: vec![],
201                                                value: crate::puppet_lang::expression::ExpressionVariant::Term(
202                                                    crate::puppet_lang::expression::Term {
203                                                        value: crate::puppet_lang::expression::TermVariant::String(
204                                                            crate::puppet_lang::string::StringExpr {
205                                                                data:
206                                                                crate::puppet_lang::string::StringVariant::SingleQuoted(
207                                                                    vec![
208                                                                        crate::puppet_lang::string::StringFragment::Literal(
209                                                                            crate::puppet_lang::string::Literal {
210                                                                                data: "bbb".to_owned(),
211                                                                                extra: Range::new(32, 2, 12, 34, 2, 14)
212                                                                            }
213                                                                        )
214                                                                    ]
215                                                                ),
216                                                                extra: Range::new(31, 2, 11, 35, 2, 15)
217                                                            },
218                                                        ),
219                                                        extra: Range::new(31, 2, 11, 35, 2, 15)
220                                                    }
221                                                ),
222                                                extra: Range::new(31, 2, 11, 35, 2, 15)
223                                            },
224                                            crate::puppet_lang::expression::Expression {
225                                                accessor: None,
226                                                comment: vec![],
227                                                value: crate::puppet_lang::expression::ExpressionVariant::Term(
228                                                    crate::puppet_lang::expression::Term {
229                                                        value: crate::puppet_lang::expression::TermVariant::String(
230                                                            crate::puppet_lang::string::StringExpr {
231                                                                data: crate::puppet_lang::string::StringVariant::DoubleQuoted(
232                                                                    vec![
233                                                                        crate::puppet_lang::string::DoubleQuotedFragment::StringFragment(
234                                                                            crate::puppet_lang::string::StringFragment::Literal(
235                                                                                crate::puppet_lang::string::Literal {
236                                                                                    data: "ccc".to_owned(),
237                                                                                    extra: Range::new(39, 2, 19, 41, 2, 21)
238                                                                                }
239                                                                            ))
240                                                                    ]),
241                                                                extra: Range::new(38, 2, 18, 42, 2, 22)
242                                                            },
243                                                        ),
244                                                        extra: Range::new(38, 2, 18, 42, 2, 22)
245                                                    }
246                                                ),
247                                                extra: Range::new(38, 2, 18, 42, 2, 22)
248                                            },
249                                        ],
250                                    }
251                                )
252                            ),
253                            extra: Range::new(22, 2, 2, 42, 2, 22),
254                        }
255                    ),
256                comment: vec![],
257            }]},
258            inherits: None,
259            extra: Range::new(0, 1, 1, 44, 2, 24),
260        }
261    );
262}
263
264#[test]
265fn test_body_require() {
266    assert_eq!(
267        parse_class(Span::new(
268            "class  abc::def () {\n require abc::def require zzz }\n"
269        ))
270            .unwrap()
271            .1,
272        Class {
273            identifier: LowerIdentifier {
274                name: vec!["abc".to_owned(), "def".to_owned()],
275                is_toplevel: false,
276                extra: Range::new(7, 1, 8, 14, 1, 15),
277            },
278            arguments: crate::puppet_lang::List::default(),
279            body: crate::puppet_lang::List {
280                last_comment: vec![],
281                value: vec![
282                    crate::puppet_lang::statement::Statement {
283                        value: crate::puppet_lang::statement::StatementVariant::Expression(
284                            crate::puppet_lang::expression::Expression {
285                                accessor: None,
286                                comment: vec![],
287                                value: crate::puppet_lang::expression::ExpressionVariant::BuiltinFunction(
288                                    crate::puppet_lang::builtin::BuiltinVariant::Require(crate::puppet_lang::builtin::Many1 {
289                                        args: vec![crate::puppet_lang::expression::Expression {
290                                            accessor: None,
291                                            comment: vec![],
292                                            value: crate::puppet_lang::expression::ExpressionVariant::Term(
293                                                crate::puppet_lang::expression::Term {
294                                                    value:
295                                                    crate::puppet_lang::expression::TermVariant::Identifier(
296                                                        LowerIdentifier {
297                                                            name: vec![
298                                                                "abc".to_owned(),
299                                                                "def".to_owned()
300                                                            ],
301                                                            is_toplevel: false,
302                                                            extra: Range::new(30, 2, 10, 37, 2, 17),
303                                                        }
304                                                    ),
305                                                    extra: Range::new(30, 2, 10, 37, 2, 17),
306                                                }
307                                            ),
308                                            extra: Range::new(30, 2, 10, 37, 2, 17),
309                                        }],
310                                        lambda: None,
311                                    },
312                                    )),
313                                extra: Range::new(22, 2, 2, 37, 2, 17),
314                            }
315                        ),
316                        comment: vec![],
317                    },
318                    crate::puppet_lang::statement::Statement {
319                        value: crate::puppet_lang::statement::StatementVariant::Expression(
320                            crate::puppet_lang::expression::Expression {
321                                accessor: None,
322                                comment: vec![],
323                                value: crate::puppet_lang::expression::ExpressionVariant::BuiltinFunction(
324                                    crate::puppet_lang::builtin::BuiltinVariant::Require(crate::puppet_lang::builtin::Many1 {
325                                        args: vec![crate::puppet_lang::expression::Expression {
326                                            accessor: None,
327                                            comment: vec![],
328                                            value: crate::puppet_lang::expression::ExpressionVariant::Term(
329                                                crate::puppet_lang::expression::Term {
330                                                    value: crate::puppet_lang::expression::TermVariant::String(
331                                                        crate::puppet_lang::string::StringExpr {
332                                                            data:
333                                                            crate::puppet_lang::string::StringVariant::SingleQuoted(
334                                                                vec![
335                                                                    crate::puppet_lang::string::StringFragment::Literal(
336                                                                        crate::puppet_lang::string::Literal {
337                                                                            data: "zzz".to_owned(),
338                                                                            extra: Range::new(47,2, 27, 49, 2, 29)
339                                                                        }
340                                                                    )
341                                                                ]
342                                                            ),
343                                                            extra: Range::new(47, 2, 27, 49, 2, 29),
344                                                        }
345                                                    ),
346                                                    extra: Range::new(47, 2, 27, 49, 2, 29)
347                                                }
348                                            ),
349                                            extra: Range::new(47, 2, 27, 49, 2, 29)
350                                        }],
351                                        lambda: None,
352                                    })),
353                                extra: Range::new(39, 2, 19, 49, 2, 29)
354                            }
355                        ),
356                        comment: vec![],
357                    }
358                ]},
359            inherits: None,
360            extra: Range::new(0, 1, 1, 51, 2, 31),
361        }
362    );
363}