1use std::{
21 collections::HashMap,
22 fmt::{Debug, Display},
23 sync::Arc,
24};
25
26use brooks_macros::builtin_function_interpreter;
27
28use crate::{
29 environment::scope::Scope,
30 mel::{
31 interpreter::{
32 error::BuiltinInterpError,
33 interpret::BuiltinFunction,
34 values::{TypedValue, Value},
35 },
36 types::{
37 Add_Query_MultiBuiltin, Add_QueryBuiltin, BooleanBuiltin, BuiltinFunctionType,
38 IntegerBuiltin, Keep_Query_MultiBuiltin, LowerBuiltin, Match_ReplaceBuiltin,
39 MatchBuiltin, Path_ElementBuiltin, Path_ElementsBuiltin, RealBuiltin,
40 Remove_Query_MultiBuiltin, Remove_QueryBuiltin, StringBuiltin, Type, UnsignedBuiltin,
41 UpperBuiltin,
42 },
43 },
44};
45
46type BuiltinInterpResult = Result<TypedValue, Box<BuiltinInterpError>>;
47
48pub trait BuiltinFunctionInterpreter: Debug {
49 fn interpw(&self, args: Value) -> BuiltinInterpResult;
50}
51
52#[builtin_function_interpreter(Type::String, Type::String, Type::Integer)]
53impl Path_ElementBuiltin {
54 fn interp(&self, path: &str, element: &i64) -> BuiltinInterpResult {
55 let parts = path.split("/");
56
57 if (*element as usize) < parts.clone().count() {
58 let part =
59 parts
60 .clone()
61 .nth((*element) as usize)
62 .ok_or(BuiltinInterpError::RuntimeError(format!(
63 "Index {} is out of bounds (max {})",
64 element,
65 parts.count()
66 )))?;
67 Ok(TypedValue {
68 value: Value::String(part.to_string()),
69 tpe: Type::String,
70 })
71 } else {
72 Err(BuiltinInterpError::RuntimeError(format!(
73 "Index {} is out of bounds (max {})",
74 element,
75 parts.count()
76 ))
77 .into())
78 }
79 }
80}
81
82#[builtin_function_interpreter(Type::String, Type::String, Type::Integer, Type::Integer)]
83impl Path_ElementsBuiltin {
84 fn interp(&self, path: &str, element_n: &i64, element_m: &i64) -> BuiltinInterpResult {
85 let parts = path.split("/");
86
87 let element_n = *element_n as usize;
88 let element_m = *element_m as usize;
89
90 if element_m < element_n {
91 return Err(BuiltinInterpError::RuntimeError(format!(
92 "Cannot access elements from {element_n} to {element_m} -- out of order",
93 ))
94 .into());
95 }
96
97 let result = parts.skip(element_n).take(element_m - element_n + 1); Ok(TypedValue {
100 value: Value::String(result.collect::<Vec<_>>().join("/")),
101 tpe: Type::String,
102 })
103 }
104}
105
106#[builtin_function_interpreter(Type::String, Type::String, Type::String)]
107impl MatchBuiltin {
108 fn interp(&self, input: &str, mtch: &str) -> BuiltinInterpResult {
109 let re = regex::RegexBuilder::new(mtch).build().map_err(|_| {
110 BuiltinInterpError::RuntimeError(format!("{mtch} is not a valid regular expression"))
112 })?;
113
114 let result = match re.find(input) {
115 Some(found) => found.as_str().to_string(),
116 None => "".to_string(),
117 };
118 Ok(TypedValue {
119 value: Value::String(result),
120 tpe: Type::String,
121 })
122 }
123}
124
125#[builtin_function_interpreter(Type::String, Type::String, Type::String, Type::String)]
126impl Match_ReplaceBuiltin {
127 fn interp(&self, input: &str, mtch: &str, replace: &str) -> BuiltinInterpResult {
128 let re = regex::RegexBuilder::new(mtch).build().map_err(|_| {
129 BuiltinInterpError::RuntimeError(format!("{mtch} is not a valid regular expression"))
131 })?;
132
133 let result = re.replace(input, replace);
134
135 Ok(TypedValue {
136 value: Value::String(result.to_string()),
137 tpe: Type::String,
138 })
139 }
140}
141
142#[derive(Debug, Clone, Default)]
143struct ParsedQuery {
144 elems: HashMap<String, String>,
145 order: Vec<String>,
146}
147
148impl TryFrom<&str> for ParsedQuery {
149 type Error = BuiltinInterpError;
150
151 fn try_from(value: &str) -> Result<Self, Self::Error> {
152 let sequences = value.split('&');
154 let mut elems: HashMap<String, String> = HashMap::new();
155 let mut order: Vec<String> = vec![];
156 for bytes in sequences {
157 if bytes.is_empty() {
158 continue;
159 }
160
161 let (name, value) = match bytes.split_once('=') {
162 None => (bytes.to_string(), "".to_string()),
163 Some((n, v)) => (n.to_string(), v.to_string()),
164 };
165
166 elems.insert(name.clone(), value);
167 order.push(name);
168 }
169
170 Ok(ParsedQuery { elems, order })
171 }
172}
173
174impl Display for ParsedQuery {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 let res: Vec<_> = self
177 .order
178 .iter()
179 .map(|e| {
180 if let Some((k, v)) = self.elems.get_key_value(e) {
181 let rest = if !v.is_empty() {
182 format!("={v}")
183 } else {
184 "".to_string()
185 };
186 k.to_string() + &rest
187 } else {
188 "".to_string()
189 }
190 })
191 .filter(|e| !e.is_empty())
192 .collect();
193
194 write!(f, "{}", res.join("&"))
195 }
196}
197
198#[builtin_function_interpreter(Type::String, Type::String, Type::String, Type::String)]
199impl Add_QueryBuiltin {
200 fn interp(&self, existing: &str, newq: &str, newv: &str) -> BuiltinInterpResult {
201 let mut pq = ParsedQuery::try_from(existing)?;
202
203 if pq
204 .elems
205 .insert(newq.to_string(), newv.to_string())
206 .is_none()
207 {
208 pq.order.push(newq.to_string())
209 }
210
211 Ok(TypedValue {
212 value: Value::String(pq.to_string()),
213 tpe: Type::String,
214 })
215 }
216}
217
218fn parse_multi_kv(i: &str) -> Vec<(String, Option<String>)> {
219 parse_multi_k(i)
220 .into_iter()
221 .map(|newi| {
222 let newi = newi.trim();
223 if let Some((n, v)) = newi.split_once('=') {
224 let n = n.trim();
225 let v = v.trim();
226 Some((
227 n.to_owned(),
228 if v.is_empty() {
229 None
230 } else {
231 Some(v.to_owned())
232 },
233 ))
234 } else {
235 None
236 }
237 })
238 .filter(|f| f.is_some())
239 .flatten()
240 .collect()
241}
242
243fn parse_multi_k(i: &str) -> Vec<String> {
244 i.split(',')
245 .map(|newi| {
246 let newi = newi.trim();
247 if !newi.is_empty() {
248 Some(newi.to_owned())
249 } else {
250 None
251 }
252 })
253 .filter(|f| f.is_some())
254 .flatten()
255 .collect()
256}
257
258#[builtin_function_interpreter(Type::String, Type::String, Type::String)]
259impl Add_Query_MultiBuiltin {
260 fn interp(&self, existing: &str, news: &str) -> BuiltinInterpResult {
261 let mut pq = ParsedQuery::try_from(existing)?;
262
263 for (n, v) in parse_multi_kv(news) {
264 if let Some(v) = v
265 && pq.elems.insert(n.to_string(), v).is_none()
266 {
267 pq.order.push(n.to_string())
268 };
269 }
270
271 Ok(TypedValue {
272 value: Value::String(pq.to_string()),
273 tpe: Type::String,
274 })
275 }
276}
277
278#[builtin_function_interpreter(Type::String, Type::String, Type::String)]
279impl Remove_QueryBuiltin {
280 fn interp(&self, existing: &str, oldq: &str) -> BuiltinInterpResult {
281 let mut pq = ParsedQuery::try_from(existing)?;
282
283 pq.elems.remove(oldq);
284
285 Ok(TypedValue {
286 value: Value::String(pq.to_string()),
287 tpe: Type::String,
288 })
289 }
290}
291
292#[builtin_function_interpreter(Type::String, Type::String, Type::String)]
293impl Remove_Query_MultiBuiltin {
294 fn interp(&self, existing: &str, olds: &str) -> BuiltinInterpResult {
295 let mut pq = ParsedQuery::try_from(existing)?;
296
297 for oldi in parse_multi_k(olds) {
298 pq.elems.remove(&oldi);
299 }
300
301 Ok(TypedValue {
302 value: Value::String(pq.to_string()),
303 tpe: Type::String,
304 })
305 }
306}
307
308#[builtin_function_interpreter(Type::String, Type::String, Type::String)]
309impl Keep_Query_MultiBuiltin {
310 fn interp(&self, existing: &str, keeps: &str) -> BuiltinInterpResult {
311 let mut pq = ParsedQuery::try_from(existing)?;
312
313 let keep: Vec<_> = parse_multi_k(keeps);
315 let keys: Vec<_> = pq.elems.keys().cloned().collect();
316
317 for k in keys {
318 if !keep.contains(&k) {
319 pq.elems.remove(&k);
320 }
321 }
322
323 Ok(TypedValue {
324 value: Value::String(pq.to_string()),
325 tpe: Type::String,
326 })
327 }
328}
329
330#[builtin_function_interpreter(Type::String, Type::String)]
331impl UpperBuiltin {
332 fn interp(&self, s: &str) -> BuiltinInterpResult {
333 Ok(TypedValue {
334 value: Value::String(s.to_uppercase()),
335 tpe: Type::String,
336 })
337 }
338}
339
340#[builtin_function_interpreter(Type::String, Type::String)]
341impl LowerBuiltin {
342 fn interp(&self, s: &str) -> BuiltinInterpResult {
343 Ok(TypedValue {
344 value: Value::String(s.to_lowercase()),
345 tpe: Type::String,
346 })
347 }
348}
349
350impl BuiltinFunctionInterpreter for BooleanBuiltin {
351 fn interpw(&self, args: Value) -> BuiltinInterpResult {
352 let args = match args {
353 Value::ArgumentList(args) => args,
354 _ => return Err(BuiltinInterpError::ArgumentsInvalid.into()),
355 };
356
357 if args.len() != 1 {
358 return Err(BuiltinInterpError::ArgumentMiscount(1, args.len()).into());
359 }
360
361 let arg = &args[0];
362
363 let result = match arg {
364 TypedValue {
365 value: Value::Nil,
366 tpe: Type::Nil,
367 } => TypedValue {
368 value: Value::Boolean(false),
369 tpe: Type::Boolean,
370 },
371 TypedValue {
372 value: Value::String(s),
373 tpe: Type::String,
374 } => TypedValue {
375 value: Value::Boolean(!s.is_empty()),
376 tpe: Type::Boolean,
377 },
378 TypedValue {
379 value: Value::Integer(i),
380 tpe: Type::Integer,
381 } => TypedValue {
382 value: Value::Boolean(*i != 0),
383 tpe: Type::Boolean,
384 },
385 TypedValue {
386 value: Value::Real(r),
387 tpe: Type::Real,
388 } => TypedValue {
389 value: Value::Boolean(*r != 0.0),
390 tpe: Type::Boolean,
391 },
392 b @ TypedValue {
393 value: Value::Boolean(_),
394 tpe: Type::Boolean,
395 } => b.clone(),
396 TypedValue { value: _, tpe: t } => {
397 return Err(BuiltinInterpError::RuntimeError(format!(
398 "Semantics of calling boolean on an argument with type {t} are undefined"
399 ))
400 .into());
401 }
402 };
403 Ok(result)
404 }
405}
406
407impl BuiltinFunctionInterpreter for IntegerBuiltin {
408 fn interpw(&self, args: Value) -> BuiltinInterpResult {
409 let args = match args {
410 Value::ArgumentList(args) => args,
411 _ => return Err(BuiltinInterpError::ArgumentsInvalid.into()),
412 };
413
414 if args.len() != 1 {
415 return Err(BuiltinInterpError::ArgumentMiscount(1, args.len()).into());
416 }
417
418 let arg = &args[0];
421
422 let result = match arg {
423 TypedValue {
424 value: Value::Nil,
425 tpe: Type::Nil,
426 } => TypedValue {
427 value: Value::Integer(0),
428 tpe: Type::Integer,
429 },
430 TypedValue {
431 value: Value::String(s),
432 tpe: Type::String,
433 } => s.parse().map_or(
434 TypedValue {
435 value: Value::Nil,
436 tpe: Type::Nil,
437 },
438 |v| TypedValue {
439 value: Value::Integer(v),
440 tpe: Type::Integer,
441 },
442 ),
443 v @ TypedValue {
444 value: Value::Integer(_),
445 tpe: Type::Integer,
446 } => v.clone(),
447 TypedValue {
448 value: Value::Real(r),
449 tpe: Type::Real,
450 } => TypedValue {
451 value: Value::Integer(*r as i64),
452 tpe: Type::Integer,
453 },
454 TypedValue {
455 value: Value::Boolean(b),
456 tpe: Type::Boolean,
457 } => TypedValue {
458 value: Value::Integer(if *b { 1 } else { 0 }),
459 tpe: Type::Integer,
460 },
461 TypedValue { value: _, tpe: t } => {
462 return Err(BuiltinInterpError::RuntimeError(format!(
463 "Semantics of calling integer on an argument with type {t} are undefined"
464 ))
465 .into());
466 }
467 };
468 Ok(result)
469 }
470}
471
472impl BuiltinFunctionInterpreter for UnsignedBuiltin {
473 fn interpw(&self, args: Value) -> BuiltinInterpResult {
474 let args = match args {
475 Value::ArgumentList(args) => args,
476 _ => return Err(BuiltinInterpError::ArgumentsInvalid.into()),
477 };
478
479 if args.len() != 1 {
480 return Err(BuiltinInterpError::ArgumentMiscount(1, args.len()).into());
481 }
482
483 let arg = &args[0];
484
485 let result = match arg {
486 TypedValue {
487 value: Value::Nil,
488 tpe: Type::Nil,
489 } => TypedValue {
490 value: Value::Unsigned(0),
491 tpe: Type::Unsigned,
492 },
493 TypedValue {
494 value: Value::String(s),
495 tpe: Type::String,
496 } => {
497 if s.starts_with("0x") {
498 u64::from_str_radix(s.trim_start_matches("0x"), 16).map_or(
499 TypedValue {
500 value: Value::Nil,
501 tpe: Type::Nil,
502 },
503 |v| TypedValue {
504 value: Value::Unsigned(v),
505 tpe: Type::Unsigned,
506 },
507 )
508 } else {
509 s.parse().map_or(
510 TypedValue {
511 value: Value::Nil,
512 tpe: Type::Nil,
513 },
514 |v| TypedValue {
515 value: Value::Unsigned(v),
516 tpe: Type::Unsigned,
517 },
518 )
519 }
520 }
521 TypedValue {
522 value: Value::Integer(value),
523 tpe: Type::Integer,
524 } => {
525 if *value >= 0 {
526 TypedValue {
527 value: Value::Unsigned(*value as u64),
528 tpe: Type::Unsigned,
529 }
530 } else {
531 TypedValue {
532 value: Value::Unsigned(0),
533 tpe: Type::Unsigned,
534 }
535 }
536 }
537 TypedValue {
538 value: Value::Real(r),
539 tpe: Type::Real,
540 } => {
541 if *r >= 0.0 {
542 TypedValue {
543 value: Value::Unsigned(*r as u64),
544 tpe: Type::Unsigned,
545 }
546 } else {
547 TypedValue {
548 value: Value::Unsigned(0),
549 tpe: Type::Unsigned,
550 }
551 }
552 }
553 TypedValue {
554 value: Value::Boolean(b),
555 tpe: Type::Boolean,
556 } => TypedValue {
557 value: Value::Unsigned(if *b { 1 } else { 0 }),
558 tpe: Type::Unsigned,
559 },
560 TypedValue { value: _, tpe: t } => {
561 return Err(BuiltinInterpError::RuntimeError(format!(
562 "Semantics of calling integer on an argument with type {t} are undefined"
563 ))
564 .into());
565 }
566 };
567 Ok(result)
568 }
569}
570
571impl BuiltinFunctionInterpreter for RealBuiltin {
572 fn interpw(&self, args: Value) -> BuiltinInterpResult {
573 let args = match args {
574 Value::ArgumentList(args) => args,
575 _ => return Err(BuiltinInterpError::ArgumentsInvalid.into()),
576 };
577
578 if args.len() != 1 {
579 return Err(BuiltinInterpError::ArgumentMiscount(1, args.len()).into());
580 }
581
582 let arg = &args[0];
583
584 let result = match arg {
585 TypedValue {
586 value: Value::Nil,
587 tpe: Type::Nil,
588 } => TypedValue {
589 value: Value::Real(0.0),
590 tpe: Type::Real,
591 },
592 TypedValue {
593 value: Value::String(s),
594 tpe: Type::String,
595 } => s.parse().map_or(
596 TypedValue {
597 value: Value::Nil,
598 tpe: Type::Nil,
599 },
600 |v| TypedValue {
601 value: Value::Real(v),
602 tpe: Type::Real,
603 },
604 ),
605 TypedValue {
606 value: Value::Integer(value),
607 tpe: Type::Integer,
608 } => TypedValue {
609 value: Value::Real(*value as f64),
610 tpe: Type::Real,
611 },
612 r @ TypedValue {
613 value: Value::Real(_),
614 tpe: Type::Real,
615 } => r.clone(),
616 TypedValue {
617 value: Value::Boolean(b),
618 tpe: Type::Boolean,
619 } => TypedValue {
620 value: Value::Real(if *b { 1.0 } else { 0.0 }),
621 tpe: Type::Real,
622 },
623 TypedValue { value: _, tpe: t } => {
624 return Err(BuiltinInterpError::RuntimeError(format!(
625 "Semantics of calling integer on an argument with type {t} are undefined"
626 ))
627 .into());
628 }
629 };
630 Ok(result)
631 }
632}
633
634impl BuiltinFunctionInterpreter for StringBuiltin {
635 fn interpw(&self, args: Value) -> BuiltinInterpResult {
636 let args = match args {
637 Value::ArgumentList(args) => args,
638 _ => return Err(BuiltinInterpError::ArgumentsInvalid.into()),
639 };
640
641 if args.len() != 1 {
642 return Err(BuiltinInterpError::ArgumentMiscount(1, args.len()).into());
643 }
644
645 Ok(TypedValue {
646 value: Value::String(args[0].to_string()),
647 tpe: Type::String,
648 })
649 }
650}
651
652macro_rules! add_builtin_function_interpreter_to_scope {
653 ($scope:ident, $builtin:ident) => {
654 $scope.insert(
655 &$builtin.name(),
656 TypedValue {
657 value: Value::Function(Arc::new($builtin.clone())),
658 tpe: Type::Function(
659 $builtin.name(),
660 $builtin.return_type_calculator(),
661 $builtin.params_type_checker(),
662 ),
663 },
664 )
665 };
666}
667
668pub fn builtin_builtin_function_interpreters() -> Scope<TypedValue> {
670 let path_element = Path_ElementBuiltin {};
671 let path_elements = Path_ElementsBuiltin {};
672 let mtch = MatchBuiltin {};
673 let match_replace = Match_ReplaceBuiltin {};
674 let add_query = Add_QueryBuiltin {};
675 let add_query_multi = Add_Query_MultiBuiltin {};
676 let remove_query = Remove_QueryBuiltin {};
677 let remove_query_multi = Remove_Query_MultiBuiltin {};
678 let keep_query_multi = Keep_Query_MultiBuiltin {};
679 let lower = LowerBuiltin {};
680 let upper = UpperBuiltin {};
681
682 let boolean = BooleanBuiltin {};
684 let integer = IntegerBuiltin {};
685 let unsigned = UnsignedBuiltin {};
686 let string = StringBuiltin {};
687 let real = RealBuiltin {};
688
689 let mut scopes = Scope::<TypedValue>::default();
690
691 scopes = add_builtin_function_interpreter_to_scope!(scopes, path_element);
692 scopes = add_builtin_function_interpreter_to_scope!(scopes, path_elements);
693 scopes = add_builtin_function_interpreter_to_scope!(scopes, mtch);
694 scopes = add_builtin_function_interpreter_to_scope!(scopes, match_replace);
695 scopes = add_builtin_function_interpreter_to_scope!(scopes, add_query);
696 scopes = add_builtin_function_interpreter_to_scope!(scopes, add_query_multi);
697 scopes = add_builtin_function_interpreter_to_scope!(scopes, remove_query);
698 scopes = add_builtin_function_interpreter_to_scope!(scopes, remove_query_multi);
699 scopes = add_builtin_function_interpreter_to_scope!(scopes, keep_query_multi);
700 scopes = add_builtin_function_interpreter_to_scope!(scopes, lower);
701 scopes = add_builtin_function_interpreter_to_scope!(scopes, upper);
702
703 scopes = add_builtin_function_interpreter_to_scope!(scopes, boolean);
704 scopes = add_builtin_function_interpreter_to_scope!(scopes, integer);
705 scopes = add_builtin_function_interpreter_to_scope!(scopes, unsigned);
706 scopes = add_builtin_function_interpreter_to_scope!(scopes, string);
707 scopes = add_builtin_function_interpreter_to_scope!(scopes, real);
708 scopes
709}