Fork of daniellemaywood.uk/gleam — Wasm codegen work
21 kB
527 lines
1use ecow::EcoString;
2
3use crate::{
4 ast::{
5 Constant, Publicity, SrcSpan, TypedConstant, TypedConstantBitArraySegment,
6 TypedConstantBitArraySegmentOption,
7 },
8 schema_capnp::{self as schema, *},
9 type_::{
10 self, expression::Implementations, AccessorsMap, Deprecation, FieldMap, RecordAccessor,
11 Type, TypeConstructor, TypeValueConstructor, TypeVar, TypeVariantConstructors,
12 ValueConstructor, ValueConstructorVariant,
13 },
14};
15use std::{collections::HashMap, ops::Deref, sync::Arc};
16
17#[derive(Debug)]
18pub struct ModuleEncoder<'a> {
19 data: &'a type_::ModuleInterface,
20 next_type_var_id: u64,
21 type_var_id_map: HashMap<u64, u64>,
22}
23
24impl<'a> ModuleEncoder<'a> {
25 pub fn new(data: &'a type_::ModuleInterface) -> Self {
26 Self {
27 data,
28 next_type_var_id: 0,
29 type_var_id_map: HashMap::new(),
30 }
31 }
32
33 pub fn encode(mut self) -> crate::Result<Vec<u8>> {
34 let span = tracing::info_span!("metadata");
35 let _enter = span.enter();
36 let mut buffer = Vec::new();
37
38 let mut message = capnp::message::Builder::new_default();
39
40 let mut module = message.init_root::<module::Builder<'_>>();
41 module.set_name(&self.data.name);
42 module.set_package(&self.data.package);
43 module.set_contains_todo(self.data.contains_todo);
44 self.set_module_types(&mut module);
45 self.set_module_values(&mut module);
46 self.set_module_accessors(&mut module);
47 self.set_module_types_constructors(&mut module);
48 self.set_unused_imports(&mut module);
49 self.set_line_numbers(&mut module);
50
51 capnp::serialize_packed::write_message(&mut buffer, &message).expect("capnp encode");
52 Ok(buffer)
53 }
54
55 fn set_line_numbers(&mut self, module: &mut module::Builder<'_>) {
56 let mut line_numbers = module.reborrow().init_line_numbers();
57 line_numbers.set_length(self.data.line_numbers.length);
58 let line_starts =
59 line_numbers.init_line_starts(self.data.line_numbers.line_starts.len() as u32);
60 for (i, l) in self.data.line_numbers.line_starts.iter().enumerate() {
61 line_starts.reborrow().set(i as u32, *l);
62 }
63 }
64
65 fn set_unused_imports(&mut self, module: &mut module::Builder<'_>) {
66 let mut unused_imports = module
67 .reborrow()
68 .init_unused_imports(self.data.unused_imports.len() as u32);
69 for (i, span) in self.data.unused_imports.iter().enumerate() {
70 let unused_import = unused_imports.reborrow().get(i as u32);
71 self.build_src_span(unused_import, *span)
72 }
73 }
74
75 fn set_module_accessors(&mut self, module: &mut module::Builder<'_>) {
76 tracing::trace!("Writing module metadata accessors");
77 let mut builder = module
78 .reborrow()
79 .init_accessors(self.data.accessors.len() as u32);
80 for (i, (key, map)) in self.data.accessors.iter().enumerate() {
81 let mut property = builder.reborrow().get(i as u32);
82 property.set_key(key);
83 self.build_accessors_map(property.init_value(), map);
84 }
85 }
86
87 fn build_accessors_map(
88 &mut self,
89 mut builder: accessors_map::Builder<'_>,
90 accessors: &AccessorsMap,
91 ) {
92 self.build_type(builder.reborrow().init_type(), &accessors.type_);
93 let mut builder = builder.init_accessors(accessors.accessors.len() as u32);
94 for (i, (name, accessor)) in accessors.accessors.iter().enumerate() {
95 let mut property = builder.reborrow().get(i as u32);
96 property.set_key(name);
97 self.build_record_accessor(property.init_value(), accessor)
98 }
99 }
100
101 fn build_record_accessor(
102 &mut self,
103 mut builder: record_accessor::Builder<'_>,
104 accessor: &RecordAccessor,
105 ) {
106 self.build_type(builder.reborrow().init_type(), &accessor.type_);
107 builder.reborrow().set_label(&accessor.label);
108 builder.set_index(accessor.index as u16);
109 }
110
111 fn set_module_types(&mut self, module: &mut module::Builder<'_>) {
112 tracing::trace!("Writing module metadata types");
113 let mut types = module.reborrow().init_types(self.data.types.len() as u32);
114 for (i, (name, type_)) in self.data.types.iter().enumerate() {
115 let mut property = types.reborrow().get(i as u32);
116 property.set_key(name);
117 self.build_type_constructor(property.init_value(), type_)
118 }
119 }
120
121 fn set_module_types_constructors(&mut self, module: &mut module::Builder<'_>) {
122 tracing::trace!("Writing module metadata types to constructors mapping");
123 let mut types_constructors = module
124 .reborrow()
125 .init_types_constructors(self.data.types_value_constructors.len() as u32);
126 for (i, (name, data)) in self.data.types_value_constructors.iter().enumerate() {
127 let mut property = types_constructors.reborrow().get(i as u32);
128 property.set_key(name);
129 self.build_type_variant_constructors(property.init_value(), data)
130 }
131 }
132
133 fn build_type_variant_constructors(
134 &mut self,
135 mut builder: types_variant_constructors::Builder<'_>,
136 data: &TypeVariantConstructors,
137 ) {
138 {
139 let mut builder = builder
140 .reborrow()
141 .init_type_parameters_ids(data.type_parameters_ids.len() as u32);
142 for (i, id) in data.type_parameters_ids.iter().enumerate() {
143 let id = self.get_or_insert_type_var_id(*id);
144 builder.set(i as u32, id as u16);
145 }
146 }
147 let mut builder = builder.init_variants(data.variants.len() as u32);
148 for (i, constructor) in data.variants.iter().enumerate() {
149 self.build_type_value_constructor(builder.reborrow().get(i as u32), constructor);
150 }
151 }
152
153 fn set_module_values(&mut self, module: &mut module::Builder<'_>) {
154 tracing::trace!("Writing module metadata values");
155 let mut values = module.reborrow().init_values(self.data.values.len() as u32);
156 for (i, (name, value)) in self.data.values.iter().enumerate() {
157 let mut property = values.reborrow().get(i as u32);
158 property.set_key(name);
159 self.build_value_constructor(property.init_value(), value)
160 }
161 }
162
163 fn build_type_constructor(
164 &mut self,
165 mut builder: type_constructor::Builder<'_>,
166 constructor: &TypeConstructor,
167 ) {
168 builder.set_module(&constructor.module);
169 builder.set_deprecated(match &constructor.deprecation {
170 Deprecation::NotDeprecated => "",
171 Deprecation::Deprecated { message } => message,
172 });
173 builder.set_publicity(self.publicity(constructor.publicity));
174 let type_builder = builder.reborrow().init_type();
175 self.build_type(type_builder, &constructor.typ);
176 self.build_types(
177 builder
178 .reborrow()
179 .init_parameters(constructor.parameters.len() as u32),
180 &constructor.parameters,
181 );
182 }
183
184 fn build_type_value_constructor(
185 &mut self,
186 mut builder: type_value_constructor::Builder<'_>,
187 constructor: &TypeValueConstructor,
188 ) {
189 builder.set_name(&constructor.name);
190 let mut builder = builder.init_parameters(constructor.parameters.len() as u32);
191 for (i, parameter) in constructor.parameters.iter().enumerate() {
192 self.build_type_value_constructor_parameter(
193 builder.reborrow().get(i as u32),
194 parameter,
195 );
196 }
197 }
198
199 fn build_type_value_constructor_parameter(
200 &mut self,
201 builder: type_value_constructor_parameter::Builder<'_>,
202 parameter: &type_::TypeValueConstructorField,
203 ) {
204 self.build_type(builder.init_type(), parameter.type_.as_ref())
205 }
206
207 fn build_value_constructor(
208 &mut self,
209 mut builder: value_constructor::Builder<'_>,
210 constructor: &ValueConstructor,
211 ) {
212 builder.set_deprecated(match &constructor.deprecation {
213 Deprecation::NotDeprecated => "",
214 Deprecation::Deprecated { message } => message,
215 });
216 builder.set_publicity(self.publicity(constructor.publicity));
217 self.build_type(builder.reborrow().init_type(), &constructor.type_);
218 self.build_value_constructor_variant(builder.init_variant(), &constructor.variant);
219 }
220
221 fn publicity(&self, publicity: Publicity) -> crate::schema_capnp::Publicity {
222 match publicity {
223 Publicity::Public => crate::schema_capnp::Publicity::Public,
224 Publicity::Private => crate::schema_capnp::Publicity::Private,
225 Publicity::Internal => crate::schema_capnp::Publicity::Internal,
226 }
227 }
228
229 fn build_src_span(&mut self, mut builder: src_span::Builder<'_>, span: SrcSpan) {
230 builder.set_start(span.start);
231 builder.set_end(span.end);
232 }
233
234 fn build_value_constructor_variant(
235 &mut self,
236 builder: value_constructor_variant::Builder<'_>,
237 constructor: &ValueConstructorVariant,
238 ) {
239 match constructor {
240 ValueConstructorVariant::LocalVariable { .. } => {
241 panic!("Unexpected local variable value constructor in module interface",)
242 }
243
244 ValueConstructorVariant::LocalConstant { .. } => {
245 panic!("Unexpected local constant value constructor in module interface",)
246 }
247
248 ValueConstructorVariant::ModuleConstant {
249 literal,
250 location,
251 module,
252 documentation: doc,
253 implementations,
254 } => {
255 let mut builder = builder.init_module_constant();
256 builder.set_documentation(doc.as_ref().map(EcoString::as_str).unwrap_or_default());
257 self.build_src_span(builder.reborrow().init_location(), *location);
258 self.build_constant(builder.reborrow().init_literal(), literal);
259 builder.reborrow().set_module(module);
260 self.build_implementations(builder.init_implementations(), *implementations)
261 }
262
263 ValueConstructorVariant::Record {
264 name,
265 field_map,
266 arity,
267 location,
268 module,
269 constructors_count,
270 constructor_index,
271 documentation: doc,
272 } => {
273 let mut builder = builder.init_record();
274 builder.set_name(name);
275 builder.set_module(module);
276 builder.set_arity(*arity);
277 builder.set_documentation(doc.as_ref().map(EcoString::as_str).unwrap_or_default());
278 builder.set_constructors_count(*constructors_count);
279 builder.set_constructor_index(*constructor_index);
280 self.build_optional_field_map(builder.reborrow().init_field_map(), field_map);
281 self.build_src_span(builder.init_location(), *location);
282 }
283
284 ValueConstructorVariant::ModuleFn {
285 arity,
286 field_map,
287 module,
288 name,
289 location,
290 documentation: doc,
291 implementations,
292 } => {
293 let mut builder = builder.init_module_fn();
294 builder.set_name(name);
295 builder.set_module(module);
296 builder.set_arity(*arity as u16);
297 builder.set_documentation(doc.as_ref().map(EcoString::as_str).unwrap_or_default());
298 self.build_optional_field_map(builder.reborrow().init_field_map(), field_map);
299 self.build_src_span(builder.reborrow().init_location(), *location);
300 self.build_implementations(builder.init_implementations(), *implementations);
301 }
302 }
303 }
304
305 fn build_optional_field_map(
306 &mut self,
307 mut builder: option::Builder<'_, field_map::Owned>,
308 field_map: &Option<FieldMap>,
309 ) {
310 match field_map {
311 Some(field_map) => self.build_field_map(builder.init_some(), field_map),
312 None => builder.set_none(()),
313 };
314 }
315
316 fn build_field_map(&mut self, mut builder: field_map::Builder<'_>, field_map: &FieldMap) {
317 builder.set_arity(field_map.arity);
318 let mut builder = builder.init_fields(field_map.fields.len() as u32);
319 for (i, (name, &position)) in field_map.fields.iter().enumerate() {
320 let mut field = builder.reborrow().get(i as u32);
321 field.set_key(name);
322 field.init_value().set_value(position);
323 }
324 }
325
326 fn build_constant(&mut self, mut builder: constant::Builder<'_>, constant: &TypedConstant) {
327 match constant {
328 Constant::Int { value, .. } => builder.set_int(value),
329 Constant::Float { value, .. } => builder.set_float(value),
330 Constant::String { value, .. } => builder.set_string(value),
331
332 Constant::Tuple { elements, .. } => {
333 self.build_constants(builder.init_tuple(elements.len() as u32), elements)
334 }
335
336 Constant::List { elements, typ, .. } => {
337 let mut builder = builder.init_list();
338 self.build_constants(
339 builder.reborrow().init_elements(elements.len() as u32),
340 elements,
341 );
342 self.build_type(builder.init_type(), typ);
343 }
344
345 Constant::BitArray { segments, .. } => {
346 let mut builder = builder.init_bit_array(segments.len() as u32);
347 for (i, segment) in segments.iter().enumerate() {
348 self.build_bit_array_segment(builder.reborrow().get(i as u32), segment);
349 }
350 }
351
352 Constant::Record { args, tag, typ, .. } => {
353 let mut builder = builder.init_record();
354 {
355 let mut builder = builder.reborrow().init_args(args.len() as u32);
356 for (i, arg) in args.iter().enumerate() {
357 self.build_constant(builder.reborrow().get(i as u32), &arg.value);
358 }
359 }
360 builder.reborrow().set_tag(tag);
361 self.build_type(builder.reborrow().init_typ(), typ);
362 }
363
364 Constant::Var {
365 module,
366 name,
367 typ,
368 constructor,
369 ..
370 } => {
371 let mut builder = builder.init_var();
372 match module {
373 Some(name) => builder.set_module(name),
374 None => builder.set_module(""),
375 };
376 builder.set_name(name);
377 self.build_type(builder.reborrow().init_typ(), typ);
378 self.build_value_constructor(
379 builder.reborrow().init_constructor(),
380 constructor
381 .as_ref()
382 .expect("This is guaranteed to hold a value."),
383 );
384 }
385 }
386 }
387
388 fn build_constants(
389 &mut self,
390 mut builder: capnp::struct_list::Builder<'_, constant::Owned>,
391 constant: &[TypedConstant],
392 ) {
393 for (i, constant) in constant.iter().enumerate() {
394 self.build_constant(builder.reborrow().get(i as u32), constant);
395 }
396 }
397
398 fn build_bit_array_segment(
399 &mut self,
400 mut builder: bit_array_segment::Builder<'_>,
401 segment: &TypedConstantBitArraySegment,
402 ) {
403 self.build_constant(builder.reborrow().init_value(), &segment.value);
404 {
405 let mut builder = builder
406 .reborrow()
407 .init_options(segment.options.len() as u32);
408 for (i, option) in segment.options.iter().enumerate() {
409 self.build_bit_array_segment_option(builder.reborrow().get(i as u32), option);
410 }
411 }
412 self.build_type(builder.init_type(), &segment.type_);
413 }
414
415 fn build_bit_array_segment_option(
416 &mut self,
417 mut builder: bit_array_segment_option::Builder<'_>,
418 option: &TypedConstantBitArraySegmentOption,
419 ) {
420 use crate::ast::TypedConstantBitArraySegmentOption as Opt;
421 match option {
422 Opt::Bytes { .. } => builder.set_bytes(()),
423 Opt::Int { .. } => builder.set_integer(()),
424 Opt::Float { .. } => builder.set_float(()),
425 Opt::Bits { .. } => builder.set_bits(()),
426 Opt::Utf8 { .. } => builder.set_utf8(()),
427 Opt::Utf16 { .. } => builder.set_utf16(()),
428 Opt::Utf32 { .. } => builder.set_utf32(()),
429 Opt::Utf8Codepoint { .. } => builder.set_utf8_codepoint(()),
430 Opt::Utf16Codepoint { .. } => builder.set_utf16_codepoint(()),
431 Opt::Utf32Codepoint { .. } => builder.set_utf32_codepoint(()),
432 Opt::Signed { .. } => builder.set_signed(()),
433 Opt::Unsigned { .. } => builder.set_unsigned(()),
434 Opt::Big { .. } => builder.set_big(()),
435 Opt::Little { .. } => builder.set_little(()),
436 Opt::Native { .. } => builder.set_native(()),
437
438 Opt::Size {
439 value, short_form, ..
440 } => {
441 let mut builder = builder.init_size();
442 self.build_constant(builder.reborrow().init_value(), value);
443 builder.set_short_form(*short_form);
444 }
445
446 Opt::Unit { value, .. } => {
447 let mut builder = builder.init_unit();
448 builder.set_value(*value);
449 }
450 }
451 }
452
453 fn build_type(&mut self, builder: schema::type_::Builder<'_>, type_: &Type) {
454 match type_ {
455 Type::Fn { args, retrn } => {
456 let mut fun = builder.init_fn();
457 self.build_types(fun.reborrow().init_arguments(args.len() as u32), args);
458 self.build_type(fun.init_return(), retrn)
459 }
460
461 Type::Named {
462 name,
463 args,
464 module,
465 package,
466 ..
467 } => {
468 let mut app = builder.init_app();
469 app.set_name(name);
470 app.set_module(module);
471 app.set_package(package);
472 self.build_types(app.reborrow().init_parameters(args.len() as u32), args);
473 }
474
475 Type::Tuple { elems } => self.build_types(
476 builder.init_tuple().init_elements(elems.len() as u32),
477 elems,
478 ),
479
480 Type::Var { type_: typ } => match typ.borrow().deref() {
481 TypeVar::Link { type_: typ } => self.build_type(builder, typ),
482 TypeVar::Unbound { id, .. } | TypeVar::Generic { id } => {
483 self.build_type_var(builder.init_var(), *id)
484 }
485 },
486 }
487 }
488
489 fn build_types(
490 &mut self,
491 mut builder: capnp::struct_list::Builder<'_, schema::type_::Owned>,
492 types: &[Arc<Type>],
493 ) {
494 for (i, type_) in types.iter().enumerate() {
495 self.build_type(builder.reborrow().get(i as u32), type_);
496 }
497 }
498
499 fn build_type_var(&mut self, mut builder: schema::type_::var::Builder<'_>, id: u64) {
500 let serialised_id = self.get_or_insert_type_var_id(id);
501 builder.set_id(serialised_id);
502 }
503
504 fn get_or_insert_type_var_id(&mut self, id: u64) -> u64 {
505 match self.type_var_id_map.get(&id) {
506 Some(&id) => id,
507 None => {
508 let new_id = self.next_type_var_id;
509 self.next_type_var_id += 1;
510 let _ = self.type_var_id_map.insert(id, new_id);
511 new_id
512 }
513 }
514 }
515
516 fn build_implementations(
517 &self,
518 mut builder: implementations::Builder<'_>,
519 implementations: Implementations,
520 ) {
521 builder.set_gleam(implementations.gleam);
522 builder.set_uses_erlang_externals(implementations.uses_erlang_externals);
523 builder.set_uses_javascript_externals(implementations.uses_javascript_externals);
524 builder.set_can_run_on_erlang(implementations.can_run_on_erlang);
525 builder.set_can_run_on_javascript(implementations.can_run_on_javascript);
526 }
527}