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, tuple},
10 IResult,
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 )(input)
111}
112
113fn parse_expression_token_parameter(input: KconfigInput) -> IResult<KconfigInput, ExpressionToken> {
114 alt((
115 map(tag("="), |_| ExpressionToken::Literal("=".to_string())),
116 map(space1, |_| ExpressionToken::Space),
117 map(tag("2>"), |_| ExpressionToken::Literal("2>".to_string())),
118 map(
119 delimited(tag("\""), parse_expression_parameter, tag("\"")),
120 ExpressionToken::DoubleQuotes,
121 ),
122 map(
123 delimited(tag("("), take_until(")"), tag(")")),
124 |d: KconfigInput| ExpressionToken::Literal("(".to_string() + d.fragment() + ")"),
125 ),
126 map(
127 delimited(tag("`"), take_until("`"), tag("`")),
128 |d: KconfigInput| ExpressionToken::Backtick(d.to_string()),
129 ),
130 map(
131 delimited(
132 ws(char::<KconfigInput, _>('\'')),
133 take_until("'"),
134 char('\''),
135 ),
136 |d| ExpressionToken::SingleQuotes(d.to_string()),
137 ),
138 parse_literal_parameter,
139 parse_expression_token_variable_parameter,
140 map(parse_function_call, |f| {
141 ExpressionToken::Function(Box::new(f))
142 }),
143 ))(input)
144}
145
146fn parse_instruction_parameter(input: KconfigInput) -> IResult<KconfigInput, String> {
147 map(
148 tuple((
149 tag("%"),
150 recognize(ws(many1(alt((alphanumeric1, recognize(one_of("_"))))))),
151 delimited(tag("("), alphanumeric1, tag(")")),
152 )),
153 |(_a, b, c)| format!("%{}({})", b, c),
154 )(input)
155}
156
157fn parse_env_variable_parameter(input: KconfigInput) -> IResult<KconfigInput, ExpressionToken> {
158 map(
159 ws(preceded(tag("$"), recognize(many1(alphanumeric1)))),
160 |d| ExpressionToken::Literal(format!("${}", d)),
161 )(input)
162}
163
164fn parse_literal_parameter(input: KconfigInput) -> IResult<KconfigInput, ExpressionToken> {
165 alt((
166 parse_env_variable_parameter,
167 map(parse_instruction_parameter, ExpressionToken::Literal),
168 map(
169 recognize(ws(many1(alt((
170 alphanumeric1,
171 tag("\\$"),
172 recognize(one_of("+(<>%&\\[]_|'.-:\n\\/")),
173 ))))),
174 |d: KconfigInput| ExpressionToken::Literal(d.fragment().to_string()),
175 ),
176 ))(input)
177}
178
179pub fn parse_expression_parameter(
180 input: KconfigInput,
181) -> IResult<KconfigInput, Vec<ExpressionToken>> {
182 alt((many1(parse_expression_token_parameter),))(input)
183}
184
185pub fn parse_parameter(input: KconfigInput) -> IResult<KconfigInput, Parameter> {
186 map(alt((parse_expression_parameter,)), |d| Parameter {
187 tokens: d,
188 })(input)
189}
190
191fn parse_function_name(input: KconfigInput) -> IResult<KconfigInput, &str> {
192 map(
193 recognize(ws(many1(alt((alphanumeric1, recognize(one_of("=-"))))))),
194 |d: KconfigInput| d.fragment().to_owned(),
195 )(input)
196}
197
198pub fn parse_function_call(input: KconfigInput) -> IResult<KconfigInput, FunctionCall> {
199 map(
200 delimited(
201 tag("$("),
202 tuple((
203 terminated(parse_function_name, opt(ws(tag(",")))),
204 separated_list0(ws(tag(",")), ws(parse_parameter)),
205 )),
206 ws(tag(")")),
207 ),
208 |(name, parameters)| FunctionCall {
209 name: name.to_string(),
210 parameters,
211 },
212 )(input)
213}