Skip to main content

nom_kconfig/attribute/
function.rs

1#[cfg(feature = "display")]
2use std::fmt::Display;
3
4use nom::{
5    branch::alt,
6    bytes::complete::{tag, take_until},
7    character::complete::{alphanumeric1, char, one_of, space1},
8    combinator::{map, opt, recognize},
9    multi::{many1, separated_list0},
10    sequence::{delimited, preceded, terminated},
11    IResult, Parser,
12};
13#[cfg(feature = "deserialize")]
14use serde::Deserialize;
15#[cfg(feature = "serialize")]
16use serde::Serialize;
17
18use crate::{util::ws, KconfigInput};
19
20#[derive(Debug, PartialEq, Clone, Default)]
21#[cfg_attr(feature = "hash", derive(Hash))]
22#[cfg_attr(feature = "serialize", derive(Serialize))]
23#[cfg_attr(feature = "deserialize", derive(Deserialize))]
24pub struct FunctionCall {
25    pub name: String,
26    pub parameters: Vec<Parameter>,
27}
28
29#[cfg(feature = "display")]
30impl Display for Parameter {
31    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
32        write!(
33            f,
34            "{}",
35            self.tokens
36                .iter()
37                .map(|d: &ExpressionToken| d.to_string())
38                .collect::<Vec<_>>()
39                .join("")
40        )
41    }
42}
43
44#[cfg(feature = "display")]
45impl Display for ExpressionToken {
46    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
47        match self {
48            ExpressionToken::Literal(s) => write!(f, "{}", s),
49            ExpressionToken::Variable(v) => write!(f, "${}", v),
50            ExpressionToken::DoubleQuotes(s) => write!(
51                f,
52                r#""{}""#,
53                s.iter().map(|d| d.to_string()).collect::<Vec<_>>().join("")
54            ),
55            ExpressionToken::SingleQuotes(s) => write!(f, "'{}'", s),
56            ExpressionToken::Backtick(c) => write!(f, "`{}`", c),
57            ExpressionToken::Function(func) => write!(f, "{}", func),
58            ExpressionToken::Space => write!(f, " "),
59        }
60    }
61}
62
63#[cfg(feature = "display")]
64impl Display for FunctionCall {
65    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
66        if self.parameters.is_empty() {
67            return write!(f, "$({})", self.name);
68        }
69        write!(
70            f,
71            "$({}, {})",
72            self.name,
73            self.parameters
74                .iter()
75                .map(|d| d.to_string())
76                .collect::<Vec<_>>()
77                .join(", ")
78        )
79    }
80}
81
82#[derive(Debug, PartialEq, Clone, Default)]
83#[cfg_attr(feature = "hash", derive(Hash))]
84#[cfg_attr(feature = "serialize", derive(Serialize))]
85#[cfg_attr(feature = "deserialize", derive(Deserialize))]
86pub struct Parameter {
87    pub tokens: Vec<ExpressionToken>,
88}
89
90#[derive(Debug, PartialEq, Clone)]
91#[cfg_attr(feature = "hash", derive(Hash))]
92#[cfg_attr(feature = "serialize", derive(Serialize))]
93#[cfg_attr(feature = "deserialize", derive(Deserialize))]
94pub enum ExpressionToken {
95    Literal(String),
96    Variable(String),
97    DoubleQuotes(Vec<ExpressionToken>),
98    SingleQuotes(String),
99    Backtick(String),
100    Function(Box<FunctionCall>),
101    Space,
102}
103
104pub fn parse_expression_token_variable_parameter(
105    input: KconfigInput,
106) -> IResult<KconfigInput, ExpressionToken> {
107    map(
108        delimited(
109            tag("$("),
110            recognize(ws(many1(recognize(one_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ_"))))),
111            tag(")"),
112        ),
113        |d: KconfigInput| ExpressionToken::Variable(d.fragment().to_string()),
114    )
115    .parse(input)
116}
117
118fn parse_expression_token_parameter(input: KconfigInput) -> IResult<KconfigInput, ExpressionToken> {
119    alt((
120        map(tag("="), |_| ExpressionToken::Literal("=".to_string())),
121        map(space1, |_| ExpressionToken::Space),
122        map(tag("2>"), |_| ExpressionToken::Literal("2>".to_string())),
123        map(
124            delimited(tag("\""), parse_expression_parameter, tag("\"")),
125            ExpressionToken::DoubleQuotes,
126        ),
127        map(
128            delimited(tag("("), take_until(")"), tag(")")),
129            |d: KconfigInput| ExpressionToken::Literal("(".to_string() + d.fragment() + ")"),
130        ),
131        map(
132            delimited(tag("`"), take_until("`"), tag("`")),
133            |d: KconfigInput| ExpressionToken::Backtick(d.to_string()),
134        ),
135        map(
136            delimited(
137                ws(char::<KconfigInput, _>('\'')),
138                take_until("'"),
139                char('\''),
140            ),
141            |d| ExpressionToken::SingleQuotes(d.to_string()),
142        ),
143        parse_literal_parameter,
144        parse_expression_token_variable_parameter,
145        map(parse_function_call, |f| {
146            ExpressionToken::Function(Box::new(f))
147        }),
148    ))
149    .parse(input)
150}
151
152fn parse_instruction_parameter(input: KconfigInput) -> IResult<KconfigInput, String> {
153    map(
154        (
155            tag("%"),
156            recognize(ws(many1(alt((alphanumeric1, recognize(one_of("_"))))))),
157            delimited(tag("("), alphanumeric1, tag(")")),
158        ),
159        |(_a, b, c)| format!("%{}({})", b, c),
160    )
161    .parse(input)
162}
163
164fn parse_env_variable_parameter(input: KconfigInput) -> IResult<KconfigInput, ExpressionToken> {
165    map(
166        ws(preceded(tag("$"), recognize(many1(alphanumeric1)))),
167        |d| ExpressionToken::Literal(format!("${}", d)),
168    )
169    .parse(input)
170}
171
172fn parse_literal_parameter(input: KconfigInput) -> IResult<KconfigInput, ExpressionToken> {
173    alt((
174        parse_env_variable_parameter,
175        map(parse_instruction_parameter, ExpressionToken::Literal),
176        map(
177            recognize(ws(many1(alt((
178                alphanumeric1,
179                tag("\\$"),
180                recognize(one_of("+(<>%&\\[]_|'.-:\n\\/")),
181            ))))),
182            |d: KconfigInput| ExpressionToken::Literal(d.fragment().to_string()),
183        ),
184    ))
185    .parse(input)
186}
187
188pub fn parse_expression_parameter(
189    input: KconfigInput,
190) -> IResult<KconfigInput, Vec<ExpressionToken>> {
191    alt((many1(parse_expression_token_parameter),)).parse(input)
192}
193
194pub fn parse_parameter(input: KconfigInput) -> IResult<KconfigInput, Parameter> {
195    map(alt((parse_expression_parameter,)), |d| Parameter {
196        tokens: d,
197    })
198    .parse(input)
199}
200
201fn parse_function_name(input: KconfigInput<'_>) -> IResult<KconfigInput<'_>, &str> {
202    map(
203        recognize(ws(many1(alt((alphanumeric1, recognize(one_of("=-"))))))),
204        |d: KconfigInput| d.fragment().to_owned(),
205    )
206    .parse(input)
207}
208
209pub fn parse_function_call(input: KconfigInput) -> IResult<KconfigInput, FunctionCall> {
210    ws(alt((
211        parse_function_call_inner,
212        delimited(char('"'), parse_function_call_inner, char('"')),
213    )))
214    .parse(input)
215}
216
217fn parse_function_call_inner(input: KconfigInput) -> IResult<KconfigInput, FunctionCall> {
218    map(
219        delimited(
220            tag("$("),
221            (
222                terminated(parse_function_name, opt(ws(tag(",")))),
223                separated_list0(ws(tag(",")), ws(parse_parameter)),
224            ),
225            ws(tag(")")),
226        ),
227        |(name, parameters)| FunctionCall {
228            name: name.to_string(),
229            parameters,
230        },
231    )
232    .parse(input)
233}