1use nom::{
36 branch::alt,
37 bytes::complete::tag,
38 character::{
39 self,
40 complete::{
41 alpha1, anychar, line_ending, not_line_ending, one_of, satisfy, space0, space1,
42 },
43 is_alphanumeric,
44 },
45 combinator::peek,
46 error::VerboseError,
47 multi::{many0, many1, separated_list1},
48 number,
49 sequence::{delimited, preceded},
50 IResult,
51};
52use std::fmt::Display;
53
54type PResult<'a, OUT> = IResult<&'a str, OUT, VerboseError<&'a str>>;
55
56#[derive(Debug)]
57pub enum Expr {
58 Variable {
59 type_name: TypeName,
60 var_name: String,
61 value: Option<ValueType>,
62 comment: Option<String>,
63 },
64 Empty, Comment,
66 Eof,
67}
68
69#[derive(Debug)]
70pub enum ValueType {
71 Const(Value),
72 Default(Value),
73}
74
75#[derive(Debug)]
76pub enum Value {
77 Bool(bool),
78 String(String),
79 Float(f64),
80 Uint(u64),
81 Int(i64),
82 Array(Vec<Value>),
83}
84
85impl Display for Value {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 match self {
88 Value::Int(n) => write!(f, "{n}"),
89 Value::Uint(n) => write!(f, "{n}"),
90 Value::Float(n) => write!(f, "{n}"),
91 Value::String(n) => write!(f, "b\"{n}\\0\""),
92 Value::Bool(n) => write!(f, "{n}"),
93 Value::Array(n) => write!(f, "{:?}", n),
94 }
95 }
96}
97
98#[derive(Debug)]
99pub enum TypeName {
100 Type {
101 type_name: String,
102 array_info: ArrayInfo,
103 },
104 ScopedType {
105 scope: String,
106 type_name: String,
107 array_info: ArrayInfo,
108 },
109 LimitedString {
110 size: usize,
111 array_info: ArrayInfo,
112 },
113 String(ArrayInfo),
114}
115
116#[derive(Debug)]
117pub enum ArrayInfo {
118 NotArray,
119 Dynamic,
120 Static(usize),
121 Limited(usize),
122}
123
124pub fn parse_msg(mut input: &str) -> PResult<Vec<Expr>> {
132 let mut result = Vec::new();
133 loop {
134 if input.is_empty() {
135 break;
136 }
137
138 let (next, expr) = parse_expr(input)?;
139 input = next;
140
141 if let Expr::Variable { .. } = &expr {
142 result.push(expr);
143 }
144 }
145
146 Ok((input, result))
147}
148
149pub fn parse_srv(mut input: &str) -> PResult<(Vec<Expr>, Vec<Expr>)> {
150 let mut request = Vec::new();
152 loop {
153 if peek_tag("---", input).is_ok() {
154 break;
155 }
156
157 let (next, expr) = parse_expr(input)?;
158 input = next;
159
160 if let Expr::Variable { .. } = &expr {
161 request.push(expr);
162 }
163 }
164
165 let (mut input, _) = tag("---")(input)?;
166
167 let mut response = Vec::new();
169 loop {
170 if input.is_empty() {
171 break;
172 }
173
174 let (next, expr) = parse_expr(input)?;
175 input = next;
176
177 if let Expr::Variable { .. } = &expr {
178 response.push(expr);
179 }
180 }
181
182 Ok(("", (request, response)))
183}
184
185fn parse_expr(input: &str) -> PResult<Expr> {
189 let (input, _) = space0(input)?;
190 alt((parse_empty, parse_comment, parse_variable))(input)
191}
192
193fn parse_variable(input: &str) -> PResult<Expr> {
198 let (input, type_name) = parse_typename(input)?;
199
200 let (input, _) = space1(input)?;
202
203 let (input, (var_name, value)) = alt((parse_immutable_var, parse_mutable_var))(input)?;
205
206 let (input, _) = space0(input)?;
208
209 let (input, comment) = if peek_tag("#", input).is_ok() {
210 let (input, _) = tag("#")(input)?;
212 let (input, c) = not_line_ending(input)?;
213 (input, Some(c.to_string()))
214 } else {
215 (input, None)
216 };
217
218 let input = if !input.is_empty() {
219 let (input, _) = line_ending(input)?;
221 input
222 } else {
223 input
224 };
225
226 Ok((
227 input,
228 Expr::Variable {
229 type_name,
230 var_name,
231 value,
232 comment,
233 },
234 ))
235}
236
237fn parse_mutable_var(input: &str) -> PResult<(String, Option<ValueType>)> {
238 let (input, var_name) = parse_identifier(input)?;
241
242 fn get_value(input: &str) -> PResult<Value> {
244 let (input, _) = space1(input)?;
245 parse_value(input)
246 }
247
248 if let Ok((input, val)) = get_value(input) {
249 Ok((input, (var_name, Some(ValueType::Default(val))))) } else {
251 Ok((input, (var_name, None))) }
253}
254
255fn parse_immutable_var(input: &str) -> PResult<(String, Option<ValueType>)> {
256 let (input, var_name) = parse_capital_identifier(input)?;
259
260 let (input, _) = space0(input)?;
262
263 let (input, _) = tag("=")(input)?;
264
265 let (input, _) = space0(input)?;
267
268 let (input, val) = parse_value(input)?;
270
271 Ok((input, (var_name, Some(ValueType::Const(val)))))
272}
273
274fn parse_typename(input: &str) -> PResult<TypeName> {
284 let (input, scope) = parse_identifier(input)?;
286
287 if scope == "string" {
288 return parse_string_type(input);
289 }
290
291 if peek_tag("/", input).is_ok() {
292 let (input, _) = tag("/")(input)?;
294 let (input, type_name) = parse_identifier(input)?;
295
296 let (input, array_info) = parse_array_info(input)?;
299 Ok((
300 input,
301 TypeName::ScopedType {
302 scope,
303 type_name,
304 array_info,
305 },
306 ))
307 } else {
308 let (input, array_info) = parse_array_info(input)?;
310 Ok((
311 input,
312 TypeName::Type {
313 type_name: scope,
314 array_info,
315 },
316 ))
317 }
318}
319
320fn parse_string_type(input: &str) -> PResult<TypeName> {
321 if peek_tag("<=", input).is_ok() {
322 let (input, _) = tag("<=")(input)?;
323 let (input, size) = character::complete::u64(input)?;
324 let (input, array_info) = parse_array_info(input)?;
325 Ok((
326 input,
327 TypeName::LimitedString {
328 size: size as usize,
329 array_info,
330 },
331 ))
332 } else {
333 let (input, array_info) = parse_array_info(input)?;
334 Ok((input, TypeName::String(array_info)))
335 }
336}
337
338fn parse_identifier(input: &str) -> PResult<String> {
342 let (input, head) = alt((tag("_"), alpha1))(input)?;
344
345 let (input, tail) = many0(satisfy(|c| is_alphanumeric(c as u8) || c == '_'))(input)?;
347
348 let tail: String = tail.iter().collect();
349 Ok((input, head.to_string() + &tail))
350}
351
352fn parse_capital_identifier(input: &str) -> PResult<String> {
356 let (input, head) = satisfy(|c| ('A'..='Z').contains(&c) || c == '_')(input)?;
358
359 let (input, tail) = many0(satisfy(|c| {
361 ('A'..='Z').contains(&c) || ('0'..='9').contains(&c) || c == '_'
362 }))(input)?;
363
364 let tail: String = tail.iter().collect();
365 Ok((input, format!("{head}{tail}")))
366}
367
368fn parse_comment(input: &str) -> PResult<Expr> {
372 let (input, _) = tag("#")(input)?;
373 let (input, _) = not_line_ending(input)?;
374
375 let input = if !input.is_empty() {
376 let (input, _) = line_ending(input)?;
378 input
379 } else {
380 input
381 };
382
383 Ok((input, Expr::Comment))
384}
385
386fn parse_empty(input: &str) -> PResult<Expr> {
388 if input.is_empty() {
389 Ok((input, Expr::Eof))
390 } else {
391 let (input, _) = line_ending(input)?;
392 Ok((input, Expr::Empty))
393 }
394}
395
396fn peek_tag<'a>(c: &'static str, input: &'a str) -> PResult<'a, &'a str> {
397 peek(tag(c))(input)
398}
399
400fn parse_value(input: &str) -> PResult<Value> {
408 alt((
409 parse_num,
410 parse_bool,
411 parse_array,
412 parse_string,
413 parse_raw_string,
414 ))(input)
415}
416
417fn parse_num(input: &str) -> PResult<Value> {
421 let (input, minus) = if peek_tag("-", input).is_ok() {
423 let (input, _) = tag("-")(input)?;
424 (input, -1)
425 } else {
426 (input, 1)
427 };
428
429 let (input, n) = character::complete::u64(input)?;
430 if peek_tag(".", input).is_ok() {
431 let (input, d) = number::complete::double(input)?;
432 let val = (d + n as f64) * minus as f64;
433 Ok((input, Value::Float(val)))
434 } else if minus == -1 {
435 Ok((input, Value::Int(n as i64 * minus)))
436 } else {
437 Ok((input, Value::Uint(n)))
438 }
439}
440
441fn parse_bool(input: &str) -> PResult<Value> {
445 let (input, val) = alt((tag("true"), tag("false")))(input)?;
446 if val == "true" {
447 Ok((input, Value::Bool(true)))
448 } else {
449 Ok((input, Value::Bool(false)))
450 }
451}
452
453fn parse_array(input: &str) -> PResult<Value> {
458 let p = delimited(space0, parse_value, space0);
459 let (input, val) = delimited(tag("["), separated_list1(tag(","), p), tag("]"))(input)?;
460 Ok((input, Value::Array(val)))
461}
462
463fn parse_array_info(input: &str) -> PResult<ArrayInfo> {
468 fn is_array(input: &str) -> PResult<()> {
469 let (input, _) = peek(preceded(space0, tag("[")))(input)?;
470 Ok((input, ()))
471 }
472
473 if is_array(input).is_ok() {
474 let (input, _) = space0(input)?;
475 let (input, _) = tag("[")(input)?;
476 let (input, _) = space0(input)?;
477 let (input, array_info) = if peek_tag("]", input).is_ok() {
478 (input, ArrayInfo::Dynamic)
480 } else if peek_tag("<", input).is_ok() {
481 let (input, _) = tag("<=")(input)?;
483 let (input, size) = character::complete::u64(input)?;
484 (input, ArrayInfo::Limited(size as usize))
485 } else {
486 let (input, size) = character::complete::u64(input)?;
488 (input, ArrayInfo::Static(size as usize))
489 };
490
491 let (input, _) = space0(input)?;
492 let (input, _) = tag("]")(input)?;
493
494 Ok((input, array_info))
495 } else {
496 Ok((input, ArrayInfo::NotArray))
497 }
498}
499
500fn parse_string(input: &str) -> PResult<Value> {
508 let (mut input, quote) = one_of("\"'")(input)?;
509
510 let mut val = String::new();
511
512 loop {
513 let (next, c) = anychar(input)?;
514 input = next;
515
516 match c {
517 c if c == quote => return Ok((input, Value::String(val))),
518 '\\' => {
519 let (next, c) = alt((one_of("rnt\\"), character::complete::char(quote)))(input)?;
520 input = next;
521
522 match c {
523 'r' => {
524 val.push_str("\\r");
525 }
526 'n' => {
527 val.push_str("\\n");
528 }
529 't' => {
530 val.push_str("\\t");
531 }
532 '\\' => {
533 val.push_str("\\\\");
534 }
535 c if c == quote => {
536 if c == '"' {
537 val.push('\\');
538 }
539 val.push(quote);
540 }
541 _ => unreachable!(),
542 }
543 }
544 _ => {
545 val.push(c);
546 }
547 }
548 }
549}
550
551fn parse_raw_string(input: &str) -> PResult<Value> {
552 let (input, result) = many1(satisfy(|c| c != '\r' && c != '\n'))(input)?;
553 let result = result.iter().fold(String::new(), |s, c| match c {
554 '\\' => format!("{s}\\\\"),
555 '"' => format!("{s}\\\""),
556 _ => format!("{s}{c}"),
557 });
558
559 Ok((input, Value::String(result)))
560}
561
562#[cfg(test)]
563mod tests {
564 use nom::Finish;
565
566 use super::parse_raw_string;
567
568 #[test]
569 fn test_parse_raw() {
570 let s = "\\";
571 let (_, v) = parse_raw_string(s).finish().unwrap();
572 println!("{v}");
573
574 let s = "\"";
575 let (_, v) = parse_raw_string(s).finish().unwrap();
576 println!("{v}");
577
578 let s = "\\\"";
579 let (_, v) = parse_raw_string(s).finish().unwrap();
580 println!("{v}");
581 }
582}