webwire_cli/idl/
field_option.rs1use nom::{
2 character::complete::char,
3 combinator::{cut, map},
4 error::context,
5 multi::separated_list0,
6 sequence::{preceded, separated_pair, terminated},
7 IResult,
8};
9
10#[cfg(test)]
11use crate::idl::common::assert_parse;
12use crate::idl::common::{parse_field_separator, parse_identifier, trailing_comma, ws, Span};
13use crate::idl::r#value::{parse_value, Value};
14
15#[derive(Debug, PartialEq)]
16pub struct FieldOption {
17 pub name: String,
18 pub value: Value,
19}
20
21pub fn parse_field_options(input: Span) -> IResult<Span, Vec<FieldOption>> {
22 context(
23 "options",
24 preceded(
25 preceded(ws, char('(')),
26 cut(terminated(
27 separated_list0(parse_field_separator, parse_field_option),
28 preceded(trailing_comma, preceded(ws, char(')'))),
29 )),
30 ),
31 )(input)
32}
33
34fn parse_field_option(input: Span) -> IResult<Span, FieldOption> {
35 map(
36 separated_pair(
37 preceded(ws, parse_identifier),
38 preceded(ws, char('=')),
39 preceded(ws, parse_value),
40 ),
41 |(name, value)| FieldOption { name, value },
42 )(input)
43}
44
45#[test]
46fn test_parse_field_options_0() {
47 let contents = ["()", "( )", "(,)", "( ,)", "(, )"];
48 for content in contents.iter() {
49 assert_parse(parse_field_options(Span::new(content)), vec![]);
50 }
51}
52
53#[test]
54fn test_parse_field_options_1() {
55 let contents = [
56 "(foo=42)",
57 "(foo= 42)",
58 "(foo=42 )",
59 "( foo=42)",
60 "(foo=42,)",
61 ];
62 for content in contents.iter() {
63 assert_parse(
64 parse_field_options(Span::new(content)),
65 vec![FieldOption {
66 name: "foo".to_owned(),
67 value: Value::Integer(42),
68 }],
69 );
70 }
71}
72
73#[test]
74fn test_parse_field_options_2() {
75 let contents = [
76 "(foo=42,bar=\"epic\")",
77 "(foo= 42, bar= \"epic\")",
78 "( foo=42,bar=\"epic\" )",
79 "( foo= 42, bar= \"epic\" )",
80 "( foo= 42, bar= \"epic\", )",
81 ];
82 for content in contents.iter() {
83 assert_parse(
84 parse_field_options(Span::new(content)),
85 vec![
86 FieldOption {
87 name: "foo".to_owned(),
88 value: Value::Integer(42),
89 },
90 FieldOption {
91 name: "bar".to_owned(),
92 value: Value::String("epic".to_string()),
93 },
94 ],
95 );
96 }
97}