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}