1use std::ascii;
18use std::collections::HashMap;
19use std::fmt;
20use std::slice;
21
22use itertools::Itertools as _;
23use pest::RuleType;
24use pest::iterators::Pair;
25use pest::iterators::Pairs;
26
27#[derive(Debug)]
32pub struct Diagnostics<T> {
33 diagnostics: Vec<T>,
35}
36
37impl<T> Diagnostics<T> {
38 pub fn new() -> Self {
40 Self {
41 diagnostics: Vec::new(),
42 }
43 }
44
45 pub fn is_empty(&self) -> bool {
47 self.diagnostics.is_empty()
48 }
49
50 pub fn len(&self) -> usize {
52 self.diagnostics.len()
53 }
54
55 pub fn iter(&self) -> slice::Iter<'_, T> {
57 self.diagnostics.iter()
58 }
59
60 pub fn add_warning(&mut self, diag: T) {
62 self.diagnostics.push(diag);
63 }
64
65 pub fn extend_with<U>(&mut self, diagnostics: Diagnostics<U>, mut f: impl FnMut(U) -> T) {
68 self.diagnostics
69 .extend(diagnostics.diagnostics.into_iter().map(&mut f));
70 }
71}
72
73impl<T> Default for Diagnostics<T> {
74 fn default() -> Self {
75 Self::new()
76 }
77}
78
79impl<'a, T> IntoIterator for &'a Diagnostics<T> {
80 type Item = &'a T;
81 type IntoIter = slice::Iter<'a, T>;
82
83 fn into_iter(self) -> Self::IntoIter {
84 self.iter()
85 }
86}
87
88#[derive(Clone, Debug, Eq, PartialEq)]
90pub struct ExpressionNode<'i, T> {
91 pub kind: T,
93 pub span: pest::Span<'i>,
95}
96
97impl<'i, T> ExpressionNode<'i, T> {
98 pub fn new(kind: T, span: pest::Span<'i>) -> Self {
100 Self { kind, span }
101 }
102}
103
104#[derive(Clone, Debug, Eq, PartialEq)]
106pub struct FunctionCallNode<'i, T> {
107 pub name: &'i str,
109 pub name_span: pest::Span<'i>,
111 pub args: Vec<ExpressionNode<'i, T>>,
113 pub keyword_args: Vec<KeywordArgument<'i, T>>,
115 pub args_span: pest::Span<'i>,
117}
118
119#[derive(Clone, Debug, Eq, PartialEq)]
121pub struct KeywordArgument<'i, T> {
122 pub name: &'i str,
124 pub name_span: pest::Span<'i>,
126 pub value: ExpressionNode<'i, T>,
128}
129
130impl<'i, T> FunctionCallNode<'i, T> {
131 pub fn arity(&self) -> usize {
133 self.args.len() + self.keyword_args.len()
134 }
135
136 pub fn expect_no_arguments(&self) -> Result<(), InvalidArguments<'i>> {
138 let ([], []) = self.expect_arguments()?;
139 Ok(())
140 }
141
142 pub fn expect_exact_arguments<const N: usize>(
144 &self,
145 ) -> Result<&[ExpressionNode<'i, T>; N], InvalidArguments<'i>> {
146 let (args, []) = self.expect_arguments()?;
147 Ok(args)
148 }
149
150 #[expect(clippy::type_complexity)]
152 pub fn expect_some_arguments<const N: usize>(
153 &self,
154 ) -> Result<(&[ExpressionNode<'i, T>; N], &[ExpressionNode<'i, T>]), InvalidArguments<'i>> {
155 self.ensure_no_keyword_arguments()?;
156 if self.args.len() >= N {
157 let (required, rest) = self.args.split_at(N);
158 Ok((required.try_into().unwrap(), rest))
159 } else {
160 Err(self.invalid_arguments_count(N, None))
161 }
162 }
163
164 #[expect(clippy::type_complexity)]
166 pub fn expect_arguments<const N: usize, const M: usize>(
167 &self,
168 ) -> Result<
169 (
170 &[ExpressionNode<'i, T>; N],
171 [Option<&ExpressionNode<'i, T>>; M],
172 ),
173 InvalidArguments<'i>,
174 > {
175 self.ensure_no_keyword_arguments()?;
176 let count_range = N..=(N + M);
177 if count_range.contains(&self.args.len()) {
178 let (required, rest) = self.args.split_at(N);
179 let mut optional = rest.iter().map(Some).collect_vec();
180 optional.resize(M, None);
181 Ok((
182 required.try_into().unwrap(),
183 optional.try_into().ok().unwrap(),
184 ))
185 } else {
186 let (min, max) = count_range.into_inner();
187 Err(self.invalid_arguments_count(min, Some(max)))
188 }
189 }
190
191 #[expect(clippy::type_complexity)]
197 pub fn expect_named_arguments<const N: usize, const M: usize>(
198 &self,
199 names: &[&str],
200 ) -> Result<
201 (
202 [&ExpressionNode<'i, T>; N],
203 [Option<&ExpressionNode<'i, T>>; M],
204 ),
205 InvalidArguments<'i>,
206 > {
207 if self.keyword_args.is_empty() {
208 let (required, optional) = self.expect_arguments::<N, M>()?;
209 Ok((required.each_ref(), optional))
210 } else {
211 let (required, optional) = self.expect_named_arguments_vec(names, N, N + M)?;
212 Ok((
213 required.try_into().ok().unwrap(),
214 optional.try_into().ok().unwrap(),
215 ))
216 }
217 }
218
219 #[expect(clippy::type_complexity)]
220 fn expect_named_arguments_vec(
221 &self,
222 names: &[&str],
223 min: usize,
224 max: usize,
225 ) -> Result<
226 (
227 Vec<&ExpressionNode<'i, T>>,
228 Vec<Option<&ExpressionNode<'i, T>>>,
229 ),
230 InvalidArguments<'i>,
231 > {
232 assert!(names.len() <= max);
233
234 if self.args.len() > max {
235 return Err(self.invalid_arguments_count(min, Some(max)));
236 }
237 let mut extracted = Vec::with_capacity(max);
238 extracted.extend(self.args.iter().map(Some));
239 extracted.resize(max, None);
240
241 for arg in &self.keyword_args {
242 let name = arg.name;
243 let span = arg.name_span.start_pos().span(&arg.value.span.end_pos());
244 let pos = names.iter().position(|&n| n == name).ok_or_else(|| {
245 self.invalid_arguments(format!(r#"Unexpected keyword argument "{name}""#), span)
246 })?;
247 if extracted[pos].is_some() {
248 return Err(self.invalid_arguments(
249 format!(r#"Got multiple values for keyword "{name}""#),
250 span,
251 ));
252 }
253 extracted[pos] = Some(&arg.value);
254 }
255
256 let optional = extracted.split_off(min);
257 let required = extracted.into_iter().flatten().collect_vec();
258 if required.len() != min {
259 return Err(self.invalid_arguments_count(min, Some(max)));
260 }
261 Ok((required, optional))
262 }
263
264 fn ensure_no_keyword_arguments(&self) -> Result<(), InvalidArguments<'i>> {
265 if let (Some(first), Some(last)) = (self.keyword_args.first(), self.keyword_args.last()) {
266 let span = first.name_span.start_pos().span(&last.value.span.end_pos());
267 Err(self.invalid_arguments("Unexpected keyword arguments".to_owned(), span))
268 } else {
269 Ok(())
270 }
271 }
272
273 fn invalid_arguments(&self, message: String, span: pest::Span<'i>) -> InvalidArguments<'i> {
274 InvalidArguments {
275 name: self.name,
276 message,
277 span,
278 }
279 }
280
281 fn invalid_arguments_count(&self, min: usize, max: Option<usize>) -> InvalidArguments<'i> {
282 let message = match (min, max) {
283 (min, Some(max)) if min == max => format!("Expected {min} arguments"),
284 (min, Some(max)) => format!("Expected {min} to {max} arguments"),
285 (min, None) => format!("Expected at least {min} arguments"),
286 };
287 self.invalid_arguments(message, self.args_span)
288 }
289
290 fn invalid_arguments_count_with_arities(
291 &self,
292 arities: impl IntoIterator<Item = usize>,
293 ) -> InvalidArguments<'i> {
294 let message = format!("Expected {} arguments", arities.into_iter().join(", "));
295 self.invalid_arguments(message, self.args_span)
296 }
297}
298
299#[derive(Clone, Debug)]
304pub struct InvalidArguments<'i> {
305 pub name: &'i str,
307 pub message: String,
309 pub span: pest::Span<'i>,
311}
312
313pub trait FoldableExpression<'i>: Sized {
315 fn fold<F>(self, folder: &mut F, span: pest::Span<'i>) -> Result<Self, F::Error>
317 where
318 F: ExpressionFolder<'i, Self> + ?Sized;
319}
320
321pub trait ExpressionFolder<'i, T: FoldableExpression<'i>> {
323 type Error;
325
326 fn fold_expression(
329 &mut self,
330 node: ExpressionNode<'i, T>,
331 ) -> Result<ExpressionNode<'i, T>, Self::Error> {
332 let ExpressionNode { kind, span } = node;
333 let kind = kind.fold(self, span)?;
334 Ok(ExpressionNode { kind, span })
335 }
336
337 fn fold_identifier(&mut self, name: &'i str, span: pest::Span<'i>) -> Result<T, Self::Error>;
339
340 fn fold_function_call(
342 &mut self,
343 function: Box<FunctionCallNode<'i, T>>,
344 span: pest::Span<'i>,
345 ) -> Result<T, Self::Error>;
346}
347
348pub fn fold_expression_nodes<'i, F, T>(
350 folder: &mut F,
351 nodes: Vec<ExpressionNode<'i, T>>,
352) -> Result<Vec<ExpressionNode<'i, T>>, F::Error>
353where
354 F: ExpressionFolder<'i, T> + ?Sized,
355 T: FoldableExpression<'i>,
356{
357 nodes
358 .into_iter()
359 .map(|node| folder.fold_expression(node))
360 .try_collect()
361}
362
363pub fn fold_function_call_args<'i, F, T>(
365 folder: &mut F,
366 function: FunctionCallNode<'i, T>,
367) -> Result<FunctionCallNode<'i, T>, F::Error>
368where
369 F: ExpressionFolder<'i, T> + ?Sized,
370 T: FoldableExpression<'i>,
371{
372 Ok(FunctionCallNode {
373 name: function.name,
374 name_span: function.name_span,
375 args: fold_expression_nodes(folder, function.args)?,
376 keyword_args: function
377 .keyword_args
378 .into_iter()
379 .map(|arg| {
380 Ok(KeywordArgument {
381 name: arg.name,
382 name_span: arg.name_span,
383 value: folder.fold_expression(arg.value)?,
384 })
385 })
386 .try_collect()?,
387 args_span: function.args_span,
388 })
389}
390
391#[derive(Debug)]
393pub struct StringLiteralParser<R> {
394 pub content_rule: R,
396 pub escape_rule: R,
398}
399
400impl<R: RuleType> StringLiteralParser<R> {
401 pub fn parse(&self, pairs: Pairs<R>) -> String {
403 let mut result = String::new();
404 for part in pairs {
405 if part.as_rule() == self.content_rule {
406 result.push_str(part.as_str());
407 } else if part.as_rule() == self.escape_rule {
408 match &part.as_str()[1..] {
409 "\"" => result.push('"'),
410 "\\" => result.push('\\'),
411 "t" => result.push('\t'),
412 "r" => result.push('\r'),
413 "n" => result.push('\n'),
414 "0" => result.push('\0'),
415 "e" => result.push('\x1b'),
416 hex if hex.starts_with('x') => {
417 result.push(char::from(
418 u8::from_str_radix(&hex[1..], 16).expect("hex characters"),
419 ));
420 }
421 char => panic!("invalid escape: \\{char:?}"),
422 }
423 } else {
424 panic!("unexpected part of string: {part:?}");
425 }
426 }
427 result
428 }
429}
430
431pub fn escape_string(unescaped: &str) -> String {
433 let mut escaped = String::with_capacity(unescaped.len());
434 for c in unescaped.chars() {
435 match c {
436 '"' => escaped.push_str(r#"\""#),
437 '\\' => escaped.push_str(r#"\\"#),
438 '\t' => escaped.push_str(r#"\t"#),
439 '\r' => escaped.push_str(r#"\r"#),
440 '\n' => escaped.push_str(r#"\n"#),
441 '\0' => escaped.push_str(r#"\0"#),
442 c if c.is_ascii_control() => {
443 for b in ascii::escape_default(c as u8) {
444 escaped.push(b as char);
445 }
446 }
447 c => escaped.push(c),
448 }
449 }
450 escaped
451}
452
453#[derive(Debug)]
455pub struct FunctionCallParser<R> {
456 pub function_name_rule: R,
458 pub function_arguments_rule: R,
460 pub keyword_argument_rule: R,
462 pub argument_name_rule: R,
464 pub argument_value_rule: R,
466}
467
468impl<R: RuleType> FunctionCallParser<R> {
469 pub fn parse<'i, T, E: From<InvalidArguments<'i>>>(
471 &self,
472 pair: Pair<'i, R>,
473 parse_name: impl Fn(Pair<'i, R>) -> Result<&'i str, E>,
476 parse_value: impl Fn(Pair<'i, R>) -> Result<ExpressionNode<'i, T>, E>,
477 ) -> Result<FunctionCallNode<'i, T>, E> {
478 let [name_pair, args_pair] = pair.into_inner().collect_array().unwrap();
479 assert_eq!(name_pair.as_rule(), self.function_name_rule);
480 assert_eq!(args_pair.as_rule(), self.function_arguments_rule);
481 let name_span = name_pair.as_span();
482 let args_span = args_pair.as_span();
483 let function_name = parse_name(name_pair)?;
484 let mut args = Vec::new();
485 let mut keyword_args = Vec::new();
486 for pair in args_pair.into_inner() {
487 let span = pair.as_span();
488 if pair.as_rule() == self.argument_value_rule {
489 if !keyword_args.is_empty() {
490 return Err(InvalidArguments {
491 name: function_name,
492 message: "Positional argument follows keyword argument".to_owned(),
493 span,
494 }
495 .into());
496 }
497 args.push(parse_value(pair)?);
498 } else if pair.as_rule() == self.keyword_argument_rule {
499 let [name_pair, value_pair] = pair.into_inner().collect_array().unwrap();
500 assert_eq!(name_pair.as_rule(), self.argument_name_rule);
501 assert_eq!(value_pair.as_rule(), self.argument_value_rule);
502 let name_span = name_pair.as_span();
503 let arg = KeywordArgument {
504 name: parse_name(name_pair)?,
505 name_span,
506 value: parse_value(value_pair)?,
507 };
508 keyword_args.push(arg);
509 } else {
510 panic!("unexpected argument rule {pair:?}");
511 }
512 }
513 Ok(FunctionCallNode {
514 name: function_name,
515 name_span,
516 args,
517 keyword_args,
518 args_span,
519 })
520 }
521}
522
523#[derive(Clone, Debug, Default)]
525pub struct AliasesMap<P, V> {
526 symbol_aliases: HashMap<String, V>,
527 function_aliases: HashMap<String, Vec<(Vec<String>, V)>>,
529 parser: P,
531}
532
533impl<P, V> AliasesMap<P, V> {
534 pub fn new() -> Self
536 where
537 P: Default,
538 {
539 Self {
540 symbol_aliases: Default::default(),
541 function_aliases: Default::default(),
542 parser: Default::default(),
543 }
544 }
545
546 pub fn insert(&mut self, decl: impl AsRef<str>, defn: impl Into<V>) -> Result<(), P::Error>
551 where
552 P: AliasDeclarationParser,
553 {
554 match self.parser.parse_declaration(decl.as_ref())? {
555 AliasDeclaration::Symbol(name) => {
556 self.symbol_aliases.insert(name, defn.into());
557 }
558 AliasDeclaration::Function(name, params) => {
559 let overloads = self.function_aliases.entry(name).or_default();
560 match overloads.binary_search_by_key(¶ms.len(), |(params, _)| params.len()) {
561 Ok(i) => overloads[i] = (params, defn.into()),
562 Err(i) => overloads.insert(i, (params, defn.into())),
563 }
564 }
565 }
566 Ok(())
567 }
568
569 pub fn symbol_names(&self) -> impl Iterator<Item = &str> {
571 self.symbol_aliases.keys().map(|n| n.as_ref())
572 }
573
574 pub fn function_names(&self) -> impl Iterator<Item = &str> {
576 self.function_aliases.keys().map(|n| n.as_ref())
577 }
578
579 pub fn get_symbol(&self, name: &str) -> Option<(AliasId<'_>, &V)> {
581 self.symbol_aliases
582 .get_key_value(name)
583 .map(|(name, defn)| (AliasId::Symbol(name), defn))
584 }
585
586 pub fn get_function(&self, name: &str, arity: usize) -> Option<(AliasId<'_>, &[String], &V)> {
589 let overloads = self.get_function_overloads(name)?;
590 overloads.find_by_arity(arity)
591 }
592
593 fn get_function_overloads(&self, name: &str) -> Option<AliasFunctionOverloads<'_, V>> {
595 let (name, overloads) = self.function_aliases.get_key_value(name)?;
596 Some(AliasFunctionOverloads { name, overloads })
597 }
598}
599
600#[derive(Clone, Debug)]
601struct AliasFunctionOverloads<'a, V> {
602 name: &'a String,
603 overloads: &'a Vec<(Vec<String>, V)>,
604}
605
606impl<'a, V> AliasFunctionOverloads<'a, V> {
607 fn arities(&self) -> impl DoubleEndedIterator<Item = usize> + ExactSizeIterator {
608 self.overloads.iter().map(|(params, _)| params.len())
609 }
610
611 fn min_arity(&self) -> usize {
612 self.arities().next().unwrap()
613 }
614
615 fn max_arity(&self) -> usize {
616 self.arities().next_back().unwrap()
617 }
618
619 fn find_by_arity(&self, arity: usize) -> Option<(AliasId<'a>, &'a [String], &'a V)> {
620 let index = self
621 .overloads
622 .binary_search_by_key(&arity, |(params, _)| params.len())
623 .ok()?;
624 let (params, defn) = &self.overloads[index];
625 Some((AliasId::Function(self.name, params), params, defn))
629 }
630}
631
632#[derive(Clone, Copy, Debug, Eq, PartialEq)]
634pub enum AliasId<'a> {
635 Symbol(&'a str),
637 Function(&'a str, &'a [String]),
639 Parameter(&'a str),
641}
642
643impl fmt::Display for AliasId<'_> {
644 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
645 match self {
646 Self::Symbol(name) => write!(f, "{name}"),
647 Self::Function(name, params) => {
648 write!(f, "{name}({params})", params = params.join(", "))
649 }
650 Self::Parameter(name) => write!(f, "{name}"),
651 }
652 }
653}
654
655#[derive(Clone, Debug)]
657pub enum AliasDeclaration {
658 Symbol(String),
660 Function(String, Vec<String>),
662}
663
664pub trait AliasDeclarationParser {
669 type Error;
671
672 fn parse_declaration(&self, source: &str) -> Result<AliasDeclaration, Self::Error>;
674}
675
676pub trait AliasDefinitionParser {
678 type Output<'i>;
680 type Error;
682
683 fn parse_definition<'i>(
685 &self,
686 source: &'i str,
687 ) -> Result<ExpressionNode<'i, Self::Output<'i>>, Self::Error>;
688}
689
690pub trait AliasExpandableExpression<'i>: FoldableExpression<'i> {
692 fn identifier(name: &'i str) -> Self;
694 fn function_call(function: Box<FunctionCallNode<'i, Self>>) -> Self;
696 fn alias_expanded(id: AliasId<'i>, subst: Box<ExpressionNode<'i, Self>>) -> Self;
698}
699
700pub trait AliasExpandError: Sized {
702 fn invalid_arguments(err: InvalidArguments<'_>) -> Self;
704 fn recursive_expansion(id: AliasId<'_>, span: pest::Span<'_>) -> Self;
706 fn within_alias_expansion(self, id: AliasId<'_>, span: pest::Span<'_>) -> Self;
708}
709
710#[derive(Debug)]
712struct AliasExpander<'i, 'a, T, P> {
713 aliases_map: &'i AliasesMap<P, String>,
715 locals: &'a HashMap<&'i str, ExpressionNode<'i, T>>,
717 states: Vec<AliasExpandingState<'i, T>>,
719}
720
721#[derive(Debug)]
722struct AliasExpandingState<'i, T> {
723 id: AliasId<'i>,
724 locals: HashMap<&'i str, ExpressionNode<'i, T>>,
725}
726
727impl<'i, T, P, E> AliasExpander<'i, '_, T, P>
728where
729 T: AliasExpandableExpression<'i> + Clone,
730 P: AliasDefinitionParser<Output<'i> = T, Error = E>,
731 E: AliasExpandError,
732{
733 fn current_locals(&self) -> &HashMap<&'i str, ExpressionNode<'i, T>> {
735 self.states.last().map_or(self.locals, |s| &s.locals)
736 }
737
738 fn expand_defn(
739 &mut self,
740 id: AliasId<'i>,
741 defn: &'i str,
742 locals: HashMap<&'i str, ExpressionNode<'i, T>>,
743 span: pest::Span<'i>,
744 ) -> Result<T, E> {
745 if self.states.iter().any(|s| s.id == id) {
747 return Err(E::recursive_expansion(id, span));
748 }
749 self.states.push(AliasExpandingState { id, locals });
750 let result = self
752 .aliases_map
753 .parser
754 .parse_definition(defn)
755 .and_then(|node| self.fold_expression(node))
756 .map(|node| T::alias_expanded(id, Box::new(node)))
757 .map_err(|e| e.within_alias_expansion(id, span));
758 self.states.pop();
759 result
760 }
761}
762
763impl<'i, T, P, E> ExpressionFolder<'i, T> for AliasExpander<'i, '_, T, P>
764where
765 T: AliasExpandableExpression<'i> + Clone,
766 P: AliasDefinitionParser<Output<'i> = T, Error = E>,
767 E: AliasExpandError,
768{
769 type Error = E;
770
771 fn fold_identifier(&mut self, name: &'i str, span: pest::Span<'i>) -> Result<T, Self::Error> {
772 if let Some(subst) = self.current_locals().get(name) {
773 let id = AliasId::Parameter(name);
774 Ok(T::alias_expanded(id, Box::new(subst.clone())))
775 } else if let Some((id, defn)) = self.aliases_map.get_symbol(name) {
776 let locals = HashMap::new(); self.expand_defn(id, defn, locals, span)
778 } else {
779 Ok(T::identifier(name))
780 }
781 }
782
783 fn fold_function_call(
784 &mut self,
785 function: Box<FunctionCallNode<'i, T>>,
786 span: pest::Span<'i>,
787 ) -> Result<T, Self::Error> {
788 if let Some(overloads) = self.aliases_map.get_function_overloads(function.name) {
791 function
793 .ensure_no_keyword_arguments()
794 .map_err(E::invalid_arguments)?;
795 let Some((id, params, defn)) = overloads.find_by_arity(function.arity()) else {
796 let min = overloads.min_arity();
797 let max = overloads.max_arity();
798 let err = if max - min + 1 == overloads.arities().len() {
799 function.invalid_arguments_count(min, Some(max))
800 } else {
801 function.invalid_arguments_count_with_arities(overloads.arities())
802 };
803 return Err(E::invalid_arguments(err));
804 };
805 let args = fold_expression_nodes(self, function.args)?;
808 let locals = params.iter().map(|s| s.as_str()).zip(args).collect();
809 self.expand_defn(id, defn, locals, span)
810 } else {
811 let function = Box::new(fold_function_call_args(self, *function)?);
812 Ok(T::function_call(function))
813 }
814 }
815}
816
817pub fn expand_aliases<'i, T, P>(
819 node: ExpressionNode<'i, T>,
820 aliases_map: &'i AliasesMap<P, String>,
821) -> Result<ExpressionNode<'i, T>, P::Error>
822where
823 T: AliasExpandableExpression<'i> + Clone,
824 P: AliasDefinitionParser<Output<'i> = T>,
825 P::Error: AliasExpandError,
826{
827 expand_aliases_with_locals(node, aliases_map, &HashMap::new())
828}
829
830pub fn expand_aliases_with_locals<'i, T, P>(
835 node: ExpressionNode<'i, T>,
836 aliases_map: &'i AliasesMap<P, String>,
837 locals: &HashMap<&'i str, ExpressionNode<'i, T>>,
838) -> Result<ExpressionNode<'i, T>, P::Error>
839where
840 T: AliasExpandableExpression<'i> + Clone,
841 P: AliasDefinitionParser<Output<'i> = T>,
842 P::Error: AliasExpandError,
843{
844 let mut expander = AliasExpander {
845 aliases_map,
846 locals,
847 states: Vec::new(),
848 };
849 expander.fold_expression(node)
850}
851
852pub fn collect_similar<I>(name: &str, candidates: I) -> Vec<String>
854where
855 I: IntoIterator,
856 I::Item: AsRef<str>,
857{
858 candidates
859 .into_iter()
860 .filter(|cand| {
861 strsim::jaro(name, cand.as_ref()) > 0.7
863 })
864 .map(|s| s.as_ref().to_owned())
865 .sorted_unstable()
866 .collect()
867}
868
869#[cfg(test)]
870mod tests {
871 use super::*;
872
873 #[test]
874 fn test_expect_arguments() {
875 fn empty_span() -> pest::Span<'static> {
876 pest::Span::new("", 0, 0).unwrap()
877 }
878
879 fn function(
880 name: &'static str,
881 args: impl Into<Vec<ExpressionNode<'static, u32>>>,
882 keyword_args: impl Into<Vec<KeywordArgument<'static, u32>>>,
883 ) -> FunctionCallNode<'static, u32> {
884 FunctionCallNode {
885 name,
886 name_span: empty_span(),
887 args: args.into(),
888 keyword_args: keyword_args.into(),
889 args_span: empty_span(),
890 }
891 }
892
893 fn value(v: u32) -> ExpressionNode<'static, u32> {
894 ExpressionNode::new(v, empty_span())
895 }
896
897 fn keyword(name: &'static str, v: u32) -> KeywordArgument<'static, u32> {
898 KeywordArgument {
899 name,
900 name_span: empty_span(),
901 value: value(v),
902 }
903 }
904
905 let f = function("foo", [], []);
906 assert!(f.expect_no_arguments().is_ok());
907 assert!(f.expect_some_arguments::<0>().is_ok());
908 assert!(f.expect_arguments::<0, 0>().is_ok());
909 assert!(f.expect_named_arguments::<0, 0>(&[]).is_ok());
910
911 let f = function("foo", [value(0)], []);
912 assert!(f.expect_no_arguments().is_err());
913 assert_eq!(
914 f.expect_some_arguments::<0>().unwrap(),
915 (&[], [value(0)].as_slice())
916 );
917 assert_eq!(
918 f.expect_some_arguments::<1>().unwrap(),
919 (&[value(0)], [].as_slice())
920 );
921 assert!(f.expect_arguments::<0, 0>().is_err());
922 assert_eq!(
923 f.expect_arguments::<0, 1>().unwrap(),
924 (&[], [Some(&value(0))])
925 );
926 assert_eq!(f.expect_arguments::<1, 1>().unwrap(), (&[value(0)], [None]));
927 assert!(f.expect_named_arguments::<0, 0>(&[]).is_err());
928 assert_eq!(
929 f.expect_named_arguments::<0, 1>(&["a"]).unwrap(),
930 ([], [Some(&value(0))])
931 );
932 assert_eq!(
933 f.expect_named_arguments::<1, 0>(&["a"]).unwrap(),
934 ([&value(0)], [])
935 );
936
937 let f = function("foo", [], [keyword("a", 0)]);
938 assert!(f.expect_no_arguments().is_err());
939 assert!(f.expect_some_arguments::<1>().is_err());
940 assert!(f.expect_arguments::<0, 1>().is_err());
941 assert!(f.expect_arguments::<1, 0>().is_err());
942 assert!(f.expect_named_arguments::<0, 0>(&[]).is_err());
943 assert!(f.expect_named_arguments::<0, 1>(&[]).is_err());
944 assert!(f.expect_named_arguments::<1, 0>(&[]).is_err());
945 assert_eq!(
946 f.expect_named_arguments::<1, 0>(&["a"]).unwrap(),
947 ([&value(0)], [])
948 );
949 assert_eq!(
950 f.expect_named_arguments::<1, 1>(&["a", "b"]).unwrap(),
951 ([&value(0)], [None])
952 );
953 assert!(f.expect_named_arguments::<1, 1>(&["b", "a"]).is_err());
954
955 let f = function("foo", [value(0)], [keyword("a", 1), keyword("b", 2)]);
956 assert!(f.expect_named_arguments::<0, 0>(&[]).is_err());
957 assert!(f.expect_named_arguments::<1, 1>(&["a", "b"]).is_err());
958 assert_eq!(
959 f.expect_named_arguments::<1, 2>(&["c", "a", "b"]).unwrap(),
960 ([&value(0)], [Some(&value(1)), Some(&value(2))])
961 );
962 assert_eq!(
963 f.expect_named_arguments::<2, 1>(&["c", "b", "a"]).unwrap(),
964 ([&value(0), &value(2)], [Some(&value(1))])
965 );
966 assert_eq!(
967 f.expect_named_arguments::<0, 3>(&["c", "b", "a"]).unwrap(),
968 ([], [Some(&value(0)), Some(&value(2)), Some(&value(1))])
969 );
970
971 let f = function("foo", [], [keyword("a", 0), keyword("a", 1)]);
972 assert!(f.expect_named_arguments::<1, 1>(&["", "a"]).is_err());
973 }
974}