witx_codegen/assemblyscript/
mod.rs

1mod common;
2mod function;
3mod header;
4mod r#struct;
5mod tuple;
6mod union;
7
8use std::io::Write;
9
10use common::*;
11
12use super::*;
13use crate::astype::*;
14use crate::error::*;
15use crate::pretty_writer::PrettyWriter;
16
17pub struct AssemblyScriptGenerator {
18    module_name: Option<String>,
19}
20
21impl AssemblyScriptGenerator {
22    pub fn new(module_name: Option<String>) -> Self {
23        AssemblyScriptGenerator { module_name }
24    }
25}
26
27impl<T: Write> Generator<T> for AssemblyScriptGenerator {
28    fn generate(
29        &self,
30        writer: &mut T,
31        module_witx: witx::Module,
32        options: &Options,
33    ) -> Result<(), Error> {
34        let mut w = PrettyWriter::new(writer, "    ");
35        let module_name = match &self.module_name {
36            None => module_witx.name().as_str().to_string(),
37            Some(module_name) => module_name.to_string(),
38        };
39        let module_id = module_witx.module_id();
40        let skip_imports = options.skip_imports;
41
42        if !options.skip_header {
43            Self::header(&mut w)?;
44        }
45
46        let module_title_comments = format!(
47            "---------------------- Module: [{}] ----------------------",
48            module_name
49        );
50        Self::write_comments(&mut w, &module_title_comments)?;
51        w.eob()?;
52
53        for type_ in module_witx.typenames() {
54            if skip_imports && &type_.module != module_id {
55                continue;
56            }
57            let constants_for_type: Vec<_> = module_witx
58                .constants()
59                .filter_map(|x| {
60                    if x.ty == type_.name {
61                        Some(ASConstant {
62                            name: x.name.as_str().to_string(),
63                            value: x.value,
64                        })
65                    } else {
66                        None
67                    }
68                })
69                .collect();
70            Self::define_type(&mut w, type_.as_ref(), &constants_for_type)?;
71        }
72
73        for func in module_witx.funcs() {
74            Self::define_func(&mut w, &module_name, func.as_ref())?;
75        }
76
77        Ok(())
78    }
79}
80
81impl AssemblyScriptGenerator {
82    fn write_docs<T: Write>(w: &mut PrettyWriter<T>, docs: &str) -> Result<(), Error> {
83        if docs.is_empty() {
84            return Ok(());
85        }
86        w.write_line("/**")?;
87        for docs_line in docs.lines() {
88            if docs_line.is_empty() {
89                w.write_line(" *")?;
90            } else {
91                w.write_line(format!(" * {}", docs_line))?;
92            }
93        }
94        w.write_line(" */")?;
95        Ok(())
96    }
97
98    fn write_comments<T: Write>(w: &mut PrettyWriter<T>, docs: &str) -> Result<(), Error> {
99        if docs.is_empty() {
100            return Ok(());
101        }
102        w.write_line("/*")?;
103        for docs_line in docs.lines() {
104            if docs_line.is_empty() {
105                w.write_line(" *")?;
106            } else {
107                w.write_line(format!(" * {}", docs_line))?;
108            }
109        }
110        w.write_line(" */")?;
111        Ok(())
112    }
113
114    fn define_as_alias<T: Write>(
115        w: &mut PrettyWriter<T>,
116        name: &str,
117        other_type: &ASType,
118    ) -> Result<(), Error> {
119        w.write_line(format!(
120            "export type {} = {};",
121            name.as_type(),
122            other_type.as_lang()
123        ))?;
124        Ok(())
125    }
126
127    fn define_as_atom<T: Write>(
128        w: &mut PrettyWriter<T>,
129        name: &str,
130        type_: &ASType,
131    ) -> Result<(), Error> {
132        w.write_line(format!(
133            "export type {} = {};",
134            name.as_type(),
135            type_.as_lang()
136        ))?;
137        Ok(())
138    }
139
140    fn define_as_enum<T: Write>(
141        w: &mut PrettyWriter<T>,
142        name: &str,
143        enum_: &ASEnum,
144    ) -> Result<(), Error> {
145        let repr = enum_.repr.as_ref();
146        w.write_line(format!(
147            "export type {} = {};",
148            name.as_type(),
149            repr.as_lang()
150        ))?;
151        w.eob()?;
152        w.write_line(format!("export namespace {} {{", name.as_namespace()))?;
153        {
154            let mut w = w.new_block();
155            for choice in &enum_.choices {
156                w.write_line(format!(
157                    "export const {}: {} = {};",
158                    choice.name.as_const(),
159                    name.as_type(),
160                    choice.value
161                ))?;
162            }
163        }
164        w.write_line("}")?;
165        Ok(())
166    }
167
168    fn define_as_constants<T: Write>(
169        w: &mut PrettyWriter<T>,
170        name: &str,
171        constants: &ASConstants,
172    ) -> Result<(), Error> {
173        let repr = constants.repr.as_ref();
174        w.write_line(format!(
175            "export type {} = {};",
176            name.as_type(),
177            repr.as_lang()
178        ))?;
179        w.eob()?;
180        Self::define_constants_for_type(w, name, &constants.constants)?;
181        Ok(())
182    }
183
184    fn define_as_type<T: Write>(
185        w: &mut PrettyWriter<T>,
186        name: &str,
187        type_: &ASType,
188    ) -> Result<(), Error> {
189        match type_ {
190            ASType::Alias(_)
191            | ASType::Bool
192            | ASType::Char8
193            | ASType::Char32
194            | ASType::F32
195            | ASType::F64
196            | ASType::U8
197            | ASType::U16
198            | ASType::U32
199            | ASType::U64
200            | ASType::S8
201            | ASType::S16
202            | ASType::S32
203            | ASType::S64
204            | ASType::USize
205            | ASType::Handle(_)
206            | ASType::Slice(_)
207            | ASType::String(_)
208            | ASType::ReadBuffer(_)
209            | ASType::WriteBuffer(_) => Self::define_as_atom(w, name, type_)?,
210            ASType::Enum(enum_) => Self::define_as_enum(w, name, enum_)?,
211            ASType::Union(union_) => Self::define_as_union(w, name, union_)?,
212            ASType::Constants(constants) => Self::define_as_constants(w, name, constants)?,
213            ASType::Tuple(members) => Self::define_as_tuple(w, name, members)?,
214            ASType::Struct(members) => Self::define_as_struct(w, name, members)?,
215            _ => {
216                dbg!(type_);
217                unimplemented!();
218            }
219        }
220        Ok(())
221    }
222
223    fn define_constants_for_type<T: Write>(
224        w: &mut PrettyWriter<T>,
225        type_name: &str,
226        constants: &[ASConstant],
227    ) -> Result<(), Error> {
228        if constants.is_empty() {
229            return Ok(());
230        }
231        w.write_line(format!("export namespace {} {{", type_name.as_namespace()))?;
232        {
233            let mut w = w.new_block();
234            let mut hex = false;
235            let mut single_bits: usize = 0;
236            for constant in constants {
237                if constant.value > 0xffff {
238                    hex = true;
239                }
240                if constant.value.count_ones() == 1 {
241                    single_bits += 1;
242                }
243            }
244            if constants.len() > 2 && single_bits == constants.len() {
245                hex = true;
246            }
247            for constant in constants {
248                let value_s = if hex {
249                    format!("0x{:x}", constant.value)
250                } else {
251                    format!("{}", constant.value)
252                };
253                w.write_line(format!(
254                    "export const {}: {} = {};",
255                    constant.name.as_const(),
256                    type_name.as_type(),
257                    value_s
258                ))?;
259            }
260        }
261        w.write_line("}")?;
262        w.eob()?;
263        Ok(())
264    }
265
266    fn define_type<T: Write>(
267        w: &mut PrettyWriter<T>,
268        type_witx: &witx::NamedType,
269        constants: &[ASConstant],
270    ) -> Result<(), Error> {
271        let docs = &type_witx.docs;
272        if !docs.is_empty() {
273            Self::write_docs(w, docs)?;
274        }
275        let type_name = type_witx.name.as_str();
276        let tref = &type_witx.tref;
277        match tref {
278            witx::TypeRef::Name(other_type) => {
279                Self::define_as_alias(w, type_name, &ASType::from(&other_type.tref))?
280            }
281            witx::TypeRef::Value(type_witx) => {
282                let t = ASType::from(type_witx.as_ref());
283                Self::define_as_type(w, type_name, &t)?
284            }
285        }
286        w.eob()?;
287        Self::define_constants_for_type(w, type_name, constants)?;
288        Ok(())
289    }
290}