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 alt((
72 delimited(tag("'"), take_until_unbalanced('\''), tag("'")),
73 delimited(tag("\""), take_until_unbalanced('"'), tag("\"")),
74 )),
75 |d| d.fragment().to_string(),
76 )
77 .parse(input)
78}
79
80pub fn take_until_unbalanced(
81 delimiter: char,
82) -> impl Fn(KconfigInput) -> IResult<KconfigInput, KconfigInput> {
83 move |i: KconfigInput| {
84 let mut index: usize = 0;
85 let mut delimiter_counter = 0;
86
87 let end_of_line = match &i.find('\n') {
88 Some(e) => *e,
89 None => i.len(),
90 };
91
92 while let Some(n) = &i[index..end_of_line].find(delimiter) {
93 delimiter_counter += 1;
94 index += n + 1;
95 }
96
97 index -= 1;
99 delimiter_counter -= 1;
101
102 match delimiter_counter % 2 == 0 {
103 true => Ok(i.take_split(index)),
104 false => Err(nom::Err::Error(Error::from_error_kind(
105 i,
106 ErrorKind::TakeUntil,
107 ))),
108 }
109 }
110}
111
112pub fn parse_number_or_symbol(input: KconfigInput) -> IResult<KconfigInput, Atom> {
114 let (input, sym) = parse_symbol(input)?;
115 match sym.clone() {
116 Symbol::Constant(s) => match string_to_number(s.as_str()) {
117 Ok((_, i)) => Ok((input, Atom::Number(i))),
118 Err(_) => Ok((input, Atom::Symbol(sym))),
119 },
120 Symbol::NonConstant(_) => Ok((input, Atom::Symbol(sym))),
121 }
122}
123
124pub fn string_to_number(input: &str) -> IResult<&str, i64> {
125 all_consuming(map_res(recognize(pair(opt(char('-')), digit1)), |d| {
126 FromStr::from_str(d)
127 }))
128 .parse(input)
129}