reproto_core/
translator.rs

1//! Translates one IR in-place into another.
2
3use 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
11/// Method for translating package.
12pub trait PackageTranslator<K, V> {
13    /// Translate the given package.
14    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    /// Translate the given package.
55    fn translate_package(
56        &self,
57        package: <Self::Source as Flavor>::Package,
58    ) -> Result<<Self::Target as Flavor>::Package>;
59
60    /// Translate the given name.
61    fn translate_name(
62        &self,
63        reg: RpReg,
64        name: Loc<RpName<Self::Target>>,
65    ) -> Result<<Self::Target as Flavor>::Type>;
66
67    /// Translate the given field.
68    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    /// Translate the given endpoint.
78    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    /// Translate a local declaration name.
88    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    /// Enum type to translate.
99    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
153/// Translator trait from one flavor to another.
154pub trait Translator {
155    type Source: 'static + Flavor;
156    type Target: 'static + Flavor;
157
158    /// Indicate that the given name has been visited.
159    fn visit(&self, _: &mut Diagnostics, _: &<Self::Source as Flavor>::Name) -> Result<()> {
160        Ok(())
161    }
162
163    /// Translate the given package from one flavor to another.
164    fn translate_package(
165        &self,
166        <Self::Source as Flavor>::Package,
167    ) -> Result<<Self::Target as Flavor>::Package>;
168
169    /// Translate the given type from one flavor to another.
170    fn translate_type(
171        &self,
172        diag: &mut Diagnostics,
173        <Self::Source as Flavor>::Type,
174    ) -> Result<<Self::Target as Flavor>::Type>;
175
176    /// Translate the given field from one flavor to another.
177    fn translate_field(
178        &self,
179        diag: &mut Diagnostics,
180        <Self::Source as Flavor>::Field,
181    ) -> Result<<Self::Target as Flavor>::Field>;
182
183    /// Translate the given endpoint from one flavor to another.
184    fn translate_endpoint(
185        &self,
186        diag: &mut Diagnostics,
187        <Self::Source as Flavor>::Endpoint,
188    ) -> Result<<Self::Target as Flavor>::Endpoint>;
189
190    /// Translate a local declaration name.
191    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    /// Enum type to translate.
199    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
206/// A translated type.
207pub trait Translate<T>
208where
209    T: Translator<Source = Self::Source>,
210{
211    type Source: 'static + Flavor;
212    type Out;
213
214    /// Translate into different flavor.
215    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    /// Translate into different flavor.
227    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    /// Translate into different flavor.
241    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    /// Translate into different flavor.
257    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    /// Translate into different flavor.
278    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
288/// Context used when translating.
289pub struct Context<T>
290where
291    T: FlavorTranslator<Source = CoreFlavor>,
292{
293    /// Type used to translate types.
294    pub flavor: T,
295    /// Registered declarations of the source type.
296    pub types: Rc<LinkedHashMap<RpName<T::Source>, Loc<RpReg>>>,
297    /// Cached and translated registered declarations.
298    pub decls: Option<RefCell<LinkedHashMap<RpName<T::Source>, RpReg>>>,
299}
300
301impl<T> Context<T>
302where
303    T: FlavorTranslator<Source = CoreFlavor>,
304{
305    /// Lookup and cause the given name to be registered.
306    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    /// Indicate that the given name has been visited.
339    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    /// Translate a local declaration name.
407    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    /// Translate enum type.
417    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}