ron_edit/
value.rs

1use crate::*;
2
3#[apply(ast)]
4#[derive(Display)]
5pub enum Value<'s> {
6    Int(Int<'s>),
7    Float(Float<'s>),
8    Str(Str<'s>),
9    Char(Char<'s>),
10    Bool(bool),
11    List(List<'s>),
12    Map(Map<'s>),
13    Unit(&'s str),
14    Tuple(Tuple<'s>),
15    Struct(Struct<'s>),
16}
17pub(crate) fn value(input: &str) -> IResult<Value> {
18    alt((
19        map(value_int, Value::Int),
20        map(value_float, Value::Float),
21        map(value_str, Value::Str),
22        map(value_char, Value::Char),
23        map(value_list, Value::List),
24        map(value_map, Value::Map),
25        map(value_tuple, Value::Tuple),
26        map(value_struct, Value::Struct),
27        map(ident, Value::Unit),
28    ))(input)
29}
30
31#[apply(ast)]
32#[derive(Display)]
33pub struct Int<'s>(&'s str);
34fn value_int(s: &str) -> IResult<Int> {
35    map(
36        recognize(tuple((
37            sign,
38            alt((
39                is_a("0123456789_"),
40                preceded(
41                    char('0'),
42                    cut(preceded(is_a("box"), is_a("0123456789ABCDEFabcdef_"))),
43                ),
44            )),
45        ))),
46        Int,
47    )(s)
48}
49
50fn sign(s: &str) -> IResult<Option<char>> {
51    opt(alt((char('+'), char('-'))))(s)
52}
53
54#[apply(ast)]
55#[derive(Display)]
56pub struct Float<'s>(&'s str);
57fn value_float(s: &str) -> IResult<Float> {
58    map(
59        // TODO test `double`
60        recognize(tuple((
61            opt(alt((char('+'), char('-')))),
62            alt((
63                tag("inf"),
64                tag("NaN"),
65                recognize(tuple((
66                    alt((
67                        recognize(tuple((digit1, opt(tuple((char('.'), digit0)))))),
68                        recognize(tuple((char('.'), digit1))),
69                    )),
70                    opt(tuple((alt((char('e'), char('E'))), sign, digit1))),
71                ))),
72            )),
73        ))),
74        Float,
75    )(s)
76}
77
78#[apply(ast)]
79#[derive(Display)]
80pub enum Str<'s> {
81    #[display(fmt = "\"{_0}\"")]
82    Baked(&'s str),
83    #[display(fmt = "r{0}\"{content}\"{0}", "\"#\".repeat(*pounds)")]
84    Raw { pounds: usize, content: &'s str },
85}
86fn value_str(s: &str) -> IResult<Str> {
87    alt((
88        map(
89            preceded(
90                char::<&str, Error>('"'),
91                cut(terminated(
92                    recognize(many0(alt((
93                        tag("\\\""),
94                        tag("\\\\"),
95                        tag("\\"),
96                        is_not("\\\""),
97                    )))),
98                    char('"'),
99                )),
100            ),
101            Str::Baked,
102        ),
103        map(raw_string, |(pounds, content)| Str::Raw { pounds, content }),
104    ))(s)
105}
106
107fn raw_string(s: &str) -> IResult<(usize, &str)> {
108    let (s, _) = char('r')(s)?;
109    let (s, pounds) = many0_count(char('#'))(s)?;
110    let terminator = format!("\"{}", "#".repeat(pounds));
111    let res = preceded(
112        char('"'),
113        cut(terminated(
114            take_until(terminator.as_str()),
115            tag(terminator.as_str()),
116        )),
117    )
118    .map(|content| (pounds, content))
119    .parse(s);
120    res
121}
122
123#[apply(ast)]
124#[derive(Display)]
125#[display(fmt = "'{_0}'")]
126pub struct Char<'s>(pub &'s str);
127fn value_char(s: &str) -> IResult<Char> {
128    map(
129        preceded(
130            char::<&str, Error>('\''),
131            cut(terminated(tag("\\'").or(is_not("'")), char('\''))),
132        ),
133        Char,
134    )(s)
135}
136
137#[apply(ast)]
138#[derive(Display)]
139#[display(fmt = "[{_0}]")]
140pub struct List<'s>(pub Separated<'s, Value<'s>>);
141fn value_list(s: &str) -> IResult<List> {
142    map(
143        preceded(char('['), cut(terminated(separated(value), char(']')))),
144        List,
145    )(s)
146}
147
148#[apply(ast)]
149#[derive(Display)]
150#[display(fmt = "{key}{after_key}:{value}")]
151pub struct MapItem<'s> {
152    pub key: Value<'s>,
153    pub after_key: Whitespace<'s>,
154    pub value: WsLead<'s, Value<'s>>,
155}
156
157#[apply(ast)]
158#[derive(Display)]
159#[display(fmt = "{{{_0}}}")]
160pub struct Map<'s>(pub Separated<'s, MapItem<'s>>);
161
162fn value_map(s: &str) -> IResult<Map> {
163    context(
164        "map",
165        map(
166            preceded(
167                char('{'),
168                cut(terminated(
169                    separated(tuple((value, ws, char(':'), ws_lead(value))).map(
170                        |(key, after_key, _, value)| MapItem {
171                            key,
172                            after_key,
173                            value,
174                        },
175                    )),
176                    char('}'),
177                )),
178            ),
179            Map,
180        ),
181    )(s)
182}
183
184#[apply(ast)]
185#[derive(Display)]
186#[display(fmt = "{}({fields})", "FormatOption(ident)")]
187pub struct Tuple<'s> {
188    pub ident: Option<WsFollowed<'s, &'s str>>,
189    pub fields: Separated<'s, Value<'s>>,
190}
191fn value_tuple(s: &str) -> IResult<Tuple> {
192    map(
193        pair(
194            opt(ws_followed(ident)),
195            delimited(char('('), separated(value), char(')')),
196        ),
197        |(ident, fields)| Tuple { ident, fields },
198    )(s)
199}
200
201#[apply(ast)]
202#[derive(Display)]
203#[display(fmt = "{key}{after_key}:{value}")]
204pub struct NamedField<'s> {
205    pub key: &'s str,
206    pub after_key: Whitespace<'s>,
207    pub value: WsLead<'s, Value<'s>>,
208}
209#[apply(ast)]
210#[derive(Display)]
211#[display(fmt = "{}({fields})", "FormatOption(ident)")]
212pub struct Struct<'s> {
213    pub ident: Option<WsFollowed<'s, &'s str>>,
214    pub fields: Separated<'s, NamedField<'s>>,
215}
216fn value_struct(s: &str) -> IResult<Struct> {
217    context(
218        "value struct",
219        map(
220            pair(
221                opt(ws_followed(ident)),
222                delimited(
223                    char('('),
224                    separated(map(
225                        tuple((ident, terminated(ws, char(':')), ws_lead(value))),
226                        |(key, after_key, value)| NamedField {
227                            key,
228                            after_key,
229                            value,
230                        },
231                    )),
232                    char(')'),
233                ),
234            ),
235            |(ident, fields)| Struct { ident, fields },
236        ),
237    )(s)
238}