1#[cfg(feature = "display")]
2use std::fmt::Display;
3use std::str::FromStr;
4
5use nom::{
6 branch::alt,
7 bytes::complete::tag,
8 character::complete::{char, digit1},
9 combinator::{all_consuming, map, map_res, opt, recognize, value},
10 error::{Error, ErrorKind, ParseError},
11 multi::many0,
12 sequence::{delimited, pair, preceded},
13 IResult, Input, Parser,
14};
15#[cfg(feature = "deserialize")]
16use serde::Deserialize;
17#[cfg(feature = "serialize")]
18use serde::Serialize;
19
20use crate::{
21 symbol::{parse_symbol, Symbol},
22 util::wsi,
23 KconfigInput,
24};
25
26use super::function::{parse_function_call, FunctionCall};
27
28#[derive(Debug, PartialEq, Clone)]
29#[cfg_attr(feature = "serialize", derive(Serialize))]
30#[cfg_attr(feature = "deserialize", derive(Deserialize))]
31pub enum Operator {
32 And,
33 Or,
34}
35
36#[derive(Debug, PartialEq, Clone)]
37#[cfg_attr(feature = "hash", derive(Hash))]
38#[cfg_attr(feature = "serialize", derive(Serialize))]
39#[cfg_attr(feature = "deserialize", derive(Deserialize))]
40pub enum CompareOperator {
41 GreaterThan,
42 GreaterOrEqual,
43 LowerThan,
44 LowerOrEqual,
45 Equal,
46 NotEqual,
47}
48
49#[cfg(feature = "display")]
50impl Display for CompareOperator {
51 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
52 match self {
53 CompareOperator::GreaterThan => write!(f, ">"),
54 CompareOperator::GreaterOrEqual => write!(f, ">="),
55 CompareOperator::LowerThan => write!(f, "<"),
56 CompareOperator::LowerOrEqual => write!(f, "<="),
57 CompareOperator::Equal => write!(f, "="),
58 CompareOperator::NotEqual => write!(f, "!="),
59 }
60 }
61}
62
63pub type Expression = OrExpression;
65#[cfg_attr(feature = "hash", derive(Hash))]
66#[cfg_attr(feature = "serialize", derive(Serialize))]
67#[cfg_attr(feature = "deserialize", derive(Deserialize))]
68#[derive(Debug, PartialEq, Clone)]
69pub enum AndExpression {
70 #[cfg_attr(feature = "serialize", serde(rename = "AndTerm"))]
71 Term(Term),
72 #[cfg_attr(feature = "serialize", serde(rename = "And"))]
73 Expression(Vec<Term>),
74}
75
76#[derive(Debug, PartialEq, Clone)]
77#[cfg_attr(feature = "hash", derive(Hash))]
78#[cfg_attr(feature = "serialize", derive(Serialize))]
79#[cfg_attr(feature = "deserialize", derive(Deserialize))]
80pub enum OrExpression {
81 #[cfg_attr(feature = "serialize", serde(rename = "OrTerm"))]
82 Term(AndExpression),
83 #[cfg_attr(feature = "serialize", serde(rename = "Or"))]
84 Expression(Vec<AndExpression>),
85}
86
87#[derive(Debug, PartialEq, Clone)]
88#[cfg_attr(feature = "hash", derive(Hash))]
89#[cfg_attr(feature = "serialize", derive(Serialize))]
90#[cfg_attr(feature = "deserialize", derive(Deserialize))]
91pub enum Term {
92 Not(Atom),
93 Atom(Atom),
94}
95
96#[derive(Debug, PartialEq, Clone)]
97#[cfg_attr(feature = "hash", derive(Hash))]
98#[cfg_attr(feature = "serialize", derive(Serialize))]
99#[cfg_attr(feature = "deserialize", derive(Deserialize))]
100#[cfg_attr(feature = "serialize", serde(rename = "Compare"))]
101pub struct CompareExpression {
102 pub left: Symbol,
103 pub operator: CompareOperator,
104 pub right: Symbol,
105}
106
107#[cfg(feature = "display")]
108impl Display for CompareExpression {
109 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
110 write!(f, "{} {} {}", self.left, self.operator, self.right)
111 }
112}
113
114#[derive(Debug, PartialEq, Clone)]
115#[cfg_attr(feature = "hash", derive(Hash))]
116#[cfg_attr(feature = "serialize", derive(Serialize))]
117#[cfg_attr(feature = "deserialize", derive(Deserialize))]
118pub enum Atom {
119 Symbol(Symbol),
120 Number(i64),
121 Compare(CompareExpression),
122 Function(FunctionCall),
123 Parenthesis(Box<Expression>),
124 String(String),
125}
126
127#[cfg(feature = "display")]
128impl Display for AndExpression {
129 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
130 match self {
131 Self::Term(t) => write!(f, "{}", t),
132 Self::Expression(t) => write!(
133 f,
134 "{}",
135 t.iter()
136 .map(|a| a.to_string())
137 .collect::<Vec<_>>()
138 .join(" && ")
139 ),
140 }
141 }
142}
143
144#[cfg(feature = "display")]
145impl Display for OrExpression {
146 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
147 match self {
148 Self::Term(t) => write!(f, "{}", t),
149 Self::Expression(t) => write!(
150 f,
151 "{}",
152 t.iter()
153 .map(|a| a.to_string())
154 .collect::<Vec<_>>()
155 .join(" || ")
156 ),
157 }
158 }
159}
160
161#[cfg(feature = "display")]
162impl Display for Term {
163 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
164 match self {
165 Term::Not(atom) => write!(f, "!{}", atom),
166 Term::Atom(atom) => write!(f, "{}", atom),
167 }
168 }
169}
170
171#[cfg(feature = "display")]
172impl Display for Atom {
173 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
174 match self {
175 Atom::Symbol(s) => write!(f, "{}", s),
176 Atom::Number(d) => write!(f, "{}", d),
177 Atom::Compare(c) => write!(f, "{}", c),
178 Atom::Function(func) => write!(f, "{}", func),
179 Atom::Parenthesis(d) => write!(f, "({})", d),
180 Atom::String(s) => write!(f, r#""{}""#, s),
181 }
182 }
183}
184
185pub fn parse_or_expression(input: KconfigInput) -> IResult<KconfigInput, OrExpression> {
186 map(
187 (
188 wsi(parse_and_expression),
189 many0(preceded(wsi(tag("||")), wsi(parse_and_expression))),
190 ),
191 |(l, ee)| {
192 if ee.is_empty() {
193 OrExpression::Term(l)
194 } else {
195 let mut ll = vec![l];
196 ll.extend(ee);
197 OrExpression::Expression(ll)
198 }
199 },
200 )
201 .parse(input)
202}
203
204pub fn parse_and_expression(input: KconfigInput) -> IResult<KconfigInput, AndExpression> {
205 map(
206 (
207 wsi(parse_term),
208 many0(preceded(wsi(tag("&&")), wsi(parse_term))),
209 ),
210 |(l, ee)| {
211 if ee.is_empty() {
212 AndExpression::Term(l)
213 } else {
214 let mut ll = vec![l];
215 ll.extend(ee);
216 AndExpression::Expression(ll)
217 }
218 },
219 )
220 .parse(input)
221}
222
223pub fn parse_term(input: KconfigInput) -> IResult<KconfigInput, Term> {
224 alt((
225 map(preceded(wsi(tag("!")), parse_atom), Term::Not),
226 map(parse_atom, Term::Atom),
227 ))
228 .parse(input)
229}
230
231pub fn parse_atom(input: KconfigInput) -> IResult<KconfigInput, Atom> {
232 alt((
233 wsi(parse_compare),
234 map(parse_function_call, Atom::Function),
235 map(
236 delimited(wsi(tag("(")), parse_expression, wsi(tag(")"))),
237 |expr: Expression| Atom::Parenthesis(Box::new(expr)),
238 ),
239 map(parse_string, Atom::String),
240 parse_number_or_symbol,
241 map(parse_number, Atom::Number),
243 ))
244 .parse(input)
245}
246
247pub fn parse_string(input: KconfigInput) -> IResult<KconfigInput, String> {
248 map(
249 delimited(tag("\""), take_until_unbalanced('"'), tag("\"")),
250 |d| d.fragment().to_string(),
251 )
252 .parse(input)
253}
254
255pub fn take_until_unbalanced(
256 delimiter: char,
257) -> impl Fn(KconfigInput) -> IResult<KconfigInput, KconfigInput> {
258 move |i: KconfigInput| {
259 let mut index: usize = 0;
260 let mut delimiter_counter = 0;
261
262 let end_of_line = match &i.find('\n') {
263 Some(e) => *e,
264 None => i.len(),
265 };
266
267 while let Some(n) = &i[index..end_of_line].find(delimiter) {
268 delimiter_counter += 1;
269 index += n + 1;
270 }
271
272 index -= 1;
274 delimiter_counter -= 1;
276
277 match delimiter_counter % 2 == 0 {
278 true => Ok(i.take_split(index)),
279 false => Err(nom::Err::Error(Error::from_error_kind(
280 i,
281 ErrorKind::TakeUntil,
282 ))),
283 }
284 }
285}
286
287pub fn parse_expression(input: KconfigInput) -> IResult<KconfigInput, Expression> {
288 parse_or_expression(input)
289}
290
291pub fn parse_compare_operator(input: KconfigInput) -> IResult<KconfigInput, CompareOperator> {
292 alt((
293 value(CompareOperator::GreaterOrEqual, tag(">=")),
294 value(CompareOperator::LowerOrEqual, tag("<=")),
295 value(CompareOperator::GreaterThan, tag(">")),
296 value(CompareOperator::LowerThan, tag("<")),
297 value(CompareOperator::Equal, tag("=")),
298 value(CompareOperator::NotEqual, tag("!=")),
299 ))
300 .parse(input)
301}
302
303pub fn parse_compare(input: KconfigInput) -> IResult<KconfigInput, Atom> {
304 map(
305 (
306 wsi(parse_symbol),
307 wsi(parse_compare_operator),
308 wsi(parse_symbol),
309 ),
310 |(l, o, r)| {
311 Atom::Compare(CompareExpression {
312 left: l,
313 operator: o,
314 right: r,
315 })
316 },
317 )
318 .parse(input)
319}
320
321pub fn parse_number_or_symbol(input: KconfigInput) -> IResult<KconfigInput, Atom> {
323 let (input, sym) = parse_symbol(input)?;
324 match sym.clone() {
325 Symbol::Constant(s) => match string_to_number(s.as_str()) {
326 Ok((_, i)) => Ok((input, Atom::Number(i))),
327 Err(_) => Ok((input, Atom::Symbol(sym))),
328 },
329 Symbol::NonConstant(_) => Ok((input, Atom::Symbol(sym))),
330 }
331}
332
333pub fn string_to_number(input: &str) -> IResult<&str, i64> {
334 all_consuming(map_res(recognize(pair(opt(char('-')), digit1)), |d| {
335 FromStr::from_str(d)
336 }))
337 .parse(input)
338}
339
340pub fn parse_if_attribute(input: KconfigInput) -> IResult<KconfigInput, Option<Expression>> {
341 opt(parse_if_expression).parse(input)
342}
343
344pub fn parse_if_expression(input: KconfigInput) -> IResult<KconfigInput, Expression> {
345 map(pair(wsi(tag("if")), wsi(parse_expression)), |(_, e)| e).parse(input)
346}
347
348pub fn parse_number(input: KconfigInput) -> IResult<KconfigInput, i64> {
349 map_res(
350 recognize(pair(opt(char('-')), digit1)),
351 |d: KconfigInput| FromStr::from_str(d.fragment()),
352 )
353 .parse(input)
354}