1use Flavor;
4use errors::Result;
5use linked_hash_map::LinkedHashMap;
6use std::cell::RefCell;
7use std::rc::Rc;
8use {CoreFlavor, Diagnostics, Loc, RpEndpoint, RpEnumType, RpField, RpName, RpReg, RpType,
9 RpVersionedPackage};
10
11pub trait PackageTranslator<K, V> {
13 fn translate_package(&self, source: K) -> Result<V>;
15}
16
17pub trait FlavorTranslator {
18 type Source: 'static + Clone + Flavor;
19 type Target: 'static + Clone + Flavor;
20
21 fn translate_i32(&self) -> Result<<Self::Target as Flavor>::Type>;
22
23 fn translate_i64(&self) -> Result<<Self::Target as Flavor>::Type>;
24
25 fn translate_u32(&self) -> Result<<Self::Target as Flavor>::Type>;
26
27 fn translate_u64(&self) -> Result<<Self::Target as Flavor>::Type>;
28
29 fn translate_float(&self) -> Result<<Self::Target as Flavor>::Type>;
30
31 fn translate_double(&self) -> Result<<Self::Target as Flavor>::Type>;
32
33 fn translate_boolean(&self) -> Result<<Self::Target as Flavor>::Type>;
34
35 fn translate_string(&self) -> Result<<Self::Target as Flavor>::Type>;
36
37 fn translate_datetime(&self) -> Result<<Self::Target as Flavor>::Type>;
38
39 fn translate_array(
40 &self,
41 _: <Self::Target as Flavor>::Type,
42 ) -> Result<<Self::Target as Flavor>::Type>;
43
44 fn translate_map(
45 &self,
46 _: <Self::Target as Flavor>::Type,
47 _: <Self::Target as Flavor>::Type,
48 ) -> Result<<Self::Target as Flavor>::Type>;
49
50 fn translate_any(&self) -> Result<<Self::Target as Flavor>::Type>;
51
52 fn translate_bytes(&self) -> Result<<Self::Target as Flavor>::Type>;
53
54 fn translate_package(
56 &self,
57 package: <Self::Source as Flavor>::Package,
58 ) -> Result<<Self::Target as Flavor>::Package>;
59
60 fn translate_name(
62 &self,
63 reg: RpReg,
64 name: Loc<RpName<Self::Target>>,
65 ) -> Result<<Self::Target as Flavor>::Type>;
66
67 fn translate_field<T>(
69 &self,
70 translator: &T,
71 diag: &mut Diagnostics,
72 field: <Self::Source as Flavor>::Field,
73 ) -> Result<<Self::Target as Flavor>::Field>
74 where
75 T: Translator<Source = Self::Source, Target = Self::Target>;
76
77 fn translate_endpoint<T>(
79 &self,
80 translator: &T,
81 diag: &mut Diagnostics,
82 endpoint: <Self::Source as Flavor>::Endpoint,
83 ) -> Result<<Self::Target as Flavor>::Endpoint>
84 where
85 T: Translator<Source = Self::Source, Target = Self::Target>;
86
87 fn translate_local_name<T>(
89 &self,
90 translator: &T,
91 diag: &mut Diagnostics,
92 reg: RpReg,
93 name: <Self::Source as Flavor>::Name,
94 ) -> Result<<Self::Target as Flavor>::Name>
95 where
96 T: Translator<Source = Self::Source, Target = Self::Target>;
97
98 fn translate_enum_type<T>(
100 &self,
101 translator: &T,
102 diag: &mut Diagnostics,
103 enum_type: <Self::Source as Flavor>::EnumType,
104 ) -> Result<<Self::Target as Flavor>::EnumType>
105 where
106 T: Translator<Source = Self::Source, Target = Self::Target>;
107}
108
109impl PackageTranslator<RpVersionedPackage, RpVersionedPackage> for () {
110 fn translate_package(&self, package: RpVersionedPackage) -> Result<RpVersionedPackage> {
111 Ok(package)
112 }
113}
114
115pub struct CoreFlavorTranslator<P, F> {
116 package_translator: P,
117 flavor: ::std::marker::PhantomData<F>,
118}
119
120impl<P, F> CoreFlavorTranslator<P, F> {
121 pub fn new(package_translator: P) -> Self {
122 Self {
123 package_translator,
124 flavor: ::std::marker::PhantomData,
125 }
126 }
127}
128
129impl<P: 'static, F: 'static> FlavorTranslator for CoreFlavorTranslator<P, F>
130where
131 P: PackageTranslator<RpVersionedPackage, F::Package>,
132 F: Flavor<
133 Type = RpType<F>,
134 Field = RpField<F>,
135 Endpoint = RpEndpoint<F>,
136 Name = Loc<RpName<F>>,
137 EnumType = RpEnumType,
138 >,
139{
140 type Source = CoreFlavor;
141 type Target = F;
142
143 translator_defaults!(Self, rp_type, local_name, field, endpoint, enum_type);
144
145 fn translate_package(
146 &self,
147 package: <Self::Source as Flavor>::Package,
148 ) -> Result<<F as Flavor>::Package> {
149 self.package_translator.translate_package(package)
150 }
151}
152
153pub trait Translator {
155 type Source: 'static + Flavor;
156 type Target: 'static + Flavor;
157
158 fn visit(&self, _: &mut Diagnostics, _: &<Self::Source as Flavor>::Name) -> Result<()> {
160 Ok(())
161 }
162
163 fn translate_package(
165 &self,
166 <Self::Source as Flavor>::Package,
167 ) -> Result<<Self::Target as Flavor>::Package>;
168
169 fn translate_type(
171 &self,
172 diag: &mut Diagnostics,
173 <Self::Source as Flavor>::Type,
174 ) -> Result<<Self::Target as Flavor>::Type>;
175
176 fn translate_field(
178 &self,
179 diag: &mut Diagnostics,
180 <Self::Source as Flavor>::Field,
181 ) -> Result<<Self::Target as Flavor>::Field>;
182
183 fn translate_endpoint(
185 &self,
186 diag: &mut Diagnostics,
187 <Self::Source as Flavor>::Endpoint,
188 ) -> Result<<Self::Target as Flavor>::Endpoint>;
189
190 fn translate_local_name(
192 &self,
193 diag: &mut Diagnostics,
194 reg: RpReg,
195 name: <Self::Source as Flavor>::Name,
196 ) -> Result<<Self::Target as Flavor>::Name>;
197
198 fn translate_enum_type(
200 &self,
201 diag: &mut Diagnostics,
202 enum_type: <Self::Source as Flavor>::EnumType,
203 ) -> Result<<Self::Target as Flavor>::EnumType>;
204}
205
206pub trait Translate<T>
208where
209 T: Translator<Source = Self::Source>,
210{
211 type Source: 'static + Flavor;
212 type Out;
213
214 fn translate(self, diag: &mut Diagnostics, translator: &T) -> Result<Self::Out>;
216}
217
218impl<T, I> Translate<T> for Loc<I>
219where
220 I: Translate<T>,
221 T: Translator<Source = I::Source>,
222{
223 type Source = I::Source;
224 type Out = Loc<I::Out>;
225
226 fn translate(self, diag: &mut Diagnostics, translator: &T) -> Result<Loc<I::Out>> {
228 Loc::and_then(self, |s| s.translate(diag, translator))
229 }
230}
231
232impl<T, I> Translate<T> for Vec<I>
233where
234 I: Translate<T>,
235 T: Translator<Source = I::Source>,
236{
237 type Source = I::Source;
238 type Out = Vec<I::Out>;
239
240 fn translate(self, diag: &mut Diagnostics, translator: &T) -> Result<Vec<I::Out>> {
242 self.into_iter()
243 .map(|v| v.translate(diag, translator))
244 .collect::<Result<Vec<_>>>()
245 }
246}
247
248impl<T, I> Translate<T> for Option<I>
249where
250 I: Translate<T>,
251 T: Translator<Source = I::Source>,
252{
253 type Source = I::Source;
254 type Out = Option<I::Out>;
255
256 fn translate(self, diag: &mut Diagnostics, translator: &T) -> Result<Option<I::Out>> {
258 let out = match self {
259 Some(inner) => Some(inner.translate(diag, translator)?),
260 None => None,
261 };
262
263 Ok(out)
264 }
265}
266
267pub struct Fields<F>(pub Vec<Loc<F>>);
268
269impl<T, F: 'static> Translate<T> for Fields<F::Field>
270where
271 F: Flavor,
272 T: Translator<Source = F>,
273{
274 type Source = F;
275 type Out = Vec<Loc<<T::Target as Flavor>::Field>>;
276
277 fn translate(self, diag: &mut Diagnostics, translator: &T) -> Result<Self::Out> {
279 let out = self.0
280 .into_iter()
281 .map(|f| Loc::and_then(f, |f| translator.translate_field(diag, f)))
282 .collect::<Result<Vec<_>>>()?;
283
284 Ok(out)
285 }
286}
287
288pub struct Context<T>
290where
291 T: FlavorTranslator<Source = CoreFlavor>,
292{
293 pub flavor: T,
295 pub types: Rc<LinkedHashMap<RpName<T::Source>, Loc<RpReg>>>,
297 pub decls: Option<RefCell<LinkedHashMap<RpName<T::Source>, RpReg>>>,
299}
300
301impl<T> Context<T>
302where
303 T: FlavorTranslator<Source = CoreFlavor>,
304{
305 fn lookup(&self, diag: &mut Diagnostics, key: &Loc<RpName<T::Source>>) -> Result<RpReg> {
307 let (key, span) = Loc::borrow_pair(key);
308 let key = key.clone().without_prefix();
309
310 let decls = self.decls.as_ref().ok_or_else(|| "no declarations")?;
311 let mut decls = decls.try_borrow_mut()?;
312
313 match decls.get(&key) {
314 Some(reg) => return Ok(reg.clone()),
315 None => {}
316 }
317
318 let reg = match self.types.get(&key) {
319 Some(reg) => Loc::borrow(reg).clone(),
320 None => {
321 diag.err(span, format!("`{}` does not exist", key));
322 return Err(format!("no such type: {}", key).into());
323 }
324 };
325
326 let reg = decls.entry(key).or_insert(reg);
327 return Ok(reg.clone());
328 }
329}
330
331impl<T> Translator for Context<T>
332where
333 T: FlavorTranslator<Source = CoreFlavor>,
334{
335 type Source = T::Source;
336 type Target = T::Target;
337
338 fn visit(&self, diag: &mut Diagnostics, name: &Loc<RpName<Self::Source>>) -> Result<()> {
340 self.lookup(diag, name)?;
341 Ok(())
342 }
343
344 fn translate_package(
345 &self,
346 source: <Self::Source as Flavor>::Package,
347 ) -> Result<<Self::Target as Flavor>::Package> {
348 self.flavor.translate_package(source)
349 }
350
351 fn translate_type(
352 &self,
353 diag: &mut Diagnostics,
354 source: <Self::Source as Flavor>::Type,
355 ) -> Result<<Self::Target as Flavor>::Type> {
356 use self::RpType::*;
357
358 let out = match source {
359 String => self.flavor.translate_string()?,
360 DateTime => self.flavor.translate_datetime()?,
361 Bytes => self.flavor.translate_bytes()?,
362 Signed { size: 32 } => self.flavor.translate_i32()?,
363 Signed { size: 64 } => self.flavor.translate_i64()?,
364 Unsigned { size: 32 } => self.flavor.translate_u32()?,
365 Unsigned { size: 64 } => self.flavor.translate_u64()?,
366 Float => self.flavor.translate_float()?,
367 Double => self.flavor.translate_double()?,
368 Boolean => self.flavor.translate_boolean()?,
369 Array { inner } => {
370 let inner = self.translate_type(diag, *inner)?;
371 self.flavor.translate_array(inner)?
372 }
373 Name { name } => {
374 let reg = self.lookup(diag, &name)?;
375 let name = name.translate(diag, self)?;
376 self.flavor.translate_name(reg, name)?
377 }
378 Map { key, value } => {
379 let key = self.translate_type(diag, *key)?;
380 let value = self.translate_type(diag, *value)?;
381 self.flavor.translate_map(key, value)?
382 }
383 Any => self.flavor.translate_any()?,
384 ty => return Err(format!("unsupported type: {}", ty).into()),
385 };
386
387 Ok(out)
388 }
389
390 fn translate_field(
391 &self,
392 diag: &mut Diagnostics,
393 source: <Self::Source as Flavor>::Field,
394 ) -> Result<<Self::Target as Flavor>::Field> {
395 self.flavor.translate_field(self, diag, source)
396 }
397
398 fn translate_endpoint(
399 &self,
400 diag: &mut Diagnostics,
401 source: <Self::Source as Flavor>::Endpoint,
402 ) -> Result<<Self::Target as Flavor>::Endpoint> {
403 self.flavor.translate_endpoint(self, diag, source)
404 }
405
406 fn translate_local_name(
408 &self,
409 diag: &mut Diagnostics,
410 reg: RpReg,
411 name: <Self::Source as Flavor>::Name,
412 ) -> Result<<Self::Target as Flavor>::Name> {
413 self.flavor.translate_local_name(self, diag, reg, name)
414 }
415
416 fn translate_enum_type(
418 &self,
419 diag: &mut Diagnostics,
420 enum_type: <Self::Source as Flavor>::EnumType,
421 ) -> Result<<Self::Target as Flavor>::EnumType> {
422 self.flavor.translate_enum_type(self, diag, enum_type)
423 }
424}