1use super::*;
2
3#[derive(Debug, Clone, PartialEq)]
4pub enum ParameterKind {
5 Export,
6 Normal,
7 Variadic(VariadicType),
8}
9
10#[derive(Debug, Clone, PartialEq)]
11pub enum VariadicType {
12 OneOrMore,
13 ZeroOrMore,
14}
15
16#[derive(Debug, Clone, PartialEq)]
17pub struct Parameter {
18 pub content: String,
19 pub default_value: Option<String>,
20 pub kind: ParameterKind,
21 pub name: String,
22 pub range: lsp::Range,
23}
24
25#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
26pub struct ParameterJson {
27 pub default_value: Option<String>,
28 pub name: String,
29}
30
31impl From<Parameter> for ParameterJson {
32 fn from(parameter: Parameter) -> Self {
33 ParameterJson {
34 name: parameter.name,
35 default_value: parameter.default_value,
36 }
37 }
38}
39
40impl Parameter {
41 #[must_use]
42 pub fn from_node(node: &Node, document: &Document) -> Option<Self> {
43 let (parameter_node, kind) = if node.kind() == "variadic_parameter" {
44 let kleene = document.get_node_text(&node.child_by_field_name("kleene")?);
45
46 let kind = match kleene.as_str() {
47 "+" => ParameterKind::Variadic(VariadicType::OneOrMore),
48 "*" => ParameterKind::Variadic(VariadicType::ZeroOrMore),
49 _ => return None,
50 };
51
52 (node.find("^parameter")?, kind)
53 } else {
54 let kind = if node.child(0).is_some_and(|child| child.kind() == "$") {
55 ParameterKind::Export
56 } else {
57 ParameterKind::Normal
58 };
59
60 (*node, kind)
61 };
62
63 let name =
64 document.get_node_text(¶meter_node.child_by_field_name("name")?);
65
66 let default_value = parameter_node
67 .child_by_field_name("default")
68 .map(|node| document.get_node_text(&node));
69
70 Some(Parameter {
71 name,
72 kind,
73 default_value,
74 content: document.get_node_text(node).trim().to_string(),
75 range: node.get_range(document),
76 })
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use {super::*, pretty_assertions::assert_eq};
83
84 #[test]
85 fn parse_normal_parameter() {
86 assert_eq!(
87 Document::from("foo target:\n").recipes()[0].parameters,
88 vec![Parameter {
89 name: "target".to_string(),
90 kind: ParameterKind::Normal,
91 default_value: None,
92 content: "target".to_string(),
93 range: lsp::Range::at(0, 4, 0, 10),
94 }],
95 );
96 }
97
98 #[test]
99 fn parse_parameter_with_default() {
100 assert_eq!(
101 Document::from("foo tests=\"default\":\n").recipes()[0].parameters,
102 vec![Parameter {
103 name: "tests".to_string(),
104 kind: ParameterKind::Normal,
105 default_value: Some("\"default\"".to_string()),
106 content: "tests=\"default\"".to_string(),
107 range: lsp::Range::at(0, 4, 0, 19),
108 }],
109 );
110 }
111
112 #[test]
113 fn parse_parameter_with_complex_default() {
114 assert_eq!(
115 Document::from("foo triple=(arch + \"-unknown-unknown\"):\n").recipes()
116 [0]
117 .parameters,
118 vec![Parameter {
119 name: "triple".to_string(),
120 kind: ParameterKind::Normal,
121 default_value: Some("(arch + \"-unknown-unknown\")".to_string()),
122 content: "triple=(arch + \"-unknown-unknown\")".to_string(),
123 range: lsp::Range::at(0, 4, 0, 38),
124 }],
125 );
126 }
127
128 #[test]
129 fn parse_export_parameter() {
130 assert_eq!(
131 Document::from("foo $bar:\n").recipes()[0].parameters,
132 vec![Parameter {
133 name: "bar".to_string(),
134 kind: ParameterKind::Export,
135 default_value: None,
136 content: "$bar".to_string(),
137 range: lsp::Range::at(0, 4, 0, 8),
138 }],
139 );
140 }
141
142 #[test]
143 fn parse_variadic_one_or_more_parameter() {
144 assert_eq!(
145 Document::from("foo +FILES:\n").recipes()[0].parameters,
146 vec![Parameter {
147 name: "FILES".to_string(),
148 kind: ParameterKind::Variadic(VariadicType::OneOrMore),
149 default_value: None,
150 content: "+FILES".to_string(),
151 range: lsp::Range::at(0, 4, 0, 10),
152 }],
153 );
154 }
155
156 #[test]
157 fn parse_variadic_zero_or_more_parameter() {
158 assert_eq!(
159 Document::from("foo *FLAGS:\n").recipes()[0].parameters,
160 vec![Parameter {
161 name: "FLAGS".to_string(),
162 kind: ParameterKind::Variadic(VariadicType::ZeroOrMore),
163 default_value: None,
164 content: "*FLAGS".to_string(),
165 range: lsp::Range::at(0, 4, 0, 10),
166 }],
167 );
168 }
169
170 #[test]
171 fn parse_variadic_with_default() {
172 assert_eq!(
173 Document::from("foo +FLAGS='-q':\n").recipes()[0].parameters,
174 vec![Parameter {
175 name: "FLAGS".to_string(),
176 kind: ParameterKind::Variadic(VariadicType::OneOrMore),
177 default_value: Some("'-q'".to_string()),
178 content: "+FLAGS='-q'".to_string(),
179 range: lsp::Range::at(0, 4, 0, 15),
180 }],
181 );
182 }
183
184 #[test]
185 fn invalid_parameter_input() {
186 assert_eq!(Document::from("foo:\n").recipes()[0].parameters, vec![]);
187 assert_eq!(Document::from("foo $:\n").recipes()[0].parameters, vec![]);
188 assert_eq!(Document::from("foo +:\n").recipes()[0].parameters, vec![]);
189 assert_eq!(Document::from("foo *:\n").recipes()[0].parameters, vec![]);
190 }
191}