1use super::util::ws;
2use crate::number::parse_number;
3use crate::KconfigInput;
4use nom::bytes::tag;
5use nom::combinator::complete;
6use nom::{
7 branch::alt,
8 bytes::{tag_no_case, take_until},
9 character::complete::{alphanumeric1, char, hex_digit1, one_of},
10 combinator::{all_consuming, map, recognize},
11 multi::many1,
12 sequence::{delimited, pair},
13 IResult, Parser,
14};
15#[cfg(feature = "deserialize")]
16use serde::Deserialize;
17#[cfg(feature = "serialize")]
18use serde::Serialize;
19use std::fmt::Display;
20
21#[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 Symbol {
31 Constant(String),
32 NonConstant(String),
33}
34
35pub fn parse_constant_symbol(input: KconfigInput) -> IResult<KconfigInput, Symbol> {
36 alt((
37 all_consuming(parse_constant_tristate),
38 all_consuming(parse_constant_bool),
39 all_consuming(parse_constant_hex),
40 all_consuming(parse_constant_int),
41 all_consuming(parse_constant_string),
42 ))
43 .parse(input)
44}
45
46fn parse_env(input: KconfigInput) -> IResult<KconfigInput, Symbol> {
47 all_consuming(complete(map(
48 delimited(tag("\"$("), take_until(")\""), tag(")\"")),
49 |e: KconfigInput| Symbol::NonConstant(format!("$({})", e.fragment())),
50 )))
51 .parse(input)
52}
53
54pub fn parse_symbol(input: KconfigInput) -> IResult<KconfigInput, Symbol> {
55 let first_word = map(
56 alt((
57 complete(recognize(delimited(
58 tag("\"$("),
59 many1(alt((alphanumeric1, recognize(one_of("._"))))),
60 tag(")\""),
61 ))),
62 recognize(ws(many1(alt((alphanumeric1, recognize(one_of("._'\""))))))),
63 )),
64 |c: KconfigInput| c,
65 )
66 .parse(input)?;
67 let ok = alt((
68 parse_env,
69 parse_constant_symbol,
70 map(parse_non_constant_symbol, |c: &str| {
71 Symbol::NonConstant(c.to_string())
72 }),
73 all_consuming(parse_constant_string),
74 ))
75 .parse(first_word.1)?;
76 Ok((first_word.0, ok.1))
77}
78
79pub fn parse_constant_int(input: KconfigInput<'_>) -> IResult<KconfigInput<'_>, Symbol> {
80 map(
81 alt((
82 parse_number,
83 delimited(ws(char('"')), parse_number, char('"')),
84 delimited(ws(char('\'')), parse_number, char('\'')),
85 )),
86 |integer: i64| Symbol::Constant(integer.to_string()),
87 )
88 .parse(input)
89}
90
91pub fn parse_constant_bool(input: KconfigInput<'_>) -> IResult<KconfigInput<'_>, Symbol> {
92 ws(alt((
93 private_parse_constant_bool,
94 delimited(ws(char('"')), private_parse_constant_bool, char('"')),
95 delimited(ws(char('\'')), private_parse_constant_bool, char('\'')),
96 )))
97 .parse(input)
98}
99
100pub fn parse_constant_hex(input: KconfigInput<'_>) -> IResult<KconfigInput<'_>, Symbol> {
101 ws(map(
102 pair(complete(tag_no_case("0x")), hex_digit1),
103 |(prefix, v): (KconfigInput, KconfigInput)| {
104 Symbol::Constant(format!("{}{}", prefix.fragment(), v.fragment()))
105 },
106 ))
107 .parse(input)
108}
109
110pub fn parse_constant_tristate(input: KconfigInput<'_>) -> IResult<KconfigInput<'_>, Symbol> {
111 ws(alt((
112 parse_constant_bool,
113 map(char('m'), |_| Symbol::Constant("m".to_string())),
114 map(delimited(ws(char('"')), char('m'), char('"')), |_| {
115 Symbol::Constant("m".to_string())
116 }),
117 map(delimited(ws(char('\'')), char('m'), char('\'')), |_| {
118 Symbol::Constant("m".to_string())
119 }),
120 )))
121 .parse(input)
122}
123
124pub fn parse_constant_string(input: KconfigInput<'_>) -> IResult<KconfigInput<'_>, Symbol> {
125 map(
126 complete(alt((
127 delimited(ws(char('"')), take_until("\""), char('"')),
128 delimited(ws(char('\'')), take_until("\'"), char('\'')),
129 ))),
130 |c: KconfigInput| Symbol::Constant(c.fragment().to_string()),
131 )
132 .parse(input)
133}
134
135pub fn parse_non_constant_symbol(input: KconfigInput<'_>) -> IResult<KconfigInput<'_>, &str> {
136 map(
137 recognize(ws(many1(alt((alphanumeric1, recognize(one_of("._"))))))),
138 |c: KconfigInput| c.trim(),
139 )
140 .parse(input)
141}
142
143fn private_parse_constant_bool(input: KconfigInput<'_>) -> IResult<KconfigInput<'_>, Symbol> {
144 alt((
145 map(char('y'), |_| Symbol::Constant("y".to_string())),
146 map(char('n'), |_| Symbol::Constant("n".to_string())),
147 ))
148 .parse(input)
149}
150
151impl Display for Symbol {
152 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
153 match self {
154 Symbol::Constant(c) => write!(f, "{}", c),
155 Symbol::NonConstant(c) => write!(f, "{}", c),
156 }
157 }
158}
159
160#[test]
161fn test_parse_constant_symbol() {
162 use crate::assert_parsing_eq;
163
164 assert_parsing_eq!(
165 parse_constant_symbol,
166 "\"64BITS\"",
167 Ok(("", Symbol::Constant("64BITS".to_string())))
168 );
169
170 assert_parsing_eq!(
171 parse_constant_symbol,
172 "\"true\"",
173 Ok(("", Symbol::Constant("true".to_string())))
174 );
175 assert_parsing_eq!(
176 parse_constant_symbol,
177 "\'false\'",
178 Ok(("", Symbol::Constant("false".to_string())))
179 );
180
181 assert_parsing_eq!(
182 parse_constant_symbol,
183 "'64BITS'",
184 Ok(("", Symbol::Constant("64BITS".to_string())))
185 );
186
187 assert_parsing_eq!(
188 parse_constant_symbol,
189 "'64'",
190 Ok(("", Symbol::Constant("64".to_string())))
191 )
192}