wick_interface_types/
parser.rs

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,)+) => { $crate::typemap!($($key => $value),+) };
137  ($($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}