1use nom::{
4 branch::alt,
5 bytes::{
6 complete::{tag, take_until, take_while, take_while1, take_while_m_n},
7 streaming,
8 },
9 character::complete::{char as tag_char, one_of},
10 combinator::{cut, map, map_res, not, opt, peek, recognize},
11 error::context,
12 multi::{many0, separated_list0, separated_list1},
13 sequence::{delimited, preceded, terminated, tuple},
14 Err as NomErr, Slice,
15};
16
17use core::mem;
18
19use crate::{
20 alloc::{vec, Box, Vec},
21 grammars::{Features, Grammar, Parse, ParseLiteral},
22 spans::{unite_spans, with_span},
23 BinaryOp, Block, Context, Destructure, DestructureRest, Error, ErrorKind, Expr, FnDefinition,
24 InputSpan, Lvalue, NomResult, ObjectDestructure, ObjectDestructureField, ObjectExpr, Spanned,
25 SpannedExpr, SpannedLvalue, SpannedStatement, Statement, UnaryOp,
26};
27
28#[cfg(test)]
29mod tests;
30
31trait GrammarType {
32 const COMPLETE: bool;
33}
34
35#[derive(Debug)]
36struct Complete(());
37
38impl GrammarType for Complete {
39 const COMPLETE: bool = true;
40}
41
42#[derive(Debug)]
43struct Streaming(());
44
45impl GrammarType for Streaming {
46 const COMPLETE: bool = false;
47}
48
49impl UnaryOp {
50 fn from_span(span: Spanned<'_, char>) -> Spanned<'_, Self> {
51 match span.extra {
52 '-' => span.copy_with_extra(UnaryOp::Neg),
53 '!' => span.copy_with_extra(UnaryOp::Not),
54 _ => unreachable!(),
55 }
56 }
57
58 fn try_from_byte(byte: u8) -> Option<Self> {
59 match byte {
60 b'-' => Some(Self::Neg),
61 b'!' => Some(Self::Not),
62 _ => None,
63 }
64 }
65}
66
67impl BinaryOp {
68 fn from_span(span: InputSpan<'_>) -> Spanned<'_, Self> {
69 Spanned::new(
70 span,
71 match *span.fragment() {
72 "+" => Self::Add,
73 "-" => Self::Sub,
74 "*" => Self::Mul,
75 "/" => Self::Div,
76 "^" => Self::Power,
77 "==" => Self::Eq,
78 "!=" => Self::NotEq,
79 "&&" => Self::And,
80 "||" => Self::Or,
81 ">" => Self::Gt,
82 "<" => Self::Lt,
83 ">=" => Self::Ge,
84 "<=" => Self::Le,
85 _ => unreachable!(),
86 },
87 )
88 }
89
90 fn is_supported(self, features: Features) -> bool {
91 match self {
92 Self::Add | Self::Sub | Self::Mul | Self::Div | Self::Power => true,
93 Self::Eq | Self::NotEq | Self::And | Self::Or => {
94 features.contains(Features::BOOLEAN_OPS_BASIC)
95 }
96 Self::Gt | Self::Lt | Self::Ge | Self::Le => features.contains(Features::BOOLEAN_OPS),
97 }
98 }
99}
100
101fn ws<Ty: GrammarType>(input: InputSpan<'_>) -> NomResult<'_, InputSpan<'_>> {
103 fn narrow_ws<T: GrammarType>(input: InputSpan<'_>) -> NomResult<'_, InputSpan<'_>> {
104 if T::COMPLETE {
105 take_while1(|c: char| c.is_ascii_whitespace())(input)
106 } else {
107 streaming::take_while1(|c: char| c.is_ascii_whitespace())(input)
108 }
109 }
110
111 fn long_comment_body<T: GrammarType>(input: InputSpan<'_>) -> NomResult<'_, InputSpan<'_>> {
112 if T::COMPLETE {
113 context(Context::Comment.to_str(), cut(take_until("*/")))(input)
114 } else {
115 streaming::take_until("*/")(input)
116 }
117 }
118
119 let comment = preceded(tag("//"), take_while(|c: char| c != '\n'));
120 let long_comment = delimited(tag("/*"), long_comment_body::<Ty>, tag("*/"));
121 let ws_line = alt((narrow_ws::<Ty>, comment, long_comment));
122 recognize(many0(ws_line))(input)
123}
124
125fn mandatory_ws<Ty: GrammarType>(input: InputSpan<'_>) -> NomResult<'_, InputSpan<'_>> {
126 let not_ident_char = peek(not(take_while_m_n(1, 1, |c: char| {
127 c.is_ascii_alphanumeric() || c == '_'
128 })));
129 preceded(not_ident_char, ws::<Ty>)(input)
130}
131
132fn var_name(input: InputSpan<'_>) -> NomResult<'_, InputSpan<'_>> {
134 context(
135 Context::Var.to_str(),
136 preceded(
137 peek(take_while_m_n(1, 1, |c: char| {
138 c.is_ascii_alphabetic() || c == '_'
139 })),
140 take_while1(|c: char| c.is_ascii_alphanumeric() || c == '_'),
141 ),
142 )(input)
143}
144
145pub fn is_valid_variable_name(name: &str) -> bool {
147 if name.is_empty() || !name.is_ascii() {
148 return false;
149 }
150
151 match var_name(InputSpan::new(name)) {
152 Ok((rest, _)) => rest.fragment().is_empty(),
153 Err(_) => false,
154 }
155}
156
157fn fn_args<'a, T, Ty>(input: InputSpan<'a>) -> NomResult<'a, (Vec<SpannedExpr<'a, T::Base>>, bool)>
163where
164 T: Parse<'a>,
165 Ty: GrammarType,
166{
167 let maybe_comma = map(opt(preceded(ws::<Ty>, tag_char(','))), |c| c.is_some());
168
169 preceded(
170 terminated(tag_char('('), ws::<Ty>),
171 cut(tuple((
173 separated_list0(delimited(ws::<Ty>, tag_char(','), ws::<Ty>), expr::<T, Ty>),
174 terminated(maybe_comma, tuple((ws::<Ty>, tag_char(')')))),
175 ))),
176 )(input)
177}
178
179fn paren_expr<'a, T, Ty>(input: InputSpan<'a>) -> NomResult<'a, SpannedExpr<'a, T::Base>>
182where
183 T: Parse<'a>,
184 Ty: GrammarType,
185{
186 with_span(fn_args::<T, Ty>)(input).and_then(|(rest, parsed)| {
187 let comma_terminated = parsed.extra.1;
188 let terms = parsed.map_extra(|terms| terms.0);
189
190 match (terms.extra.len(), comma_terminated) {
191 (1, false) => Ok((
192 rest,
193 terms.map_extra(|mut terms| terms.pop().unwrap().extra),
194 )),
195
196 _ => {
197 if T::FEATURES.contains(Features::TUPLES) {
198 Ok((rest, terms.map_extra(Expr::Tuple)))
199 } else {
200 Err(NomErr::Failure(
201 ErrorKind::UnexpectedTerm { context: None }.with_span(&terms),
202 ))
203 }
204 }
205 }
206 })
207}
208
209fn block_expr<'a, T, Ty>(input: InputSpan<'a>) -> NomResult<'a, SpannedExpr<'a, T::Base>>
211where
212 T: Parse<'a>,
213 Ty: GrammarType,
214{
215 map(with_span(block::<T, Ty>), |spanned| {
216 spanned.map_extra(Expr::Block)
217 })(input)
218}
219
220fn object_expr_field<'a, T, Ty>(
221 input: InputSpan<'a>,
222) -> NomResult<'a, (Spanned<'a>, Option<SpannedExpr<'a, T::Base>>)>
223where
224 T: Parse<'a>,
225 Ty: GrammarType,
226{
227 let colon_sep = delimited(ws::<Ty>, tag_char(':'), ws::<Ty>);
228 tuple((
229 map(var_name, Spanned::from),
230 opt(preceded(colon_sep, expr::<T, Ty>)),
231 ))(input)
232}
233
234fn object_expr<'a, T, Ty>(input: InputSpan<'a>) -> NomResult<'a, SpannedExpr<'a, T::Base>>
235where
236 T: Parse<'a>,
237 Ty: GrammarType,
238{
239 let object = preceded(
240 terminated(tag("#{"), ws::<Ty>),
241 cut(terminated(
242 terminated(
243 separated_list0(comma_sep::<Ty>, object_expr_field::<T, Ty>),
244 opt(comma_sep::<Ty>),
245 ),
246 preceded(ws::<Ty>, tag_char('}')),
247 )),
248 );
249
250 map(with_span(object), |spanned| {
251 spanned.map_extra(|fields| Expr::Object(ObjectExpr { fields }))
252 })(input)
253}
254
255fn fn_def_expr<'a, T, Ty>(input: InputSpan<'a>) -> NomResult<'a, SpannedExpr<'a, T::Base>>
257where
258 T: Parse<'a>,
259 Ty: GrammarType,
260{
261 map(with_span(fn_def::<T, Ty>), |spanned| {
262 spanned.map_extra(Expr::FnDefinition)
263 })(input)
264}
265
266fn simplest_expr<'a, T, Ty>(input: InputSpan<'a>) -> NomResult<'a, SpannedExpr<'a, T::Base>>
271where
272 T: Parse<'a>,
273 Ty: GrammarType,
274{
275 fn error<'b, T>(input: InputSpan<'b>) -> NomResult<'b, SpannedExpr<'b, T::Base>>
276 where
277 T: Parse<'b>,
278 {
279 let e = ErrorKind::Leftovers.with_span(&input.into());
280 Err(NomErr::Error(e))
281 }
282
283 let block_parser = if T::FEATURES.contains(Features::BLOCKS) {
284 block_expr::<T, Ty>
285 } else {
286 error::<T>
287 };
288
289 let object_parser = if T::FEATURES.contains(Features::OBJECTS) {
290 object_expr::<T, Ty>
291 } else {
292 error::<T>
293 };
294
295 let fn_def_parser = if T::FEATURES.contains(Features::FN_DEFINITIONS) {
296 fn_def_expr::<T, Ty>
297 } else {
298 error::<T>
299 };
300
301 alt((
302 map(with_span(<T::Base>::parse_literal), |span| {
303 span.map_extra(Expr::Literal)
304 }),
305 map(with_span(var_name), |span| {
306 span.copy_with_extra(Expr::Variable)
307 }),
308 fn_def_parser,
309 map(
310 with_span(tuple((
311 terminated(with_span(one_of("-!")), ws::<Ty>),
312 expr_with_calls::<T, Ty>,
313 ))),
314 |spanned| {
315 spanned.map_extra(|(op, inner)| Expr::Unary {
316 op: UnaryOp::from_span(op),
317 inner: Box::new(inner),
318 })
319 },
320 ),
321 block_parser,
322 object_parser,
323 paren_expr::<T, Ty>,
324 ))(input)
325}
326
327#[derive(Debug)]
328struct MethodOrFnCall<'a, T: Grammar<'a>> {
329 fn_name: Option<InputSpan<'a>>,
330 args: Option<Vec<SpannedExpr<'a, T>>>,
331}
332
333impl<'a, T: Grammar<'a>> MethodOrFnCall<'a, T> {
334 fn is_method(&self) -> bool {
335 self.fn_name.is_some() && self.args.is_some()
336 }
337}
338
339type MethodParseResult<'a, T> = NomResult<'a, MethodOrFnCall<'a, <T as Parse<'a>>::Base>>;
340
341fn fn_call<'a, T, Ty>(input: InputSpan<'a>) -> MethodParseResult<'a, T>
342where
343 T: Parse<'a>,
344 Ty: GrammarType,
345{
346 map(fn_args::<T, Ty>, |(args, _)| MethodOrFnCall {
347 fn_name: None,
348 args: Some(args),
349 })(input)
350}
351
352fn method_or_fn_call<'a, T, Ty>(input: InputSpan<'a>) -> MethodParseResult<'a, T>
353where
354 T: Parse<'a>,
355 Ty: GrammarType,
356{
357 let var_name_or_digits = alt((var_name, take_while1(|c: char| c.is_ascii_digit())));
358 let method_parser = map_res(
359 tuple((var_name_or_digits, opt(fn_args::<T, Ty>))),
360 |(fn_name, maybe_args)| {
361 if maybe_args.is_some() && !is_valid_variable_name(fn_name.fragment()) {
362 Err(ErrorKind::LiteralName)
363 } else {
364 Ok(MethodOrFnCall {
365 fn_name: Some(fn_name),
366 args: maybe_args.map(|(args, _)| args),
367 })
368 }
369 },
370 );
371
372 alt((
373 preceded(tuple((tag_char('.'), ws::<Ty>)), cut(method_parser)),
374 fn_call::<T, Ty>,
375 ))(input)
376}
377
378fn expr_with_calls<'a, T, Ty>(input: InputSpan<'a>) -> NomResult<'a, SpannedExpr<'a, T::Base>>
380where
381 T: Parse<'a>,
382 Ty: GrammarType,
383{
384 let method_or_fn_call = if T::FEATURES.contains(Features::METHODS) {
385 method_or_fn_call::<T, Ty>
386 } else {
387 fn_call::<T, Ty>
388 };
389
390 let mut parser = tuple((
391 simplest_expr::<T, Ty>,
392 many0(with_span(preceded(ws::<Ty>, method_or_fn_call))),
393 ));
394 parser(input).and_then(|(rest, (base, calls))| {
395 fold_args(input, base, calls).map(|folded| (rest, folded))
396 })
397}
398
399fn simple_expr<'a, T, Ty>(input: InputSpan<'a>) -> NomResult<'a, SpannedExpr<'a, T::Base>>
401where
402 T: Parse<'a>,
403 Ty: GrammarType,
404{
405 let as_keyword = delimited(ws::<Ty>, tag("as"), mandatory_ws::<Ty>);
406 let parser = tuple((
407 expr_with_calls::<T, Ty>,
408 many0(preceded(as_keyword, cut(with_span(<T::Base>::parse_type)))),
409 ));
410
411 map(parser, |(base, casts)| {
412 casts.into_iter().fold(base, |value, ty| {
413 let united_span = unite_spans(input, &value, &ty);
414 united_span.copy_with_extra(Expr::TypeCast {
415 value: Box::new(value),
416 ty,
417 })
418 })
419 })(input)
420}
421
422#[allow(clippy::option_if_let_else, clippy::range_plus_one)]
423fn fold_args<'a, T: Grammar<'a>>(
425 input: InputSpan<'a>,
426 mut base: SpannedExpr<'a, T>,
427 calls: Vec<Spanned<'a, MethodOrFnCall<'a, T>>>,
428) -> Result<SpannedExpr<'a, T>, NomErr<Error<'a>>> {
429 let mut maybe_reordered_op = None;
438
439 if matches!(base.extra, Expr::Literal(_)) {
440 match calls.first() {
441 Some(call) if !call.extra.is_method() => {
442 let e = ErrorKind::LiteralName.with_span(&base);
444 return Err(NomErr::Failure(e));
445 }
446 Some(_) => maybe_reordered_op = UnaryOp::try_from_byte(base.fragment().as_bytes()[0]),
448 None => { }
449 }
450 }
451
452 let reordered_op = if let Some(reordered_op) = maybe_reordered_op {
453 let lit_start = base.location_offset() - input.location_offset();
454 let unsigned_lit_input = input.slice((lit_start + 1)..(lit_start + base.fragment().len()));
455
456 if let Ok((_, unsigned_lit)) = T::parse_literal(unsigned_lit_input) {
457 base = SpannedExpr::new(unsigned_lit_input, Expr::Literal(unsigned_lit));
458
459 let op_span = input.slice(lit_start..(lit_start + 1));
462 Some(Spanned::new(op_span, reordered_op))
463 } else {
464 None
465 }
466 } else {
467 None
468 };
469
470 let folded = calls.into_iter().fold(base, |name, call| {
471 let united_span = unite_spans(input, &name, &call);
472
473 let expr = if let Some(fn_name) = call.extra.fn_name {
476 if let Some(args) = call.extra.args {
477 Expr::Method {
478 name: fn_name.into(),
479 receiver: Box::new(name),
480 args,
481 }
482 } else {
483 Expr::FieldAccess {
484 name: fn_name.into(),
485 receiver: Box::new(name),
486 }
487 }
488 } else {
489 Expr::Function {
490 name: Box::new(name),
491 args: call.extra.args.expect("Args must be present for functions"),
492 }
493 };
494 united_span.copy_with_extra(expr)
495 });
496
497 Ok(if let Some(unary_op) = reordered_op {
498 unite_spans(input, &unary_op, &folded).copy_with_extra(Expr::Unary {
499 op: unary_op,
500 inner: Box::new(folded),
501 })
502 } else {
503 folded
504 })
505}
506
507fn binary_expr<'a, T, Ty>(input: InputSpan<'a>) -> NomResult<'a, SpannedExpr<'a, T::Base>>
510where
511 T: Parse<'a>,
512 Ty: GrammarType,
513{
514 #[rustfmt::skip]
519 let binary_ops = alt((
520 tag("+"), tag("-"), tag("*"), tag("/"), tag("^"), tag("=="), tag("!="), tag("&&"), tag("||"), tag(">="), tag("<="), tag(">"), tag("<"), ));
525 let mut binary_ops = map(binary_ops, BinaryOp::from_span);
526
527 let full_binary_ops = move |input| {
528 let (rest, spanned_op) = binary_ops(input)?;
529 if spanned_op.extra.is_supported(T::FEATURES) {
530 Ok((rest, spanned_op))
531 } else {
532 let err = ErrorKind::UnsupportedOp(spanned_op.extra.into());
534 let spanned_err = err.with_span(&spanned_op);
535 Err(NomErr::Failure(spanned_err))
536 }
537 };
538
539 let mut binary_parser = tuple((
540 simple_expr::<T, Ty>,
541 many0(tuple((
542 delimited(ws::<Ty>, full_binary_ops, ws::<Ty>),
543 cut(simple_expr::<T, Ty>),
544 ))),
545 ));
546
547 let (remaining_input, (first, rest)) = binary_parser(input)?;
548 let folded = fold_binary_expr(input, first, rest).map_err(NomErr::Failure)?;
549 Ok((remaining_input, folded))
550}
551
552fn fold_binary_expr<'a, T: Grammar<'a>>(
583 input: InputSpan<'a>,
584 first: SpannedExpr<'a, T>,
585 rest: Vec<(Spanned<'a, BinaryOp>, SpannedExpr<'a, T>)>,
586) -> Result<SpannedExpr<'a, T>, Error<'a>> {
587 let mut right_contour: Vec<BinaryOp> = vec![];
588
589 rest.into_iter().try_fold(first, |mut acc, (new_op, expr)| {
590 let united_span = unite_spans(input, &acc, &expr);
591
592 let insert_pos = right_contour
593 .iter()
594 .position(|past_op| past_op.priority() >= new_op.extra.priority())
595 .unwrap_or_else(|| right_contour.len());
596
597 let chained_comparison = right_contour.get(insert_pos).map_or(false, |past_op| {
599 past_op.is_comparison() && new_op.extra.is_comparison()
600 });
601
602 right_contour.truncate(insert_pos);
603 right_contour.push(new_op.extra);
604
605 if insert_pos == 0 {
606 if chained_comparison {
607 return Err(ErrorKind::ChainedComparison.with_span(&united_span));
608 }
609
610 Ok(united_span.copy_with_extra(Expr::Binary {
611 lhs: Box::new(acc),
612 op: new_op,
613 rhs: Box::new(expr),
614 }))
615 } else {
616 let mut parent = &mut acc;
617 for _ in 1..insert_pos {
618 parent = match parent.extra {
619 Expr::Binary { ref mut rhs, .. } => rhs,
620 _ => unreachable!(),
621 };
622 }
623
624 *parent = unite_spans(input, &parent, &expr).copy_with_extra(parent.extra.clone());
625 if let Expr::Binary { ref mut rhs, .. } = parent.extra {
626 let rhs_span = unite_spans(input, rhs, &expr);
627 if chained_comparison {
628 return Err(ErrorKind::ChainedComparison.with_span(&rhs_span));
629 }
630
631 let dummy = Box::new(rhs.copy_with_extra(Expr::Variable));
632 let old_rhs = mem::replace(rhs, dummy);
633 let new_expr = Expr::Binary {
634 lhs: old_rhs,
635 op: new_op,
636 rhs: Box::new(expr),
637 };
638 *rhs = Box::new(rhs_span.copy_with_extra(new_expr));
639 }
640 acc = united_span.copy_with_extra(acc.extra);
641 Ok(acc)
642 }
643 })
644}
645
646fn expr<'a, T, Ty>(input: InputSpan<'a>) -> NomResult<'a, SpannedExpr<'a, T::Base>>
647where
648 T: Parse<'a>,
649 Ty: GrammarType,
650{
651 context(Context::Expr.to_str(), binary_expr::<T, Ty>)(input)
652}
653
654fn comma_sep<Ty: GrammarType>(input: InputSpan<'_>) -> NomResult<'_, char> {
655 delimited(ws::<Ty>, tag_char(','), ws::<Ty>)(input)
656}
657
658fn comma_separated_lvalues<'a, T, Ty>(
659 input: InputSpan<'a>,
660) -> NomResult<'a, Vec<GrammarLvalue<'a, T>>>
661where
662 T: Parse<'a>,
663 Ty: GrammarType,
664{
665 separated_list0(comma_sep::<Ty>, lvalue::<T, Ty>)(input)
666}
667
668fn destructure_rest<'a, T, Ty>(
669 input: InputSpan<'a>,
670) -> NomResult<'a, Spanned<'a, DestructureRest<'a, <T::Base as Grammar<'a>>::Type>>>
671where
672 T: Parse<'a>,
673 Ty: GrammarType,
674{
675 map(
676 with_span(preceded(
677 terminated(tag("..."), ws::<Ty>),
678 cut(opt(simple_lvalue_with_type::<T, Ty>)),
679 )),
680 |spanned| {
681 spanned.map_extra(|maybe_lvalue| {
682 maybe_lvalue.map_or(DestructureRest::Unnamed, |lvalue| DestructureRest::Named {
683 variable: lvalue.with_no_extra(),
684 ty: match lvalue.extra {
685 Lvalue::Variable { ty } => ty,
686 _ => None,
687 },
688 })
689 })
690 },
691 )(input)
692}
693
694type DestructureTail<'a, T> = (
695 Spanned<'a, DestructureRest<'a, T>>,
696 Option<Vec<SpannedLvalue<'a, T>>>,
697);
698
699fn destructure_tail<'a, T, Ty>(
700 input: InputSpan<'a>,
701) -> NomResult<'a, DestructureTail<'a, <T::Base as Grammar<'a>>::Type>>
702where
703 T: Parse<'a>,
704 Ty: GrammarType,
705{
706 tuple((
707 destructure_rest::<T, Ty>,
708 opt(preceded(comma_sep::<Ty>, comma_separated_lvalues::<T, Ty>)),
709 ))(input)
710}
711
712fn destructure<'a, T, Ty>(
714 input: InputSpan<'a>,
715) -> NomResult<'a, Destructure<'a, <T::Base as Grammar<'a>>::Type>>
716where
717 T: Parse<'a>,
718 Ty: GrammarType,
719{
720 let main_parser = alt((
721 map(destructure_tail::<T, Ty>, |rest| (vec![], Some(rest))),
723 tuple((
724 comma_separated_lvalues::<T, Ty>,
725 opt(preceded(comma_sep::<Ty>, destructure_tail::<T, Ty>)),
726 )),
727 ));
728 let main_parser = terminated(main_parser, opt(comma_sep::<Ty>));
730
731 map(main_parser, |(start, maybe_rest)| {
732 if let Some((middle, end)) = maybe_rest {
733 Destructure {
734 start,
735 middle: Some(middle),
736 end: end.unwrap_or_default(),
737 }
738 } else {
739 Destructure {
740 start,
741 middle: None,
742 end: vec![],
743 }
744 }
745 })(input)
746}
747
748type GrammarLvalue<'a, T> = SpannedLvalue<'a, <<T as Parse<'a>>::Base as Grammar<'a>>::Type>;
749
750fn parenthesized_destructure<'a, T, Ty>(input: InputSpan<'a>) -> NomResult<'a, GrammarLvalue<'a, T>>
751where
752 T: Parse<'a>,
753 Ty: GrammarType,
754{
755 with_span(map(
756 delimited(
757 terminated(tag_char('('), ws::<Ty>),
758 destructure::<T, Ty>,
759 preceded(ws::<Ty>, tag_char(')')),
760 ),
761 Lvalue::Tuple,
762 ))(input)
763}
764
765fn simple_lvalue_with_type<'a, T, Ty>(input: InputSpan<'a>) -> NomResult<'a, GrammarLvalue<'a, T>>
767where
768 T: Parse<'a>,
769 Ty: GrammarType,
770{
771 map(
772 tuple((
773 var_name,
774 opt(preceded(
775 delimited(ws::<Ty>, tag_char(':'), ws::<Ty>),
776 cut(with_span(<T::Base>::parse_type)),
777 )),
778 )),
779 |(name, ty)| Spanned::new(name, Lvalue::Variable { ty }),
780 )(input)
781}
782
783fn simple_lvalue_without_type<'a, T>(input: InputSpan<'a>) -> NomResult<'a, GrammarLvalue<'a, T>>
784where
785 T: Parse<'a>,
786{
787 map(var_name, |name| {
788 Spanned::new(name, Lvalue::Variable { ty: None })
789 })(input)
790}
791
792fn object_destructure_field<'a, T, Ty>(
793 input: InputSpan<'a>,
794) -> NomResult<'a, ObjectDestructureField<'a, <T::Base as Grammar<'a>>::Type>>
795where
796 T: Parse<'a>,
797 Ty: GrammarType,
798{
799 let field_sep = alt((tag(":"), tag("->")));
800 let field_sep = tuple((ws::<Ty>, field_sep, ws::<Ty>));
801 let field = tuple((var_name, opt(preceded(field_sep, lvalue::<T, Ty>))));
802 map(field, |(name, maybe_binding)| ObjectDestructureField {
803 field_name: Spanned::new(name, ()),
804 binding: maybe_binding,
805 })(input)
806}
807
808fn object_destructure<'a, T, Ty>(
809 input: InputSpan<'a>,
810) -> NomResult<'a, ObjectDestructure<'a, <T::Base as Grammar<'a>>::Type>>
811where
812 T: Parse<'a>,
813 Ty: GrammarType,
814{
815 let inner = separated_list1(comma_sep::<Ty>, object_destructure_field::<T, Ty>);
816 let inner = terminated(inner, opt(comma_sep::<Ty>));
817 let inner = delimited(
818 terminated(tag_char('{'), ws::<Ty>),
819 inner,
820 preceded(ws::<Ty>, tag_char('}')),
821 );
822 map(inner, |fields| ObjectDestructure { fields })(input)
823}
824
825fn mapped_object_destructure<'a, T, Ty>(input: InputSpan<'a>) -> NomResult<'a, GrammarLvalue<'a, T>>
826where
827 T: Parse<'a>,
828 Ty: GrammarType,
829{
830 with_span(map(object_destructure::<T, Ty>, Lvalue::Object))(input)
831}
832
833fn lvalue<'a, T, Ty>(input: InputSpan<'a>) -> NomResult<'a, GrammarLvalue<'a, T>>
835where
836 T: Parse<'a>,
837 Ty: GrammarType,
838{
839 fn error<'b, T>(input: InputSpan<'b>) -> NomResult<'b, GrammarLvalue<'b, T>>
840 where
841 T: Parse<'b>,
842 {
843 let e = ErrorKind::Leftovers.with_span(&input.into());
844 Err(NomErr::Error(e))
845 }
846
847 let simple_lvalue = if T::FEATURES.contains(Features::TYPE_ANNOTATIONS) {
848 simple_lvalue_with_type::<T, Ty>
849 } else {
850 simple_lvalue_without_type::<T>
851 };
852
853 let destructure = if T::FEATURES.contains(Features::TUPLES) {
854 parenthesized_destructure::<T, Ty>
855 } else {
856 error::<T>
857 };
858
859 let object_destructure = if T::FEATURES.contains(Features::OBJECTS) {
860 mapped_object_destructure::<T, Ty>
861 } else {
862 error::<T>
863 };
864
865 alt((destructure, object_destructure, simple_lvalue))(input)
866}
867
868#[allow(clippy::option_if_let_else)]
869fn statement<'a, T, Ty>(input: InputSpan<'a>) -> NomResult<'a, SpannedStatement<'a, T::Base>>
870where
871 T: Parse<'a>,
872 Ty: GrammarType,
873{
874 let assignment = tuple((tag("="), peek(not(tag_char('=')))));
875 let assignment_parser = tuple((
876 opt(terminated(
877 lvalue::<T, Ty>,
878 delimited(ws::<Ty>, assignment, ws::<Ty>),
879 )),
880 expr::<T, Ty>,
881 ));
882
883 with_span(map(assignment_parser, |(lvalue, rvalue)| {
884 if let Some(lvalue) = lvalue {
886 Statement::Assignment {
887 lhs: lvalue,
888 rhs: Box::new(rvalue),
889 }
890 } else {
891 Statement::Expr(rvalue)
892 }
893 }))(input)
894}
895
896pub(crate) fn statements<'a, T>(input_span: InputSpan<'a>) -> Result<Block<'a, T::Base>, Error<'a>>
898where
899 T: Parse<'a>,
900{
901 if !input_span.fragment().is_ascii() {
902 return Err(Error::new(input_span, ErrorKind::NonAsciiInput));
903 }
904 statements_inner::<T, Complete>(input_span)
905}
906
907pub(crate) fn streaming_statements<'a, T>(
909 input_span: InputSpan<'a>,
910) -> Result<Block<'a, T::Base>, Error<'a>>
911where
912 T: Parse<'a>,
913{
914 if !input_span.fragment().is_ascii() {
915 return Err(Error::new(input_span, ErrorKind::NonAsciiInput));
916 }
917
918 statements_inner::<T, Complete>(input_span)
919 .or_else(|_| statements_inner::<T, Streaming>(input_span))
920}
921
922fn statements_inner<'a, T, Ty>(input_span: InputSpan<'a>) -> Result<Block<'a, T::Base>, Error<'a>>
923where
924 T: Parse<'a>,
925 Ty: GrammarType,
926{
927 delimited(ws::<Ty>, separated_statements::<T, Ty>, ws::<Ty>)(input_span)
928 .map_err(|e| match e {
929 NomErr::Failure(e) | NomErr::Error(e) => e,
930 NomErr::Incomplete(_) => ErrorKind::Incomplete.with_span(&input_span.into()),
931 })
932 .and_then(|(remaining, statements)| {
933 if remaining.fragment().is_empty() {
934 Ok(statements)
935 } else {
936 Err(ErrorKind::Leftovers.with_span(&remaining.into()))
937 }
938 })
939}
940
941fn separated_statement<'a, T, Ty>(
942 input: InputSpan<'a>,
943) -> NomResult<'a, SpannedStatement<'a, T::Base>>
944where
945 T: Parse<'a>,
946 Ty: GrammarType,
947{
948 terminated(statement::<T, Ty>, preceded(ws::<Ty>, tag_char(';')))(input)
949}
950
951fn separated_statements<'a, T, Ty>(input: InputSpan<'a>) -> NomResult<'a, Block<'a, T::Base>>
953where
954 T: Parse<'a>,
955 Ty: GrammarType,
956{
957 map(
958 tuple((
959 many0(terminated(separated_statement::<T, Ty>, ws::<Ty>)),
960 opt(expr::<T, Ty>),
961 )),
962 |(statements, return_value)| Block {
963 statements,
964 return_value: return_value.map(Box::new),
965 },
966 )(input)
967}
968
969fn block<'a, T, Ty>(input: InputSpan<'a>) -> NomResult<'a, Block<'a, T::Base>>
971where
972 T: Parse<'a>,
973 Ty: GrammarType,
974{
975 preceded(
976 terminated(tag_char('{'), ws::<Ty>),
977 cut(terminated(
978 separated_statements::<T, Ty>,
979 preceded(ws::<Ty>, tag_char('}')),
980 )),
981 )(input)
982}
983
984fn fn_def<'a, T, Ty>(input: InputSpan<'a>) -> NomResult<'a, FnDefinition<'a, T::Base>>
986where
987 T: Parse<'a>,
988 Ty: GrammarType,
989{
990 let body_parser = alt((
991 block::<T, Ty>,
992 map(expr::<T, Ty>, |spanned| Block {
993 statements: vec![],
994 return_value: Some(Box::new(spanned)),
995 }),
996 ));
997
998 let args_parser = preceded(
999 terminated(tag_char('|'), ws::<Ty>),
1000 cut(terminated(
1001 destructure::<T, Ty>,
1002 preceded(ws::<Ty>, tag_char('|')),
1003 )),
1004 );
1005
1006 let parser = tuple((with_span(args_parser), cut(preceded(ws::<Ty>, body_parser))));
1007 map(parser, |(args, body)| FnDefinition { args, body })(input)
1008}