1use std::fmt::Debug;
2
3use nom::branch::alt;
4use nom::bytes::complete::tag;
5use nom::character::complete::{alpha1, alphanumeric1, char, multispace0};
6use nom::combinator::{opt, recognize};
7use nom::error::ParseError;
8use nom::multi::{many0, many0_count, separated_list1};
9use nom::sequence::{delimited, pair, terminated, tuple};
10use nom::IResult;
11
12use crate::{Field, Type};
13
14#[derive(Debug, Clone)]
15#[non_exhaustive]
16pub enum ParserError {
17 Fail(String),
18 UnexpectedToken,
19}
20
21impl std::error::Error for ParserError {}
22impl std::fmt::Display for ParserError {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 match self {
25 ParserError::Fail(v) => write!(f, "Could not parse {} into TypeSignature", v),
26 ParserError::UnexpectedToken => write!(f, "Unexpected token"),
27 }
28 }
29}
30
31fn ws<'a, F, O, E: ParseError<&'a str>>(inner: F) -> impl FnMut(&'a str) -> IResult<&'a str, O, E>
32where
33 F: FnMut(&'a str) -> IResult<&'a str, O, E>,
34{
35 delimited(multispace0, inner, multispace0)
36}
37
38pub fn parse(input: &str) -> Result<Type, ParserError> {
39 _parse(input)
40 .map(|(_, t)| t)
41 .map_err(|_| ParserError::Fail(input.to_owned()))
42}
43
44fn square_brackets(input: &str) -> IResult<&str, &str> {
45 delimited(char('['), multispace0, char(']'))(input)
46}
47
48fn struct_type(input: &str) -> IResult<&str, Type> {
49 let (i, v) = delimited(char('{'), separated_list1(char(','), ws(key_type_pair)), char('}'))(input)?;
50 let v: Vec<_> = v.into_iter().map(|(s, t)| Field::new(s, t)).collect();
51 Ok((i, Type::AnonymousStruct(v)))
52}
53
54fn map_type(input: &str) -> IResult<&str, Type> {
55 let (i, (_, ty)) = delimited(char('{'), ws(map_key_type_pair), char('}'))(input)?;
56
57 Ok((
58 i,
59 Type::Map {
60 key: Box::new(Type::String),
61 value: Box::new(ty),
62 },
63 ))
64}
65
66fn key_type_pair(input: &str) -> IResult<&str, (&str, Type)> {
67 let (i, (key, _, t)) = tuple((identifier, ws(char(':')), valid_type))(input)?;
68 Ok((i, (key, t)))
69}
70
71fn map_key_type_pair(input: &str) -> IResult<&str, (&str, Type)> {
72 let (i, (key, _, t)) = tuple((tag("string"), ws(char(':')), valid_type))(input)?;
73 Ok((i, (key, t)))
74}
75
76fn identifier(input: &str) -> IResult<&str, &str> {
77 recognize(pair(
78 alt((alpha1, tag("_"))),
79 many0_count(alt((alphanumeric1, tag("_")))),
80 ))(input)
81}
82
83fn list_type(input: &str) -> IResult<&str, Type> {
84 let (i, (t, _)) = pair(typename, ws(square_brackets))(input)?;
85
86 Ok((i, Type::List { ty: Box::new(t) }))
87}
88
89fn valid_type(input: &str) -> IResult<&str, Type> {
90 alt((map_type, struct_type, list_type, typename))(input)
91}
92
93fn typename(input: &str) -> IResult<&str, Type> {
94 let (i, t) = alt((
95 recognize(pair(many0(terminated(identifier, tag("::"))), identifier)),
96 identifier,
97 ))(input)?;
98 let t = match t {
99 "bool" => Type::Bool,
100 "i8" => Type::I8,
101 "i16" => Type::I16,
102 "i32" => Type::I32,
103 "i64" => Type::I64,
104 "u8" => Type::U8,
105 "u16" => Type::U16,
106 "u32" => Type::U32,
107 "u64" => Type::U64,
108 "int" => Type::I64,
109 "uint" => Type::U64,
110 "float" => Type::F64,
111 "f32" => Type::F32,
112 "f64" => Type::F64,
113 "bytes" => Type::Bytes,
114 "string" => Type::String,
115 "datetime" => Type::Datetime,
116 "object" => Type::Object,
117 x => Type::Named(x.to_owned()),
118 };
119 Ok((i, t))
120}
121
122fn _parse(input: &str) -> IResult<&str, Type> {
123 let (i, (t, optional)) = pair(alt((list_type, map_type, struct_type, typename)), opt(tag("?")))(input)?;
124 if optional.is_some() {
125 Ok((i, Type::Optional { ty: Box::new(t) }))
126 } else {
127 Ok((i, t))
128 }
129}
130
131#[macro_export]
132macro_rules! fields {
133 (@single $($x:tt)*) => (());
134 (@count $($rest:expr),*) => (<[()]>::len(&[$($crate::fields!(@single $rest)),*]));
135
136 ($($key:expr => $value:expr),* $(,)?) => {
138 {
139 let _cap = $crate::fields!(@count $(stringify!($key)),*);
140 let mut _map = ::std::vec::Vec::with_capacity(_cap);
141 $(
142 let _ = _map.push($crate::Field::new($key, $crate::parse($value).unwrap()));
143 )*
144 _map
145 }
146 };
147}
148
149#[macro_export]
150macro_rules! operation {
151 ($name:expr => {
152 config: {$($ckey:expr => $cvalue:expr),* $(,)?},
153 inputs: {$($ikey:expr => $ivalue:expr),* $(,)?},
154 outputs: {$($okey:expr => $ovalue:expr),* $(,)?},
155 }) => {
156 $crate::OperationSignature::new(
157 $name.to_owned(),
158 $crate::fields! {$($ikey => $ivalue),*},
159 $crate::fields! {$($okey => $ovalue),*},
160 $crate::fields! {$($ckey => $cvalue),*},
161 )
162 };
163 ($name:expr => {
164 inputs: {$($ikey:expr => $ivalue:expr),* $(,)?},
165 outputs: {$($okey:expr => $ovalue:expr),* $(,)?},
166 }) => {
167 $crate::OperationSignature::new(
168 $name.to_owned(),
169 $crate::fields! {$($ikey => $ivalue),*},
170 $crate::fields! {$($okey => $ovalue),*},
171 Vec::new()
172 )
173 };
174}
175
176#[macro_export]
177macro_rules! component {
178 (
179 name: $name:expr,
180 version: $version:expr,
181 operations: {
182 $($opname:expr => {
183 config: {$($ckey:expr => $cvalue:expr),* $(,)?},
184 inputs: {$($ikey:expr => $ivalue:expr),* $(,)?},
185 outputs: {$($okey:expr => $ovalue:expr),* $(,)?},
186 }),* $(,)?
187 }
188 ) => {{
189 let mut ops = std::vec::Vec::default();
190 $(
191 let _ = ops.push($crate::operation!($opname => {config:{$($ckey => $cvalue),*}, inputs: {$($ikey => $ivalue),*}, outputs: {$($okey => $ovalue),*},}));
192 )*;
193
194 $crate::component! {
195 name: $name,
196 version: $version,
197 operations: ops,
198 }
199 }};
200 (
201 name: $name:expr,
202 version: $version:expr,
203 operations: {
204 $($opname:expr => {
205 inputs: {$($ikey:expr => $ivalue:expr),* $(,)?},
206 outputs: {$($okey:expr => $ovalue:expr),* $(,)?},
207 }),* $(,)?
208 }
209 ) => {{
210 let mut ops = std::vec::Vec::default();
211 $(
212 let _ = ops.push($crate::operation!($opname => {config:{}, inputs: {$($ikey => $ivalue),*}, outputs: {$($okey => $ovalue),*},}));
213 )*;
214
215 $crate::component! {
216 name: $name,
217 version: $version,
218 operations: ops,
219 }
220 }};
221 (
222 name: $name:expr,
223 version: $version:expr,
224 operations: $ops:expr,
225 ) => {{
226 $crate::ComponentSignature::new($name.to_owned(),$version.map(|v|v.into()),$ops,Vec::new(),Vec::new())
227 }};
228}
229
230#[cfg(test)]
231mod test {
232
233 use anyhow::Result;
234
235 use super::*;
236 use crate::Field;
237
238 #[rstest::rstest]
239 #[case("bool[]", Type::Bool)]
240 #[case("bool []", Type::Bool)]
241 #[case("bool [ ]", Type::Bool)]
242 #[case("string[]", Type::String)]
243 fn test_list_variants(#[case] input: &'static str, #[case] expected: Type) -> Result<()> {
244 let (_i, t) = list_type(input)?;
245 assert_eq!(t, Type::List { ty: Box::new(expected) });
246 Ok(())
247 }
248
249 #[rstest::rstest]
250 #[case("{ myBool : bool }", Type::Bool)]
251 #[case("{myBool:bool}", Type::Bool)]
252 #[case("{ myBool : bool }", Type::Bool)]
253 fn test_struct_variants(#[case] input: &'static str, #[case] expected: Type) -> Result<()> {
254 let (_i, t) = struct_type(input)?;
255 let fields = [Field::new("myBool", expected)];
256 assert_eq!(t, Type::AnonymousStruct(fields.into()));
257 Ok(())
258 }
259
260 #[rstest::rstest]
261 #[case("bool", Type::Bool)]
262 #[case("i8", Type::I8)]
263 #[case("i16", Type::I16)]
264 #[case("i32", Type::I32)]
265 #[case("i64", Type::I64)]
266 #[case("int", Type::I64)]
267 #[case("uint", Type::U64)]
268 #[case("float", Type::F64)]
269 #[case("u8", Type::U8)]
270 #[case("u16", Type::U16)]
271 #[case("u32", Type::U32)]
272 #[case("u64", Type::U64)]
273 #[case("f32", Type::F32)]
274 #[case("f64", Type::F64)]
275 #[case("bytes", Type::Bytes)]
276 #[case("string", Type::String)]
277 #[case("datetime", Type::Datetime)]
278 #[case("object", Type::Object)]
279 #[case("myType", Type::Named("myType".to_owned()))]
280 #[case("name::myType", Type::Named("name::myType".to_owned()))]
281 fn test_parse_typename(#[case] as_str: &'static str, #[case] ty: Type) -> Result<()> {
282 assert_eq!(typename(as_str)?, ("", ty));
283 Ok(())
284 }
285
286 #[rstest::rstest]
287 #[case("bool", Type::Bool)]
288 #[case("i8", Type::I8)]
289 #[case("i16", Type::I16)]
290 #[case("i32", Type::I32)]
291 #[case("i64", Type::I64)]
292 #[case("u8", Type::U8)]
293 #[case("u16", Type::U16)]
294 #[case("u32", Type::U32)]
295 #[case("u64", Type::U64)]
296 #[case("f32", Type::F32)]
297 #[case("f64", Type::F64)]
298 #[case("bytes", Type::Bytes)]
299 #[case("string", Type::String)]
300 #[case("datetime", Type::Datetime)]
301 #[case("object", Type::Object)]
302 #[case("myType[]", Type::List{ty:Box::new(Type::Named("myType".to_owned()))})]
303 #[case("{string: bool}", Type::Map{key:Box::new(Type::String),value:Box::new(Type::Bool)})]
304 #[case("{string: bool[]}", Type::Map{key:Box::new(Type::String),value:Box::new(Type::List{ty:Box::new(Type::Bool)})})]
305 #[case("{string: name::myType}", Type::Map{key:Box::new(Type::String),value:Box::new(Type::Named("name::myType".to_owned()))})]
306 #[case("name::myType", Type::Named("name::myType".to_owned()))]
307 fn test_parse_type(#[case] as_str: &'static str, #[case] ty: Type) -> Result<()> {
308 assert_eq!(valid_type(as_str)?, ("", ty));
309 Ok(())
310 }
311
312 #[rstest::rstest]
313 #[case("bool", Type::Bool)]
314 #[case("i8", Type::I8)]
315 #[case("i16", Type::I16)]
316 #[case("i32", Type::I32)]
317 #[case("i64", Type::I64)]
318 #[case("u8", Type::U8)]
319 #[case("u16", Type::U16)]
320 #[case("u32", Type::U32)]
321 #[case("u64", Type::U64)]
322 #[case("f32", Type::F32)]
323 #[case("f32", Type::F32)]
324 #[case("f64?", Type::Optional{ty:Box::new(Type::F64)} )]
325 #[case("bytes", Type::Bytes)]
326 #[case("string", Type::String)]
327 #[case("datetime", Type::Datetime)]
328 #[case("{string:string}", Type::Map { key: Box::new(Type::String), value: Box::new(Type::String) })]
329 #[case("{string:string[]}", Type::Map { key: Box::new(Type::String), value: Box::new(Type::List{ty:Box::new(Type::String)}) })]
330 #[case("object", Type::Object)]
331 #[case("myType", Type::Named("myType".to_owned()))]
332 #[case("name::myType", Type::Named("name::myType".to_owned()))]
333 fn test_parse(#[case] as_str: &'static str, #[case] ty: Type) -> Result<()> {
334 assert_eq!(parse(as_str)?, ty);
335 Ok(())
336 }
337}