planus_codegen/
backend_translation.rs

1use planus_types::{
2    ast::Docstrings,
3    intermediate::{
4        AbsolutePath, DeclarationIndex, DeclarationKind, Declarations, NamespaceIndex, SimpleType,
5        Table, Type, TypeKind,
6    },
7};
8use vec_map::VecMap;
9
10use super::backend::{
11    Backend, DeclarationNames, DeclarationTranslationContext, NamespaceNames, ResolvedType,
12};
13use crate::backend::{DeclInfo, Keywords, Names, RelativeNamespace};
14
15#[derive(Debug, Clone)]
16pub struct BackendNamespace<B: ?Sized + Backend> {
17    pub info: B::NamespaceInfo,
18    pub children: Vec<BackendNamespace<B>>,
19    pub declarations: Vec<BackendDeclaration<B>>,
20    pub docstrings: Docstrings,
21}
22
23#[derive(Debug, Clone)]
24pub enum BackendDeclaration<B: ?Sized + Backend> {
25    Table(BackendTable<B>),
26    Struct(BackendStruct<B>),
27    Enum(BackendEnum<B>),
28    Union(BackendUnion<B>),
29    #[allow(dead_code)]
30    RpcService(BackendRpcService<B>),
31}
32
33#[derive(Debug, Clone)]
34pub struct BackendTable<B: ?Sized + Backend> {
35    pub docstrings: Docstrings,
36    pub max_vtable_size: u32,
37    pub _max_size: u32,
38    pub _max_alignment: u32,
39    pub info: B::TableInfo,
40    pub fields: BackendTableFields<B::TableFieldInfo>,
41}
42
43#[derive(Debug, Clone)]
44pub struct BackendStruct<B: ?Sized + Backend> {
45    pub docstrings: Docstrings,
46    pub size: u32,
47    pub alignment: u32,
48    pub info: B::StructInfo,
49    pub fields: Vec<BackendStructField<B::StructFieldInfo>>,
50}
51
52#[derive(Debug, Clone)]
53pub struct BackendEnum<B: ?Sized + Backend> {
54    pub docstrings: Docstrings,
55    pub size: u32,
56    pub info: B::EnumInfo,
57    pub variants: Vec<BackendVariant<B::EnumVariantInfo>>,
58}
59
60#[derive(Debug, Clone)]
61pub struct BackendUnion<B: ?Sized + Backend> {
62    pub docstrings: Docstrings,
63    pub info: B::UnionInfo,
64    pub variants: Vec<BackendVariant<B::UnionVariantInfo>>,
65}
66
67#[derive(Debug, Clone)]
68pub struct BackendRpcService<B: ?Sized + Backend> {
69    pub _docstrings: Docstrings,
70    pub _info: B::RpcServiceInfo,
71    pub _methods: Vec<B::RpcMethodInfo>,
72}
73
74#[derive(Debug, Clone)]
75pub struct NameAndDocstrings {
76    pub original_name: String,
77    pub docstrings: Docstrings,
78}
79
80#[derive(Debug, Clone)]
81pub struct BackendVariant<V> {
82    pub name_and_docs: NameAndDocstrings,
83    pub variant: V,
84}
85
86impl<V> std::ops::Deref for BackendVariant<V> {
87    type Target = V;
88
89    fn deref(&self) -> &V {
90        &self.variant
91    }
92}
93#[derive(Debug, Clone)]
94pub struct BackendTableFields<F> {
95    fields: VecMap<(NameAndDocstrings, F)>,
96    declaration_order: Vec<(usize, u32, BackendTableFieldType)>,
97    alignment_order: Vec<(usize, u32, BackendTableFieldType)>,
98}
99
100impl<F> BackendTableFields<F> {
101    #[allow(clippy::too_many_arguments)]
102    fn new<'a, B: ?Sized + Backend<TableFieldInfo = F>>(
103        declarations: &'a Declarations,
104        backend: &mut B,
105        translation_context: &mut DeclarationTranslationContext<'a, '_, B>,
106        full_translated_decls: &'a VecMap<BackendDeclaration<B>>,
107        decl: &'a Table,
108        decl_path: &AbsolutePath,
109        translated_decl: &B::TableInfo,
110    ) -> BackendTableFields<<B as Backend>::TableFieldInfo> {
111        let mut declaration_order = Vec::new();
112
113        let fields = decl
114            .fields
115            .iter()
116            .enumerate()
117            .filter(|(_index, (_field_name, field))| !field.deprecated)
118            .map(|(index, (field_name, field))| {
119                match &field.type_.kind {
120                    TypeKind::Union(_) => {
121                        declaration_order.push((
122                            index,
123                            field.vtable_index,
124                            BackendTableFieldType::UnionKey,
125                        ));
126                        declaration_order.push((
127                            index,
128                            field.vtable_index + 1,
129                            BackendTableFieldType::UnionValue,
130                        ));
131                    }
132                    TypeKind::Vector(v) if matches!(v.kind, TypeKind::Union(_)) => {
133                        declaration_order.push((
134                            index,
135                            field.vtable_index,
136                            BackendTableFieldType::UnionKeyVector,
137                        ));
138                        declaration_order.push((
139                            index,
140                            field.vtable_index + 1,
141                            BackendTableFieldType::UnionValueVector,
142                        ));
143                    }
144                    _ => {
145                        declaration_order.push((
146                            index,
147                            field.vtable_index,
148                            BackendTableFieldType::Other,
149                        ));
150                    }
151                }
152
153                let translated_type = translate_type(
154                    translation_context,
155                    declarations,
156                    full_translated_decls,
157                    &field.type_,
158                    &decl_path.clone_pop(),
159                );
160                (
161                    index,
162                    (
163                        NameAndDocstrings {
164                            original_name: field_name.clone(),
165                            docstrings: field.docstrings.clone(),
166                        },
167                        backend.generate_table_field(
168                            translation_context,
169                            translated_decl,
170                            decl,
171                            field_name,
172                            field,
173                            translated_type,
174                        ),
175                    ),
176                )
177            })
178            .collect();
179
180        let mut alignment_order = declaration_order.clone();
181        alignment_order.sort_by_key(|(index, _, field_type)| {
182            std::cmp::Reverse(if *field_type == BackendTableFieldType::UnionKey {
183                1
184            } else {
185                decl.fields[*index].object_alignment
186            })
187        });
188
189        BackendTableFields {
190            fields,
191            declaration_order,
192            alignment_order,
193        }
194    }
195
196    pub fn declaration_order(&self) -> impl Iterator<Item = BackendTableField<'_, F>> {
197        self.declaration_order
198            .iter()
199            .filter(|(_, _, field_type)| !field_type.is_key())
200            .map(
201                move |&(index, vtable_index, field_type)| BackendTableField {
202                    field_type,
203                    vtable_index,
204                    name_and_docs: &self.fields[index].0,
205                    info: &self.fields[index].1,
206                },
207            )
208    }
209
210    pub fn alignment_order(&self) -> impl Iterator<Item = BackendTableField<'_, F>> {
211        self.alignment_order
212            .iter()
213            .map(
214                move |&(index, vtable_index, field_type)| BackendTableField {
215                    field_type,
216                    vtable_index,
217                    name_and_docs: &self.fields[index].0,
218                    info: &self.fields[index].1,
219                },
220            )
221    }
222
223    pub fn is_empty(&self) -> bool {
224        self.declaration_order.is_empty()
225    }
226}
227
228impl<F> Default for BackendTableFields<F> {
229    fn default() -> Self {
230        Self {
231            fields: Default::default(),
232            declaration_order: Default::default(),
233            alignment_order: Default::default(),
234        }
235    }
236}
237
238pub struct BackendTableField<'a, F> {
239    pub field_type: BackendTableFieldType,
240    pub vtable_index: u32,
241    pub info: &'a F,
242    pub name_and_docs: &'a NameAndDocstrings,
243}
244
245#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
246pub enum BackendTableFieldType {
247    UnionKey,
248    UnionValue,
249    UnionKeyVector,
250    UnionValueVector,
251    Other,
252}
253
254impl BackendTableFieldType {
255    pub fn is_key(self) -> bool {
256        matches!(self, Self::UnionKey | Self::UnionKeyVector)
257    }
258}
259
260#[derive(Debug, Clone)]
261pub struct BackendStructField<F> {
262    pub offset: u32,
263    pub size: u32,
264    pub padding_after_field: u32,
265    pub info: F,
266    pub name_and_docs: NameAndDocstrings,
267}
268
269fn translate_type_index<'a, B: ?Sized + Backend>(
270    translation_context: &DeclarationTranslationContext<'a, '_, B>,
271    declarations: &'a Declarations,
272    full_translated_decls: &'a VecMap<BackendDeclaration<B>>,
273    index: DeclarationIndex,
274    current_namespace_path: &AbsolutePath,
275) -> ResolvedType<'a, B> {
276    let (path, decl) = &translation_context.translated_decls[index.0];
277    let relative_path: RelativeNamespace<B> = RelativeNamespace::new(
278        current_namespace_path,
279        &path.clone_pop(),
280        translation_context.translated_namespaces,
281        declarations,
282    );
283    match decl {
284        DeclInfo::Table(translated_decl, decl) => {
285            ResolvedType::Table(index, decl, translated_decl, relative_path)
286        }
287        DeclInfo::Struct(translated_decl, decl) => {
288            ResolvedType::Struct(index, decl, translated_decl, relative_path)
289        }
290        DeclInfo::Enum(translated_decl, decl) => {
291            if let BackendDeclaration::Enum(BackendEnum { variants, .. }) =
292                full_translated_decls.get(index.0).unwrap()
293            {
294                ResolvedType::Enum(index, decl, translated_decl, relative_path, variants)
295            } else {
296                unreachable!()
297            }
298        }
299        DeclInfo::Union(translated_decl, decl) => {
300            ResolvedType::Union(index, decl, translated_decl, relative_path)
301        }
302        DeclInfo::RpcService(_translated_decl, _decl) => todo!(),
303    }
304}
305
306fn translate_type<'a, B: ?Sized + Backend>(
307    translation_context: &DeclarationTranslationContext<'a, '_, B>,
308    declarations: &'a Declarations,
309    full_translated_decls: &'a VecMap<BackendDeclaration<B>>,
310    type_: &'a Type,
311    current_namespace_path: &AbsolutePath,
312) -> ResolvedType<'a, B> {
313    match &type_.kind {
314        TypeKind::Table(index)
315        | TypeKind::Union(index)
316        | TypeKind::SimpleType(SimpleType::Struct(index))
317        | TypeKind::SimpleType(SimpleType::Enum(index)) => translate_type_index(
318            translation_context,
319            declarations,
320            full_translated_decls,
321            *index,
322            current_namespace_path,
323        ),
324        TypeKind::SimpleType(type_) => translate_simple_type(
325            translation_context,
326            declarations,
327            full_translated_decls,
328            type_,
329            current_namespace_path,
330        ),
331        TypeKind::Vector(type_) => ResolvedType::Vector(Box::new(translate_type(
332            translation_context,
333            declarations,
334            full_translated_decls,
335            type_,
336            current_namespace_path,
337        ))),
338        TypeKind::Array(type_, size) => ResolvedType::Array(
339            Box::new(translate_type(
340                translation_context,
341                declarations,
342                full_translated_decls,
343                type_,
344                current_namespace_path,
345            )),
346            *size,
347        ),
348        TypeKind::String => ResolvedType::String,
349    }
350}
351
352fn translate_simple_type<'a, B: ?Sized + Backend>(
353    translation_context: &DeclarationTranslationContext<'a, '_, B>,
354    declarations: &'a Declarations,
355    full_translated_decls: &'a VecMap<BackendDeclaration<B>>,
356    type_: &'a SimpleType,
357    current_namespace_path: &AbsolutePath,
358) -> ResolvedType<'a, B> {
359    match type_ {
360        SimpleType::Struct(index) | SimpleType::Enum(index) => translate_type_index(
361            translation_context,
362            declarations,
363            full_translated_decls,
364            *index,
365            current_namespace_path,
366        ),
367        SimpleType::Bool => ResolvedType::Bool,
368        SimpleType::Integer(typ) => ResolvedType::Integer(*typ),
369        SimpleType::Float(typ) => ResolvedType::Float(*typ),
370    }
371}
372
373fn make_recursive_structure<B: ?Sized + Backend>(
374    declarations: &Declarations,
375    translated_namespaces: &mut VecMap<B::NamespaceInfo>,
376    translated_decls: &mut VecMap<BackendDeclaration<B>>,
377    current_namespace_index: NamespaceIndex,
378) -> BackendNamespace<B> {
379    let (_, current_namespace) = declarations.get_namespace(current_namespace_index);
380    let current_translated_namespace = translated_namespaces
381        .remove(current_namespace_index.0)
382        .unwrap();
383    let translated_declarations: Vec<BackendDeclaration<B>> = current_namespace
384        .declaration_ids
385        .values()
386        .map(|id| translated_decls.remove(id.0).unwrap())
387        .collect();
388
389    let children = current_namespace
390        .child_namespaces
391        .values()
392        .map(|id| {
393            make_recursive_structure(declarations, translated_namespaces, translated_decls, *id)
394        })
395        .collect();
396
397    BackendNamespace {
398        info: current_translated_namespace,
399        children,
400        declarations: translated_declarations,
401        docstrings: current_namespace.docstrings.clone(),
402    }
403}
404
405pub fn run_backend<B: ?Sized + Backend>(
406    backend: &mut B,
407    declarations: &Declarations,
408) -> BackendNamespace<B> {
409    let keywords: Keywords = B::KEYWORDS.iter().copied().collect();
410    let mut global_names = Names::new(&keywords);
411    let global_names = &mut global_names;
412    let mut namespace_names = (0..declarations.namespaces.len())
413        .map(|_| Names::new(&keywords))
414        .collect::<Vec<_>>();
415    let mut declaration_names = (0..declarations.declarations.len())
416        .map(|_| Names::new(&keywords))
417        .collect::<Vec<_>>();
418    let translated_namespaces = declarations
419        .namespaces
420        .iter()
421        .zip(&mut namespace_names)
422        .map(|((namespace_name, namespace), namespace_names)| {
423            backend.generate_namespace(
424                &mut NamespaceNames {
425                    _global_names: global_names,
426                    namespace_names,
427                },
428                namespace_name,
429                namespace,
430            )
431        })
432        .collect::<Vec<_>>();
433    let translated_decls: Vec<(AbsolutePath, DeclInfo<B>)> = declarations
434        .declarations
435        .iter()
436        .zip(&mut declaration_names)
437        .enumerate()
438        .map(|(decl_id, ((decl_name, decl), declaration_names))| {
439            let namespace_names = &mut namespace_names[decl.namespace_id.0];
440            let decl: DeclInfo<B> = match &decl.kind {
441                DeclarationKind::Table(decl) => DeclInfo::Table(
442                    backend.generate_table(
443                        &mut DeclarationNames {
444                            _global_names: global_names,
445                            _namespace_names: namespace_names,
446                            declaration_names,
447                        },
448                        &translated_namespaces,
449                        DeclarationIndex(decl_id),
450                        decl_name,
451                        decl,
452                    ),
453                    decl,
454                ),
455                DeclarationKind::Struct(decl) => DeclInfo::Struct(
456                    backend.generate_struct(
457                        &mut DeclarationNames {
458                            _global_names: global_names,
459                            _namespace_names: namespace_names,
460                            declaration_names,
461                        },
462                        &translated_namespaces,
463                        DeclarationIndex(decl_id),
464                        decl_name,
465                        decl,
466                    ),
467                    decl,
468                ),
469                DeclarationKind::Enum(decl) => DeclInfo::Enum(
470                    backend.generate_enum(
471                        &mut DeclarationNames {
472                            _global_names: global_names,
473                            _namespace_names: namespace_names,
474                            declaration_names,
475                        },
476                        &translated_namespaces,
477                        DeclarationIndex(decl_id),
478                        decl_name,
479                        decl,
480                    ),
481                    decl,
482                ),
483                DeclarationKind::Union(decl) => DeclInfo::Union(
484                    backend.generate_union(
485                        &mut DeclarationNames {
486                            _global_names: global_names,
487                            _namespace_names: namespace_names,
488                            declaration_names,
489                        },
490                        &translated_namespaces,
491                        DeclarationIndex(decl_id),
492                        decl_name,
493                        decl,
494                    ),
495                    decl,
496                ),
497                DeclarationKind::RpcService(_decl) => todo!(),
498            };
499            (decl_name.clone(), decl)
500        })
501        .collect::<Vec<_>>();
502
503    let mut full_translated_decls: VecMap<BackendDeclaration<B>> =
504        VecMap::with_capacity(declarations.declarations.len());
505
506    for (i, (((_decl_path, decl), orig_decl), declaration_names)) in translated_decls
507        .iter()
508        .zip(&declarations.declarations)
509        .zip(&mut declaration_names)
510        .enumerate()
511    {
512        if let DeclInfo::Enum(translated_decl, decl) = decl {
513            let namespace_names = &mut namespace_names[orig_decl.1.namespace_id.0];
514            full_translated_decls.insert(
515                i,
516                BackendDeclaration::Enum(BackendEnum {
517                    size: decl.type_.byte_size(),
518                    info: translated_decl.clone(),
519                    variants: decl
520                        .variants
521                        .iter()
522                        .map(|(value, variant)| BackendVariant {
523                            name_and_docs: NameAndDocstrings {
524                                original_name: variant.name.clone(),
525                                docstrings: variant.docstrings.clone(),
526                            },
527                            variant: backend.generate_enum_variant(
528                                &mut DeclarationTranslationContext {
529                                    declaration_names: DeclarationNames {
530                                        _global_names: global_names,
531                                        _namespace_names: namespace_names,
532                                        declaration_names,
533                                    },
534                                    translated_namespaces: &translated_namespaces,
535                                    translated_decls: &translated_decls,
536                                },
537                                translated_decl,
538                                decl,
539                                &variant.name,
540                                value,
541                            ),
542                        })
543                        .collect(),
544                    docstrings: (orig_decl.1).docstrings.clone(),
545                }),
546            );
547        }
548    }
549
550    for (i, (((decl_path, decl), orig_decl), declaration_names)) in translated_decls
551        .iter()
552        .zip(&declarations.declarations)
553        .zip(&mut declaration_names)
554        .enumerate()
555    {
556        let namespace_names = &mut namespace_names[orig_decl.1.namespace_id.0];
557        let mut translation_context = DeclarationTranslationContext {
558            declaration_names: DeclarationNames {
559                _global_names: global_names,
560                _namespace_names: namespace_names,
561                declaration_names,
562            },
563            translated_namespaces: &translated_namespaces,
564            translated_decls: &translated_decls,
565        };
566        let decl = match decl {
567            DeclInfo::Enum(..) => continue,
568            DeclInfo::Table(translated_decl, decl) => BackendDeclaration::Table(BackendTable {
569                max_vtable_size: decl.max_vtable_size,
570                _max_size: decl.max_size,
571                _max_alignment: decl.max_alignment,
572                info: translated_decl.clone(),
573                fields: BackendTableFields::new(
574                    declarations,
575                    backend,
576                    &mut translation_context,
577                    &full_translated_decls,
578                    decl,
579                    decl_path,
580                    translated_decl,
581                ),
582                docstrings: (orig_decl.1).docstrings.clone(),
583            }),
584            DeclInfo::Struct(translated_decl, decl) => BackendDeclaration::Struct(BackendStruct {
585                size: decl.size,
586                alignment: decl.alignment,
587                info: translated_decl.clone(),
588                fields: decl
589                    .fields
590                    .iter()
591                    .map(|(field_name, field)| {
592                        let translated_type = translate_simple_type(
593                            &translation_context,
594                            declarations,
595                            &full_translated_decls,
596                            &field.type_,
597                            &decl_path.clone_pop(),
598                        );
599                        BackendStructField {
600                            info: backend.generate_struct_field(
601                                &mut translation_context,
602                                translated_decl,
603                                decl,
604                                field_name,
605                                field,
606                                translated_type,
607                            ),
608                            offset: field.offset,
609                            padding_after_field: field.padding_after_field,
610                            size: field.size,
611                            name_and_docs: NameAndDocstrings {
612                                original_name: field_name.clone(),
613                                docstrings: field.docstrings.clone(),
614                            },
615                        }
616                    })
617                    .collect(),
618                docstrings: (orig_decl.1).docstrings.clone(),
619            }),
620            DeclInfo::Union(translated_decl, decl) => BackendDeclaration::Union(BackendUnion {
621                info: translated_decl.clone(),
622                variants: decl
623                    .variants
624                    .iter()
625                    .enumerate()
626                    .map(|(index, (name, variant))| {
627                        let translated_type = translate_type(
628                            &translation_context,
629                            declarations,
630                            &full_translated_decls,
631                            &variant.type_,
632                            &decl_path.clone_pop(),
633                        );
634                        BackendVariant {
635                            name_and_docs: NameAndDocstrings {
636                                original_name: name.clone(),
637                                docstrings: variant.docstrings.clone(),
638                            },
639                            variant: backend.generate_union_variant(
640                                &mut translation_context,
641                                translated_decl,
642                                decl,
643                                name,
644                                index as u8,
645                                variant,
646                                translated_type,
647                            ),
648                        }
649                    })
650                    .collect(),
651                docstrings: (orig_decl.1).docstrings.clone(),
652            }),
653            DeclInfo::RpcService(_translated_decl, _decl) => todo!(),
654        };
655        full_translated_decls.insert(i, decl);
656    }
657
658    let mut translated_namespaces: VecMap<_> =
659        translated_namespaces.into_iter().enumerate().collect();
660
661    make_recursive_structure(
662        declarations,
663        &mut translated_namespaces,
664        &mut full_translated_decls,
665        declarations.get_root_namespace().0,
666    )
667}