Skip to main content

nom_kconfig/attribute/
function.rs

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