htmls/interpreter/
function.rs

1use crate::{FunctionNode, parser::ast::Literal};
2
3use super::{Interpreter, InterpreterError, InterpreterResult};
4
5pub fn apply_function(it: &mut Interpreter, node: &FunctionNode) -> InterpreterResult<()> {
6    let texts = it.result.texts_mut()?;
7
8    match node.name.as_str() {
9        "trim" => trim(texts),
10        "replace" => {
11            if node.arguments.len() != 2 {
12                return Err(InterpreterError::MissingArgument(
13                    "repalce must include 2 argument.".to_string(),
14                ));
15            };
16            let value0 = match &node.arguments[0] {
17                Literal::Str(v) => v,
18                _ => {
19                    return Err(InterpreterError::InvalidArgument(
20                        "The first parameter of replace expects a value of type str.".to_string(),
21                    ));
22                }
23            };
24            let value1 = match &node.arguments[1] {
25                Literal::Str(v) => v,
26                _ => {
27                    return Err(InterpreterError::InvalidArgument(
28                        "The 2th parameter of replace expects a value of type str.".to_string(),
29                    ));
30                }
31            };
32            replace(texts, value0, value1)
33        }
34        "lowercase" => lowercase(texts),
35        "uppercase" => uppercase(texts),
36        "join" => {
37            let value0 = if node.arguments.len() == 1 {
38                match &node.arguments[0] {
39                    Literal::Str(v) => v,
40                    _ => {
41                        return Err(InterpreterError::InvalidArgument(
42                            "join expects a value of type str".to_string(),
43                        ));
44                    }
45                }
46            } else if node.arguments.len() == 0 {
47                ""
48            } else {
49                return Err(InterpreterError::MissingArgument(
50                    "join must include 0 or 1 argument.".to_string(),
51                ));
52            };
53            join(texts, value0)
54        }
55        "format" => {
56            let value0 = if node.arguments.len() == 1 {
57                match &node.arguments[0] {
58                    Literal::Str(v) => v,
59                    _ => {
60                        return Err(InterpreterError::InvalidArgument(
61                            "format expect a value of type str".to_string(),
62                        ));
63                    }
64                }
65            } else {
66                return Err(InterpreterError::MissingArgument(
67                    "format must include 1 argument.".to_string(),
68                ));
69            };
70            format(texts, value0)
71        }
72        "contains" => {
73            let value0 = if node.arguments.len() == 1 {
74                match &node.arguments[0] {
75                    Literal::Str(v) => v,
76                    _ => {
77                        return Err(InterpreterError::InvalidArgument(
78                            "contains expect a value of type str".to_string(),
79                        ));
80                    }
81                }
82            } else {
83                return Err(InterpreterError::MissingArgument(
84                    "contains must include 1 argument.".to_string(),
85                ));
86            };
87            contains(texts, value0);
88        }
89        "starts_with" => {
90            let value0 = if node.arguments.len() == 1 {
91                match &node.arguments[0] {
92                    Literal::Str(v) => v,
93                    _ => {
94                        return Err(InterpreterError::InvalidArgument(
95                            "starts_with expect a value of type str".to_string(),
96                        ));
97                    }
98                }
99            } else {
100                return Err(InterpreterError::MissingArgument(
101                    "starts_with must include 1 argument.".to_string(),
102                ));
103            };
104            starts_with(texts, value0);
105        }
106        "ends_with" => {
107            let value0 = if node.arguments.len() == 1 {
108                match &node.arguments[0] {
109                    Literal::Str(v) => v,
110                    _ => {
111                        return Err(InterpreterError::InvalidArgument(
112                            "ends_with expect a value of type str".to_string(),
113                        ));
114                    }
115                }
116            } else {
117                return Err(InterpreterError::MissingArgument(
118                    "ends_with must include 1 argument.".to_string(),
119                ));
120            };
121            ends_with(texts, value0);
122        }
123        "in" => {
124            let value0 = if node.arguments.len() == 1 {
125                match &node.arguments[0] {
126                    Literal::List(list) => {
127                        let mut values = Vec::new();
128                        for item in list {
129                            match item {
130                                Literal::Str(v) => values.push(v.clone()),
131                                _ => {
132                                    return Err(InterpreterError::InvalidArgument(
133                                        "in expect a value of type list<str>".to_string(),
134                                    ));
135                                }
136                            };
137                        }
138                        values
139                    }
140                    _ => {
141                        return Err(InterpreterError::InvalidArgument(
142                            "in expect a value of type list<str>".to_string(),
143                        ));
144                    }
145                }
146            } else {
147                return Err(InterpreterError::MissingArgument(
148                    "in must include 1 argument.".to_string(),
149                ));
150            };
151
152            in_(texts, value0);
153        }
154        "slice" => {
155            if node.arguments.len() != 2 {
156                return Err(InterpreterError::MissingArgument(
157                    "slice must include 2 argument.".to_string(),
158                ));
159            };
160
161            let st = match &node.arguments[0] {
162                Literal::Int(n) => {
163                    if *n < 0 {
164                        return Err(InterpreterError::InvalidArgument(
165                            "slice's parameter must be greater than or equal to 0.".to_string(),
166                        ));
167                    };
168                    Some(*n as usize)
169                }
170                Literal::Nil => None,
171                _ => {
172                    return Err(InterpreterError::InvalidArgument(
173                        "slice expect a value of type int".to_string(),
174                    ));
175                }
176            };
177
178            let ed = match &node.arguments[1] {
179                Literal::Int(n) => {
180                    if *n < 0 {
181                        return Err(InterpreterError::InvalidArgument(
182                            "slice's parameter must be greater than or equal to 0.".to_string(),
183                        ));
184                    };
185                    Some(*n as usize)
186                }
187                Literal::Nil => None,
188                _ => {
189                    return Err(InterpreterError::InvalidArgument(
190                        "slice expect a value of type int".to_string(),
191                    ));
192                }
193            };
194
195            slice(texts, st, ed);
196        }
197        _ => return Err(InterpreterError::UnknownFunction(node.name.clone())),
198    };
199
200    Ok(())
201}
202
203fn trim(texts: &mut Vec<String>) {
204    texts
205        .iter_mut()
206        .for_each(|text| *text = text.trim().to_string());
207}
208
209fn replace(texts: &mut Vec<String>, search: &str, replacement: &str) {
210    texts
211        .iter_mut()
212        .for_each(|text| *text = text.replace(search, replacement))
213}
214
215fn lowercase(texts: &mut Vec<String>) {
216    texts
217        .iter_mut()
218        .for_each(|text| *text = text.to_lowercase())
219}
220
221fn uppercase(texts: &mut Vec<String>) {
222    texts
223        .iter_mut()
224        .for_each(|text| *text = text.to_uppercase())
225}
226
227fn join(texts: &mut Vec<String>, separator: &str) {
228    *texts = vec![texts.join(separator)]
229}
230
231fn format(texts: &mut Vec<String>, format_str: &str) {
232    texts.iter_mut().for_each(|text| {
233        if format_str.contains("{}") {
234            *text = format!("{}", format_str.replacen("{}", &text, 1));
235        } else if format_str.starts_with("%") {
236            match format_str {
237                "%s" => { /* Keep as is, equivalent to {} */ }
238                "%d" | "%i" => {
239                    if let Ok(num) = text.trim().parse::<i64>() {
240                        *text = num.to_string();
241                    }
242                }
243                "%f" => {
244                    if let Ok(num) = text.trim().parse::<f64>() {
245                        *text = num.to_string();
246                    }
247                }
248                "%x" => {
249                    if let Ok(num) = text.trim().parse::<i64>() {
250                        *text = format!("{:x}", num);
251                    }
252                }
253                "%X" => {
254                    if let Ok(num) = text.trim().parse::<i64>() {
255                        *text = format!("{:X}", num);
256                    }
257                }
258                _ => {
259                    *text = format!("{}{}", format_str, text);
260                }
261            }
262        } else {
263            *text = format!("{}{}", format_str, text);
264        }
265    })
266}
267
268fn contains(texts: &mut Vec<String>, inner: &str) {
269    let mut result = Vec::new();
270
271    for text in texts.iter() {
272        if text.contains(inner) {
273            result.push(text.clone());
274        }
275    }
276
277    *texts = result;
278}
279
280fn starts_with(texts: &mut Vec<String>, st: &str) {
281    let mut result = Vec::new();
282
283    for text in texts.iter() {
284        if text.starts_with(st) {
285            result.push(text.clone());
286        }
287    }
288
289    *texts = result;
290}
291
292fn ends_with(texts: &mut Vec<String>, ed: &str) {
293    let mut result = Vec::new();
294
295    for text in texts.iter() {
296        if text.ends_with(ed) {
297            result.push(text.clone());
298        }
299    }
300
301    *texts = result;
302}
303
304fn in_(texts: &mut Vec<String>, list: Vec<String>) {
305    let mut result = Vec::new();
306    for text in texts.iter() {
307        if list.contains(text) {
308            result.push(text.clone());
309        }
310    }
311
312    *texts = result;
313}
314
315fn slice(tests: &mut Vec<String>, st: Option<usize>, ed: Option<usize>) {
316    tests.iter_mut().for_each(|text| {
317        let mut st = st.unwrap_or(0);
318        let mut ed = ed.unwrap_or(text.len());
319        if ed > text.len() {
320            ed = text.len();
321        };
322
323        if st > ed {
324            if st > text.len() {
325                st = text.len();
326            }
327            let temp = st;
328            st = ed;
329            ed = temp;
330        }
331
332        if let Some(t) = text.get(st..ed) {
333            *text = t.to_string();
334        }
335    });
336}