rsass/parser/
formalargs.rs

1use super::strings::name;
2use super::util::{ignore_comments, opt_spacelike};
3use super::value::space_list;
4use super::{PResult, Span};
5use crate::sass::{CallArgs, FormalArgs, Name};
6use nom::bytes::complete::tag;
7use nom::character::complete::char;
8use nom::combinator::{cut, map, map_res, opt};
9use nom::error::context;
10use nom::multi::separated_list0;
11use nom::sequence::{delimited, pair, preceded, terminated};
12use nom::Parser as _;
13
14pub fn formal_args(input: Span) -> PResult<FormalArgs> {
15    let (input, _) = terminated(char('('), opt_spacelike).parse(input)?;
16    let (input, v) = separated_list0(
17        preceded(tag(","), opt_spacelike),
18        map(
19            pair(
20                delimited(tag("$"), name, opt_spacelike),
21                opt(delimited(
22                    terminated(tag(":"), opt_spacelike),
23                    cut(context("Expected expression.", space_list)),
24                    opt_spacelike,
25                )),
26            ),
27            |(name, d)| (name.into(), d),
28        ),
29    )
30    .parse(input)?;
31    let (input, va) = if !v.is_empty() {
32        terminated(
33            opt(tag("...")),
34            preceded(opt_spacelike, terminated(opt(tag(",")), opt_spacelike)),
35        )
36        .parse(input)?
37    } else {
38        (input, None)
39    };
40    let (input, _) = char(')')(input)?;
41    Ok((
42        input,
43        if va.is_none() {
44            FormalArgs::new(v)
45        } else {
46            FormalArgs::new_va(v)
47        },
48    ))
49}
50
51pub fn call_args(input: Span) -> PResult<CallArgs> {
52    delimited(
53        terminated(char('('), opt_spacelike),
54        map_res(
55            |input| {
56                let (input, args) = separated_list0(
57                    terminated(tag(","), opt_spacelike),
58                    pair(
59                        opt(map(
60                            delimited(
61                                tag("$"),
62                                name,
63                                delimited(
64                                    ignore_comments,
65                                    char(':'),
66                                    opt_spacelike,
67                                ),
68                            ),
69                            Name::from,
70                        )),
71                        terminated(space_list, opt_spacelike),
72                    ),
73                )
74                .parse(input)?;
75                let (input, trail) = if !args.is_empty() {
76                    opt(terminated(char(','), opt_spacelike)).parse(input)?
77                } else {
78                    (input, None)
79                };
80                Ok((input, (args, trail)))
81            },
82            |(args, trail)| CallArgs::new(args, trail.is_some()),
83        ),
84        cut(char(')')),
85    )
86    .parse(input)
87}