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
use crate::puppet_parser::{
common::{space0_delimimited, space1_delimimited},
{range::Range, IResult, ParseError, Span},
};
use nom::{
branch::alt,
bytes::complete::tag,
combinator::{eof, map, opt},
sequence::{pair, preceded, terminated, tuple},
};
use crate::puppet_lang::toplevel::{FunctionDef, Toplevel, ToplevelVariant};
pub fn parse_typedef(input: Span) -> IResult<crate::puppet_lang::toplevel::TypeDef<Range>> {
map(
tuple((
tag("type"),
space1_delimimited(crate::puppet_parser::identifier::camelcase_identifier_with_ns_located),
ParseError::protect(|_| "'=' expected".to_string(), tag("=")),
ParseError::protect(
|_| "Type specification expected".to_string(),
space0_delimimited(crate::puppet_parser::typing::parse_type_specification),
),
)),
|(keyword, identifier, _, value)| crate::puppet_lang::toplevel::TypeDef {
extra: Range::from((keyword, &value.extra)),
identifier,
value,
},
)(input)
}
pub fn parse_functiondef(input: Span) -> IResult<FunctionDef<Range>> {
map(
tuple((
tag("function"),
preceded(super::common::separator1, crate::puppet_parser::class::parse_header),
ParseError::protect(
|_| "'{' or '>>' expected".to_string(),
pair(
space0_delimimited(opt(preceded(
tag(">>"),
ParseError::protect(
|_| "Failed to parse return type".to_owned(),
space0_delimimited(crate::puppet_parser::typing::parse_type_specification),
),
))),
crate::puppet_parser::statement::parse_statement_block,
),
),
)),
|(keyword, (identifier, arguments), (return_type, (_left_curly, body, right_curly)))| {
FunctionDef {
identifier,
arguments,
return_type,
body,
extra: Range::from((keyword, right_curly)),
}
},
)(input)
}
pub fn parse(input: Span) -> IResult<Toplevel<Range>> {
crate::puppet_parser::common::space0_delimimited(alt((
map(crate::puppet_parser::class::parse_class, |v| Toplevel {
extra: v.extra.clone(),
data: ToplevelVariant::Class(v),
}),
map(crate::puppet_parser::class::parse_definition, |v| Toplevel {
extra: v.extra.clone(),
data: ToplevelVariant::Definition(v),
}),
map(crate::puppet_parser::class::parse_plan, |v| Toplevel {
extra: v.extra.clone(),
data: ToplevelVariant::Plan(v),
}),
map(parse_typedef, |v| Toplevel {
extra: v.extra.clone(),
data: ToplevelVariant::TypeDef(v),
}),
map(parse_functiondef, |v| Toplevel {
extra: v.extra.clone(),
data: ToplevelVariant::FunctionDef(v),
}),
)))(input)
}
pub fn parse_file(
input: Span,
) -> IResult<crate::puppet_lang::List<Range, crate::puppet_lang::statement::Statement<Range>>> {
terminated(crate::puppet_parser::statement::parse_statement_list, eof)(input)
}
#[test]
fn test_toplevel() {
assert!(crate::puppet_parser::statement::parse_statement_list(Span::new(
"# @summary Install and enroll client to freeipa cluster
#
# A description of what this class does
#
# @example
# include freeipa::install::client
class freeipa::install::client {
}"
))
.is_ok())
}
#[test]
fn test_function() {
assert!(parse(Span::new("function abc::def () {}")).is_ok());
assert!(parse(Span::new("function abc::def ($a, $b) {}")).is_ok());
assert!(parse(Span::new("function abc::def ($a, $b) >> String {}")).is_ok());
}