nom_kconfig/attribute/expression/
atom.rs1use crate::attribute::expression::parse_compare;
2use crate::attribute::{
3 parse_expression, parse_function_call, CompareExpression, Expression, FunctionCall,
4};
5use crate::number::parse_number;
6use crate::symbol::parse_symbol;
7use crate::util::wsi;
8use crate::{KconfigInput, Symbol};
9use nom::{
10 branch::alt,
11 bytes::complete::tag,
12 character::complete::{char, digit1},
13 combinator::{all_consuming, map, map_res, opt, recognize},
14 error::{Error, ErrorKind, ParseError},
15 sequence::{delimited, pair},
16 IResult, Input, Parser,
17};
18#[cfg(feature = "deserialize")]
19use serde::Deserialize;
20#[cfg(feature = "serialize")]
21use serde::Serialize;
22#[cfg(feature = "display")]
23use std::fmt::Display;
24use std::str::FromStr;
25
26#[derive(Debug, PartialEq, Clone)]
27#[cfg_attr(feature = "hash", derive(Hash))]
28#[cfg_attr(feature = "serialize", derive(Serialize))]
29#[cfg_attr(feature = "deserialize", derive(Deserialize))]
30pub enum Atom {
31 Symbol(Symbol),
32 Number(i64),
33 Compare(CompareExpression),
34 Function(FunctionCall),
35 Parenthesis(Box<Expression>),
36 String(String),
37}
38
39#[cfg(feature = "display")]
40impl Display for Atom {
41 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
42 match self {
43 Atom::Symbol(s) => write!(f, "{}", s),
44 Atom::Number(d) => write!(f, "{}", d),
45 Atom::Compare(c) => write!(f, "{}", c),
46 Atom::Function(func) => write!(f, "{}", func),
47 Atom::Parenthesis(d) => write!(f, "({})", d),
48 Atom::String(s) => write!(f, r#""{}""#, s),
49 }
50 }
51}
52
53pub fn parse_atom(input: KconfigInput) -> IResult<KconfigInput, Atom> {
54 alt((
55 wsi(parse_compare),
56 map(parse_function_call, Atom::Function),
57 map(
58 delimited(wsi(tag("(")), parse_expression, wsi(tag(")"))),
59 |expr: Expression| Atom::Parenthesis(Box::new(expr)),
60 ),
61 parse_number_or_symbol,
62 map(parse_number, Atom::Number),
64 map(parse_string, Atom::String),
65 ))
66 .parse(input)
67}
68
69pub fn parse_string(input: KconfigInput) -> IResult<KconfigInput, String> {
70 map(
71 delimited(tag("\""), take_until_unbalanced('"'), tag("\"")),
72 |d| d.fragment().to_string(),
73 )
74 .parse(input)
75}
76
77pub fn take_until_unbalanced(
78 delimiter: char,
79) -> impl Fn(KconfigInput) -> IResult<KconfigInput, KconfigInput> {
80 move |i: KconfigInput| {
81 let mut index: usize = 0;
82 let mut delimiter_counter = 0;
83
84 let end_of_line = match &i.find('\n') {
85 Some(e) => *e,
86 None => i.len(),
87 };
88
89 while let Some(n) = &i[index..end_of_line].find(delimiter) {
90 delimiter_counter += 1;
91 index += n + 1;
92 }
93
94 index -= 1;
96 delimiter_counter -= 1;
98
99 match delimiter_counter % 2 == 0 {
100 true => Ok(i.take_split(index)),
101 false => Err(nom::Err::Error(Error::from_error_kind(
102 i,
103 ErrorKind::TakeUntil,
104 ))),
105 }
106 }
107}
108
109pub fn parse_number_or_symbol(input: KconfigInput) -> IResult<KconfigInput, Atom> {
111 let (input, sym) = parse_symbol(input)?;
112 match sym.clone() {
113 Symbol::Constant(s) => match string_to_number(s.as_str()) {
114 Ok((_, i)) => Ok((input, Atom::Number(i))),
115 Err(_) => Ok((input, Atom::Symbol(sym))),
116 },
117 Symbol::NonConstant(_) => Ok((input, Atom::Symbol(sym))),
118 }
119}
120
121pub fn string_to_number(input: &str) -> IResult<&str, i64> {
122 all_consuming(map_res(recognize(pair(opt(char('-')), digit1)), |d| {
123 FromStr::from_str(d)
124 }))
125 .parse(input)
126}