Skip to main content

mproto_codegen/codegen/
mod.rs

1use genco::prelude::*;
2
3use crate::{ast::QualifiedIdentifier, Database};
4
5pub use codegen_cx::{
6    type_uses_param, type_uses_type_param, CodegenCx, ResolvedType, TypeParamBinding,
7    TypeParamBindings,
8};
9pub(crate) use type_base_len::{
10    enum_base_len, enum_variant_base_len, struct_base_len, type_base_len, TypeBaseLen,
11};
12
13mod codegen_cx;
14pub mod js;
15pub mod name_util;
16pub mod rust;
17mod type_base_len;
18
19pub trait MprotoLang {
20    type GencoLang: genco::lang::Lang;
21
22    fn associated_constant(type_name: &str, constant: &str) -> Tokens<Self::GencoLang>;
23
24    // mproto specific concepts
25    fn type_param_base_len(type_name: &str) -> Tokens<Self::GencoLang>;
26    fn const_fn_max() -> Tokens<Self::GencoLang>;
27    fn import_qualified(
28        db: &Database,
29        local_def_source: Option<&str>,
30        qualified_identifier: &QualifiedIdentifier,
31    ) -> Tokens<Self::GencoLang>;
32}
33
34#[derive(Debug, Eq, PartialEq)]
35pub enum MprotoJs {}
36#[derive(Debug, Eq, PartialEq)]
37pub enum MprotoRust {}
38
39impl MprotoLang for MprotoJs {
40    type GencoLang = genco::lang::JavaScript;
41
42    fn associated_constant(type_name: &str, constant: &str) -> Tokens<Self::GencoLang> {
43        quote! { $type_name.$constant }
44    }
45
46    fn type_param_base_len(type_name: &str) -> Tokens<Self::GencoLang> {
47        quote! { this.$(type_name)Encoder.baseLength() }
48    }
49
50    fn const_fn_max() -> Tokens<Self::GencoLang> {
51        quote! { Math.max }
52    }
53
54    fn import_qualified(
55        db: &Database,
56        local_def_source: Option<&str>,
57        qualified_identifier: &QualifiedIdentifier,
58    ) -> Tokens<Self::GencoLang> {
59        if let Some(module) = &qualified_identifier.module {
60            // Import from some other crate.
61            let lib_suffix = db
62                .lookup_module_lib_suffix(module)
63                // TODO error handling
64                .expect(&format!("module '{module}' not found"));
65            quote! {
66                $(genco::lang::js::import(
67                    format!("{module}-{lib_suffix}").as_ref(),
68                    &qualified_identifier.name,
69                ))
70            }
71        } else if let Some(local_def_source) = local_def_source {
72            // Import from a module in the same crate.
73            quote! {
74                $(genco::lang::js::import(
75                    local_def_source,
76                    &qualified_identifier.name,
77                ))
78            }
79        } else {
80            // No import required.
81            quote! { $(&qualified_identifier.name) }
82        }
83    }
84}
85
86impl MprotoLang for MprotoRust {
87    type GencoLang = genco::lang::Rust;
88
89    fn associated_constant(type_name: &str, constant: &str) -> Tokens<Self::GencoLang> {
90        quote! { $type_name::$constant }
91    }
92
93    fn type_param_base_len(type_name: &str) -> Tokens<Self::GencoLang> {
94        Self::associated_constant(type_name, "BASE_LEN")
95    }
96
97    fn const_fn_max() -> Tokens<Self::GencoLang> {
98        quote! { $(genco::lang::rust::import("mproto", "max")) }
99    }
100
101    fn import_qualified(
102        db: &Database,
103        local_def_source: Option<&str>,
104        qualified_identifier: &QualifiedIdentifier,
105    ) -> Tokens<Self::GencoLang> {
106        if let Some(module) = &qualified_identifier.module {
107            // Import from some other crate.
108            let lib_suffix = db
109                .lookup_module_lib_suffix(module)
110                // TODO error handling
111                .expect(&format!("module '{module}' not found"));
112            quote! {
113                $(
114                    genco::lang::rust::import(
115                        &format!("{module}_{lib_suffix}"),
116                        &qualified_identifier.name,
117                    )
118                    .qualified()
119                )
120            }
121        } else if let Some(local_def_source) = local_def_source {
122            // Import from a module in the same crate.
123            quote! {
124                $(genco::lang::rust::import(
125                    local_def_source,
126                    &qualified_identifier.name,
127                ))
128            }
129        } else {
130            // No import required.
131            quote! { $(&qualified_identifier.name) }
132        }
133    }
134}