ts_type/
macros.rs

1#[macro_export]
2macro_rules! type_error_at {
3  ($location:expr, $($arg:tt)*) => {
4      TsTypeError {
5          message: format!($($arg)*),
6          location: $location.to_string(),
7      }
8  };
9}
10
11#[macro_export]
12macro_rules! ts_tt {
13
14  // unwrap single items
15  (( $single:tt )) => {{
16      ts_tt!($single)
17  }};
18
19  // variable
20  (( # $var:ident ))  => {{
21      $var.clone()
22  }};
23
24  // paren
25  (( $($items:tt)+ )) => {{
26      let inner = ts_type!($($items)*);
27      match inner {
28          $crate::TsType::Intersection(_) => $crate::TsType::Paren(Box::new(inner)),
29          $crate::TsType::Union(_) => $crate::TsType::Paren(Box::new(inner)),
30          _ => inner, // remove superfluous parentheses
31      }
32  }};
33
34  // tuple
35  ([ $first:tt $($items:tt)* ]) => {{
36      let tuple = $crate::TsType::Tuple(vec![]);
37      let mut stack = vec![tuple];
38      let mut first = ts_tt!($first);
39      $crate::build_ts_type!(stack first $($items)*)
40  }};
41
42  // base
43  ($base:tt) => {{
44      $crate::TsType::Base(stringify!($base).to_string())
45  }};
46}
47
48#[macro_export]
49macro_rules! build_ts_type {
50
51  // array
52  ($stack:ident $ty:ident [] $($rest:tt)*) => {{
53      $ty = $ty.in_array();
54      $crate::build_ts_type!($stack $ty $($rest)*)
55  }};
56
57  // indexed access
58  ($stack:ident $ty:ident [ $($keys:tt)+ ] $($rest:tt)*) => {{
59      $ty = $ty.property(Box::new(ts_type!($($keys)+)));
60      $crate::build_ts_type!($stack $ty $($rest)*)
61  }};
62
63  // intersection
64  ($stack:ident $ty:ident & $other:tt $($rest:tt)*) => {{
65      let intersection = $crate::TsType::Intersection(vec![$ty]);
66      $stack.push(intersection);
67      $ty = $crate::ts_tt!($other);
68      $crate::build_ts_type!($stack $ty $($rest)*)
69  }};
70
71  // union
72  ($stack:ident $ty:ident | $other:tt $($rest:tt)*) => {{
73      let _union = $crate::TsType::Union(vec![$ty]);
74      $stack.push(_union);
75      $ty = $crate::ts_tt!($other);
76      $crate::build_ts_type!($stack $ty $($rest)*)
77  }};
78
79  // generic
80  ($stack:ident $ty:ident < $arg:tt $($rest:tt)*) => {{
81      $ty = $ty.as_generic(vec![]);
82      $stack.push($ty);
83      let mut arg = $crate::ts_tt!($arg);
84      $crate::build_ts_type!($stack arg $($rest)*)
85  }};
86
87  // comma
88  ($stack:ident $ty:ident , $next:tt $($rest:tt)*) => {{
89      let top: $crate::TsType = $stack.pop().unwrap_or_else(|| {
90          panic!("Unexpected `,` found.");
91      });
92      $stack.push(top.join($ty).unwrap());
93      #[allow(unused_mut)]
94      let mut next = $crate::ts_tt!($next);
95      build_ts_type!($stack next $($rest)*)
96  }};
97
98  // generic end
99  ($stack:ident $arg:ident > $($rest:tt)*) => {{
100      let mut ty = $arg;
101      loop {
102          let top: $crate::TsType = $stack.pop().unwrap_or_else(|| {
103              panic!("Unmatched `>` found.");
104          });
105          ty = top.join(ty).unwrap();
106          if let $crate::TsType::Generic(_, _) = ty {
107              break;
108          } else if $stack.is_empty() {
109              panic!("Unmatched `>` found.");
110          }
111      }
112      $crate::build_ts_type!($stack ty $($rest)*)
113  }};
114
115  // double generic end
116  ($stack:ident $arg:ident >> $($rest:tt)*) => {{
117      let mut ty = $arg;
118      let mut count = 0;
119      loop {
120          let top: $crate::TsType = $stack.pop().unwrap_or_else(|| {
121              panic!("Unmatched `>` found.");
122          });
123          ty = top.join(ty).unwrap();
124          if let $crate::TsType::Generic(_, _) = ty {
125              count += 1;
126          }
127          if count == 2 {
128              break;
129          } else if $stack.is_empty() {
130              panic!("Unmatched `>` found.");
131          }
132      }
133      $crate::build_ts_type!($stack ty $($rest)*)
134  }};
135
136  // base
137  ($stack:ident $ty:ident) => {{
138      let mut ty = $ty;
139      for _ in 0..$stack.len() {
140          let top: $crate::TsType = $stack.pop().unwrap();
141          ty = top.join(ty).unwrap();
142      }
143      ty
144  }};
145}
146
147/// Create a `TsType` using TypeScript type syntax.
148#[macro_export]
149macro_rules! ts_type {
150
151  // union
152  (| $member:tt $($rest:tt)*) => {{
153      let _union = $crate::TsType::Union(vec![]);
154      let mut stack = vec![_union];
155      let mut member = $crate::ts_tt!($member);
156      $crate::build_ts_type!(stack member $($rest)*)
157  }};
158
159  // array
160  ($elem:tt [] $($rest:tt)*) => {{
161      let mut stack = vec![];
162      #[allow(unused_mut)]
163      let mut array = $crate::TsType::Array(Box::new($crate::ts_tt!($elem)));
164      $crate::build_ts_type!(stack array $($rest)*)
165  }};
166
167  // indexed access
168  ($object:tt [ $($key:tt)+ ] $($rest:tt)*) => {{
169      let mut stack = vec![];
170      let mut object = $crate::TsType::IndexedAccess(Box::new(ts_tt!($object)), Box::new(ts_type!($($key)+)));
171      build_ts_type!(stack object $($rest)*)
172  }};
173
174  // generic
175  ($generic:tt < $arg:tt $($rest:tt)*) => {{
176      let generic = $crate::TsType::Generic(Box::new(ts_tt!($generic)), vec![]);
177      let mut stack = vec![generic];
178      #[allow(unused_mut)]
179      let mut arg = ts_tt!($arg);
180      build_ts_type!(stack arg $($rest)*)
181  }};
182
183  // base
184  ($base:tt $($rest:tt)*) => {{
185      let mut stack = vec![];
186      #[allow(unused_mut)]
187      let mut base = $crate::ts_tt!($base);
188      $crate::build_ts_type!(stack base $($rest)*)
189  }};
190}