Skip to main content

nom_kconfig/
symbol.rs

1use super::util::ws;
2use crate::number::parse_number;
3use crate::string::{parse_first_word, parse_string};
4use crate::tristate::Tristate;
5use crate::KconfigInput;
6use nom::bytes::tag;
7use nom::combinator::complete;
8use nom::{
9    branch::alt,
10    bytes::{tag_no_case, take_until},
11    character::complete::{alphanumeric1, char, hex_digit1, one_of},
12    combinator::{all_consuming, map, recognize},
13    multi::many1,
14    sequence::{delimited, pair},
15    IResult, Parser,
16};
17#[cfg(feature = "deserialize")]
18use serde::Deserialize;
19#[cfg(feature = "serialize")]
20use serde::Serialize;
21#[cfg(feature = "display")]
22use std::fmt::Display;
23
24/// There are two types of symbols: constant and non-constant symbols. Non-constant symbols are the most
25/// common ones and are defined with the 'config' statement. Non-constant symbols consist entirely of al-
26/// phanumeric characters or underscores. Constant symbols are only part of expressions. Constant symbols
27/// are always surrounded by single or double quotes. Within the quote, any other character is allowed and
28/// the quotes can be escaped using ''.
29#[derive(Debug, PartialEq, Clone)]
30#[cfg_attr(feature = "hash", derive(Hash))]
31#[cfg_attr(feature = "serialize", derive(Serialize))]
32#[cfg_attr(feature = "deserialize", derive(Deserialize))]
33pub enum Symbol {
34    Constant(ConstantSymbol),
35    NonConstant(String),
36}
37
38#[derive(Debug, PartialEq, Clone)]
39#[cfg_attr(feature = "hash", derive(Hash))]
40#[cfg_attr(feature = "serialize", derive(Serialize))]
41#[cfg_attr(feature = "deserialize", derive(Deserialize))]
42pub enum ConstantSymbol {
43    Integer(i64),
44    Hex(String),
45    Boolean(bool),
46    String(String),
47    Tristate(Tristate),
48}
49
50pub fn parse_constant_symbol(input: KconfigInput) -> IResult<KconfigInput, ConstantSymbol> {
51    alt((
52        all_consuming(parse_constant_bool),
53        all_consuming(parse_constant_tristate),
54        all_consuming(parse_constant_hex),
55        all_consuming(parse_constant_int),
56        all_consuming(parse_constant_string),
57    ))
58    .parse(input)
59}
60
61fn parse_env(input: KconfigInput) -> IResult<KconfigInput, Symbol> {
62    all_consuming(complete(map(
63        delimited(tag("\"$("), take_until(")\""), tag(")\"")),
64        |e: KconfigInput| Symbol::NonConstant(format!("$({})", e.fragment())),
65    )))
66    .parse(input)
67}
68
69pub fn parse_symbol(input: KconfigInput) -> IResult<KconfigInput, Symbol> {
70    let first_word = parse_first_word.parse(input)?;
71    let ok = alt((
72        parse_env,
73        map(parse_constant_symbol, Symbol::Constant),
74        map(parse_non_constant_symbol, |c: &str| {
75            Symbol::NonConstant(c.to_string())
76        }),
77        map(all_consuming(parse_constant_string), |c| {
78            Symbol::Constant(c)
79        }),
80    ))
81    .parse(first_word.1)?;
82    Ok((first_word.0, ok.1))
83}
84
85pub fn parse_constant_int(input: KconfigInput<'_>) -> IResult<KconfigInput<'_>, ConstantSymbol> {
86    map(parse_number, |integer: i64| {
87        ConstantSymbol::Integer(integer)
88    })
89    .parse(input)
90}
91
92pub fn parse_constant_bool(input: KconfigInput<'_>) -> IResult<KconfigInput<'_>, ConstantSymbol> {
93    ws(private_parse_constant_bool).parse(input)
94}
95
96pub fn parse_constant_hex(input: KconfigInput<'_>) -> IResult<KconfigInput<'_>, ConstantSymbol> {
97    ws(map(parse_constant_hex_as_string, |e| {
98        ConstantSymbol::Hex(e)
99    }))
100    .parse(input)
101}
102
103pub fn parse_constant_hex_as_string(input: KconfigInput<'_>) -> IResult<KconfigInput<'_>, String> {
104    ws(map(
105        pair(complete(tag_no_case("0x")), hex_digit1),
106        |(prefix, v): (KconfigInput, KconfigInput)| {
107            format!("{}{}", prefix.fragment(), v.fragment())
108        },
109    ))
110    .parse(input)
111}
112
113pub fn parse_constant_tristate(
114    input: KconfigInput<'_>,
115) -> IResult<KconfigInput<'_>, ConstantSymbol> {
116    ws(alt((
117        map(char('m'), |_| ConstantSymbol::Tristate(Tristate::Module)),
118        map(parse_constant_bool, |c| match c {
119            ConstantSymbol::Boolean(true) => ConstantSymbol::Tristate(Tristate::Yes),
120            ConstantSymbol::Boolean(false) => ConstantSymbol::Tristate(Tristate::No),
121            _ => ConstantSymbol::Tristate(Tristate::No),
122        }),
123    )))
124    .parse(input)
125}
126
127pub fn parse_constant_string(input: KconfigInput<'_>) -> IResult<KconfigInput<'_>, ConstantSymbol> {
128    map(parse_string, ConstantSymbol::String).parse(input)
129}
130
131pub fn parse_non_constant_symbol(input: KconfigInput<'_>) -> IResult<KconfigInput<'_>, &str> {
132    map(
133        recognize(ws(many1(alt((alphanumeric1, recognize(one_of("._-"))))))),
134        |c: KconfigInput| c.trim(),
135    )
136    .parse(input)
137}
138
139fn private_parse_constant_bool(
140    input: KconfigInput<'_>,
141) -> IResult<KconfigInput<'_>, ConstantSymbol> {
142    alt((
143        map(char('y'), |_| ConstantSymbol::Boolean(true)),
144        map(char('n'), |_| ConstantSymbol::Boolean(false)),
145    ))
146    .parse(input)
147}
148
149#[cfg(feature = "display")]
150impl Display for Symbol {
151    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
152        match self {
153            Symbol::Constant(c) => write!(f, "{}", c),
154            Symbol::NonConstant(c) => write!(f, "{}", c),
155        }
156    }
157}
158
159#[cfg(feature = "display")]
160impl Display for ConstantSymbol {
161    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
162        match self {
163            ConstantSymbol::Boolean(b) => match b {
164                true => write!(f, "y"),
165                false => write!(f, "n"),
166            },
167            ConstantSymbol::Integer(i) => write!(f, "{}", i),
168            ConstantSymbol::Hex(h) => write!(f, "{}", h),
169            ConstantSymbol::String(s) => write!(f, "\"{}\"", s),
170            ConstantSymbol::Tristate(t) => write!(f, "{}", t),
171        }
172    }
173}
174
175#[test]
176fn test_parse_constant_symbol() {
177    use crate::assert_parsing_eq;
178
179    assert_parsing_eq!(
180        parse_constant_symbol,
181        "\"64BITS\"",
182        Ok(("", ConstantSymbol::String("64BITS".to_string())))
183    );
184
185    assert_parsing_eq!(
186        parse_constant_symbol,
187        "\"true\"",
188        Ok(("", ConstantSymbol::String("true".to_string())))
189    );
190    assert_parsing_eq!(
191        parse_constant_symbol,
192        "\'false\'",
193        Ok(("", ConstantSymbol::String("false".to_string())))
194    );
195
196    assert_parsing_eq!(
197        parse_constant_symbol,
198        "'64BITS'",
199        Ok(("", ConstantSymbol::String("64BITS".to_string())))
200    );
201
202    assert_parsing_eq!(
203        parse_constant_symbol,
204        "'64'",
205        Ok(("", ConstantSymbol::String("64".to_string())))
206    )
207}