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