witx_codegen/assemblyscript/
mod.rs1mod 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}