1use nom::branch::alt;
2use nom::bytes::complete::tag;
3use nom::character::complete::char as cchar;
4use nom::combinator::{map, opt};
5use nom::sequence::{delimited, terminated, tuple};
6use nom::IResult;
7
8use crate::basic::{Identifier, IdentifierRef, ListSeparator, Separator};
9use crate::constant::{ConstValue, ConstValueRef, IntConstant};
10use crate::types::{FieldType, FieldTypeRef};
11use crate::Parser;
12
13#[derive(Debug, Clone, PartialEq)]
18pub struct FieldRef<'a> {
19 pub id: Option<IntConstant>,
20 pub required: Option<bool>,
21 pub type_: FieldTypeRef<'a>,
22 pub name: IdentifierRef<'a>,
23 pub default: Option<ConstValueRef<'a>>,
24}
25
26impl<'a> Parser<'a> for FieldRef<'a> {
27 fn parse(input: &'a str) -> IResult<&'a str, Self> {
28 map(
29 tuple((
30 opt(terminated(
31 IntConstant::parse,
32 delimited(opt(Separator::parse), cchar(':'), opt(Separator::parse)),
33 )),
34 opt(terminated(
35 alt((
36 map(tag("required"), |_| true),
37 map(tag("optional"), |_| false),
38 )),
39 Separator::parse,
40 )),
41 terminated(FieldTypeRef::parse, Separator::parse),
42 terminated(IdentifierRef::parse, opt(Separator::parse)),
43 opt(map(
44 tuple((cchar('='), opt(Separator::parse), ConstValueRef::parse)),
45 |(_, _, cv)| cv,
46 )),
47 opt(Separator::parse),
48 opt(ListSeparator::parse),
49 )),
50 |(id, required, type_, name, default, _, _)| Self {
51 id,
52 required,
53 type_,
54 name,
55 default,
56 },
57 )(input)
58 }
59}
60
61#[derive(Debug, Clone, PartialEq)]
62pub struct Field {
63 pub id: Option<IntConstant>,
64 pub required: Option<bool>,
65 pub type_: FieldType,
66 pub name: Identifier,
67 pub default: Option<ConstValue>,
68}
69
70impl<'a> From<FieldRef<'a>> for Field {
71 fn from(r: FieldRef<'a>) -> Self {
72 Self {
73 id: r.id,
74 required: r.required,
75 type_: r.type_.into(),
76 name: r.name.into(),
77 default: r.default.map(Into::into),
78 }
79 }
80}
81
82impl<'a> Parser<'a> for Field {
83 fn parse(input: &'a str) -> IResult<&'a str, Self> {
84 FieldRef::parse(input).map(|(remains, parsed)| (remains, parsed.into()))
85 }
86}
87
88#[cfg(test)]
89mod test {
90 use crate::basic::LiteralRef;
91
92 use super::*;
93
94 #[test]
95 fn test_field() {
96 let expected = FieldRef {
97 id: None,
98 required: Some(true),
99 type_: FieldTypeRef::String,
100 name: IdentifierRef::from("name"),
101 default: Some(ConstValueRef::Literal(LiteralRef::from("ihciah"))),
102 };
103 assert_eq!(
104 FieldRef::parse("required string name = 'ihciah'")
105 .unwrap()
106 .1,
107 expected
108 );
109 assert_eq!(
110 FieldRef::parse("required string name='ihciah';").unwrap().1,
111 expected
112 );
113
114 let expected = FieldRef {
115 id: Some(IntConstant::from(3)),
116 required: Some(true),
117 type_: FieldTypeRef::String,
118 name: IdentifierRef::from("name"),
119 default: Some(ConstValueRef::Literal(LiteralRef::from("ihciah"))),
120 };
121 assert_eq!(
122 FieldRef::parse("3 : required string name = 'ihciah'")
123 .unwrap()
124 .1,
125 expected
126 );
127 assert_eq!(
128 FieldRef::parse("3:required string name='ihciah';")
129 .unwrap()
130 .1,
131 expected
132 );
133 }
134}