1use nom::{
2 branch::alt,
3 bytes::complete::tag,
4 character::{complete::alphanumeric1, one_of},
5 combinator::{map, recognize},
6 multi::many1,
7 sequence::{delimited, pair, preceded},
8 IResult, Parser,
9};
10#[cfg(feature = "deserialize")]
11use serde::Deserialize;
12#[cfg(feature = "serialize")]
13use serde::Serialize;
14#[cfg(feature = "display")]
15use std::fmt::Display;
16
17use super::expression::{parse_if_attribute, Expression};
18use crate::{
19 number::parse_number,
20 symbol::{parse_constant_hex_as_string, parse_non_constant_symbol},
21};
22use crate::{util::ws, KconfigInput};
23
24#[derive(Debug, Clone, PartialEq)]
26#[cfg_attr(feature = "hash", derive(Hash))]
27#[cfg_attr(feature = "serialize", derive(Serialize))]
28#[cfg_attr(feature = "deserialize", derive(Deserialize))]
29pub struct Range {
30 pub lower_bound: RangeBound,
31 pub upper_bound: RangeBound,
32 #[cfg_attr(
33 any(feature = "serialize", feature = "deserialize"),
34 serde(skip_serializing_if = "Option::is_none")
35 )]
36 pub r#if: Option<Expression>,
37}
38
39#[cfg(feature = "display")]
40impl Display for Range {
41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 match &self.r#if {
43 Some(i) => write!(f, "{} {} if {}", self.lower_bound, self.upper_bound, i),
44 None => write!(f, "{} {}", self.lower_bound, self.upper_bound),
45 }
46 }
47}
48
49fn parse_bounds(input: KconfigInput) -> IResult<KconfigInput, (RangeBound, RangeBound)> {
51 (ws(parse_range_bound), ws(parse_range_bound)).parse(input)
52}
53
54pub fn parse_range(input: KconfigInput) -> IResult<KconfigInput, Range> {
76 map(
77 preceded(ws(tag("range")), pair(ws(parse_bounds), parse_if_attribute)),
78 |((l, r), i)| Range {
79 lower_bound: l,
80 upper_bound: r,
81 r#if: i,
82 },
83 )
84 .parse(input)
85}
86
87#[derive(Debug, Clone, PartialEq)]
88#[cfg_attr(feature = "hash", derive(Hash))]
89#[cfg_attr(feature = "serialize", derive(Serialize))]
90#[cfg_attr(feature = "deserialize", derive(Deserialize))]
91pub enum RangeBound {
92 Hex(String),
93 Number(i64),
94 Symbol(String),
95 Variable(String),
96}
97
98fn parse_range_bound(input: KconfigInput) -> IResult<KconfigInput, RangeBound> {
99 alt((
100 map(parse_constant_hex_as_string, RangeBound::Hex),
101 map(parse_number, RangeBound::Number),
102 map(parse_non_constant_symbol, |s| {
103 RangeBound::Symbol(s.to_string())
104 }),
105 map(parse_variable, |v| RangeBound::Variable(v.to_string())),
106 ))
107 .parse(input)
108}
109
110#[cfg(feature = "display")]
111impl Display for RangeBound {
112 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113 match self {
114 RangeBound::Hex(h) => write!(f, "{}", h),
115 RangeBound::Number(n) => write!(f, "{}", n),
116 RangeBound::Symbol(s) => write!(f, "{}", s),
117 RangeBound::Variable(v) => write!(f, "$({})", v),
118 }
119 }
120}
121
122fn parse_variable(input: KconfigInput) -> IResult<KconfigInput, String> {
123 map(
124 delimited(
125 tag("$("),
126 recognize(ws(many1(alt((alphanumeric1, recognize(one_of("_"))))))),
127 tag(")"),
128 ),
129 |d: KconfigInput| d.fragment().to_string(),
130 )
131 .parse(input)
132}