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#[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}