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