Fork of daniellemaywood.uk/gleam — Wasm codegen work
20 kB
667 lines
1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2020 The Gleam contributors
3
4//! Seriaisation and deserialisation of Gleam compiler metadata into binary files
5//! using serde.
6
7#[cfg(test)]
8mod tests;
9
10use std::{collections::HashMap, sync::Arc};
11
12use crate::{
13 ast::{
14 BitArrayOption, BitArraySegment, CallArg, Constant, RecordBeingUpdated, RecordUpdateArg,
15 TypedConstant,
16 },
17 type_::{
18 self, AccessorsMap, ModuleInterface, RecordAccessor, Type, TypeAliasConstructor,
19 TypeConstructor, TypeValueConstructor, TypeValueConstructorField, TypeVar,
20 TypeVariantConstructors, ValueConstructor, ValueConstructorVariant,
21 },
22 uid::UniqueIdGenerator,
23};
24
25pub fn encode(module: &ModuleInterface) -> Result<Vec<u8>, bincode::error::EncodeError> {
26 bincode::serde::encode_to_vec(module, bincode::config::legacy())
27}
28
29pub fn decode(
30 bytes: &[u8],
31 ids: UniqueIdGenerator,
32) -> Result<ModuleInterface, bincode::error::DecodeError> {
33 bincode::serde::decode_from_slice(bytes, bincode::config::legacy())
34 .map(|(module, _)| remap_type_variable_ids(module, ids))
35}
36
37fn remap_type_variable_ids(module: ModuleInterface, ids: UniqueIdGenerator) -> ModuleInterface {
38 RemapIds::new(ids).module(module)
39}
40
41struct RemapIds {
42 ids: UniqueIdGenerator,
43 remapped_variable_ids: HashMap<u64, u64>,
44}
45
46impl RemapIds {
47 fn new(ids: UniqueIdGenerator) -> Self {
48 Self {
49 ids,
50 remapped_variable_ids: HashMap::new(),
51 }
52 }
53
54 fn module(&mut self, module: ModuleInterface) -> ModuleInterface {
55 let ModuleInterface {
56 name,
57 origin,
58 package,
59 types,
60 types_value_constructors,
61 values,
62 accessors,
63 line_numbers,
64 src_path,
65 is_internal,
66 warnings,
67 minimum_required_version,
68 type_aliases,
69 documentation,
70 contains_echo,
71 references,
72 inline_functions,
73 } = module;
74
75 let types = types
76 .into_iter()
77 .map(|(name, type_)| (name, self.type_constructor(type_)))
78 .collect();
79 let types_value_constructors = types_value_constructors
80 .into_iter()
81 .map(|(name, type_)| (name, self.type_variant_constructors(type_)))
82 .collect();
83 let values = values
84 .into_iter()
85 .map(|(name, value)| (name, self.value_constructor(value)))
86 .collect();
87 let accessors = accessors
88 .into_iter()
89 .map(|(name, accessors)| (name, self.accessors_map(accessors)))
90 .collect();
91 let type_aliases = type_aliases
92 .into_iter()
93 .map(|(name, type_)| (name, self.type_alias(type_)))
94 .collect();
95
96 ModuleInterface {
97 name,
98 origin,
99 package,
100 types,
101 types_value_constructors,
102 values,
103 accessors,
104 line_numbers,
105 src_path,
106 is_internal,
107 warnings,
108 minimum_required_version,
109 type_aliases,
110 documentation,
111 contains_echo,
112 references,
113 inline_functions,
114 }
115 }
116
117 fn type_constructor(&mut self, type_: TypeConstructor) -> TypeConstructor {
118 let TypeConstructor {
119 publicity,
120 origin,
121 module,
122 parameters,
123 type_,
124 deprecation,
125 documentation,
126 } = type_;
127
128 let parameters = parameters
129 .into_iter()
130 .map(|parameter| self.type_(parameter))
131 .collect();
132 let type_ = self.type_(type_);
133
134 TypeConstructor {
135 publicity,
136 origin,
137 module,
138 parameters,
139 type_,
140 deprecation,
141 documentation,
142 }
143 }
144
145 fn type_variant_constructors(
146 &mut self,
147 type_: TypeVariantConstructors,
148 ) -> TypeVariantConstructors {
149 let TypeVariantConstructors {
150 type_parameters_ids,
151 opaque,
152 variants,
153 } = type_;
154
155 let type_parameters_ids = type_parameters_ids
156 .into_iter()
157 .map(|id| self.id(id))
158 .collect();
159
160 let variants = variants
161 .into_iter()
162 .map(|variant| self.type_value_constructor(variant))
163 .collect();
164
165 TypeVariantConstructors {
166 type_parameters_ids,
167 opaque,
168 variants,
169 }
170 }
171
172 fn type_value_constructor(&mut self, variant: TypeValueConstructor) -> TypeValueConstructor {
173 let TypeValueConstructor {
174 name,
175 parameters,
176 documentation,
177 } = variant;
178
179 let parameters = parameters
180 .into_iter()
181 .map(
182 |TypeValueConstructorField {
183 type_,
184 label,
185 documentation,
186 }| TypeValueConstructorField {
187 type_: self.type_(type_),
188 label,
189 documentation,
190 },
191 )
192 .collect();
193
194 TypeValueConstructor {
195 name,
196 parameters,
197 documentation,
198 }
199 }
200
201 fn value_constructor(&mut self, value: ValueConstructor) -> ValueConstructor {
202 let ValueConstructor {
203 publicity,
204 deprecation,
205 variant,
206 type_,
207 } = value;
208
209 let variant = self.value_constructor_variant(variant);
210
211 let type_ = self.type_(type_);
212
213 ValueConstructor {
214 publicity,
215 deprecation,
216 variant,
217 type_,
218 }
219 }
220
221 fn value_constructor_variant(
222 &mut self,
223 variant: ValueConstructorVariant,
224 ) -> ValueConstructorVariant {
225 match variant {
226 ValueConstructorVariant::LocalVariable { location, origin } => {
227 ValueConstructorVariant::LocalVariable { location, origin }
228 }
229 ValueConstructorVariant::ModuleConstant {
230 documentation,
231 location,
232 module,
233 name,
234 literal,
235 implementations,
236 } => ValueConstructorVariant::ModuleConstant {
237 documentation,
238 location,
239 module,
240 name,
241 literal: self.constant(literal),
242 implementations,
243 },
244 ValueConstructorVariant::ModuleFn {
245 name,
246 field_map,
247 module,
248 arity,
249 location,
250 documentation,
251 implementations,
252 external_erlang,
253 external_javascript,
254 external_wasm,
255 purity,
256 } => ValueConstructorVariant::ModuleFn {
257 name,
258 field_map,
259 module,
260 arity,
261 location,
262 documentation,
263 implementations,
264 external_erlang,
265 external_javascript,
266 external_wasm,
267 purity,
268 },
269 ValueConstructorVariant::Record {
270 name,
271 arity,
272 field_map,
273 location,
274 module,
275 variants_count,
276 variant_index,
277 documentation,
278 } => ValueConstructorVariant::Record {
279 name,
280 arity,
281 field_map,
282 location,
283 module,
284 variants_count,
285 variant_index,
286 documentation,
287 },
288 }
289 }
290
291 fn constant(&mut self, constant: TypedConstant) -> TypedConstant {
292 match constant {
293 Constant::Int {
294 location,
295 value,
296 int_value,
297 } => Constant::Int {
298 location,
299 value,
300 int_value,
301 },
302 Constant::Float {
303 location,
304 value,
305 float_value,
306 } => Constant::Float {
307 location,
308 value,
309 float_value,
310 },
311 Constant::String { location, value } => Constant::String { location, value },
312 Constant::Tuple {
313 location,
314 elements,
315 type_,
316 } => Constant::Tuple {
317 location,
318 elements: elements
319 .into_iter()
320 .map(|element| self.constant(element))
321 .collect(),
322 type_: self.type_(type_),
323 },
324 Constant::List {
325 location,
326 elements,
327 type_,
328 tail,
329 } => Constant::List {
330 location,
331 elements: elements
332 .into_iter()
333 .map(|element| self.constant(element))
334 .collect(),
335 type_: self.type_(type_),
336 tail: tail.map(|tail| Box::new(self.constant(*tail))),
337 },
338 Constant::Record {
339 location,
340 module,
341 name,
342 arguments,
343 type_,
344 field_map,
345 record_constructor,
346 } => Constant::Record {
347 location,
348 module,
349 name,
350 arguments: arguments.map(|arguments| {
351 arguments
352 .into_iter()
353 .map(
354 |CallArg {
355 label,
356 location,
357 value,
358 implicit,
359 }| CallArg {
360 label,
361 location,
362 value: self.constant(value),
363 implicit,
364 },
365 )
366 .collect()
367 }),
368 type_: self.type_(type_),
369 field_map,
370 record_constructor: record_constructor
371 .map(|constructor| Box::new(self.value_constructor(*constructor))),
372 },
373 Constant::RecordUpdate {
374 location,
375 constructor_location,
376 module,
377 name,
378 record:
379 RecordBeingUpdated {
380 base: record,
381 location: record_location,
382 },
383 arguments,
384 type_,
385 field_map,
386 } => Constant::RecordUpdate {
387 location,
388 constructor_location,
389 module,
390 name,
391 record: RecordBeingUpdated {
392 base: Box::new(self.constant(*record)),
393 location: record_location,
394 },
395 arguments: arguments
396 .into_iter()
397 .map(
398 |RecordUpdateArg {
399 label,
400 location,
401 value,
402 }| RecordUpdateArg {
403 label,
404 location,
405 value: self.constant(value),
406 },
407 )
408 .collect(),
409 type_: self.type_(type_),
410 field_map,
411 },
412 Constant::BitArray { location, segments } => Constant::BitArray {
413 location,
414 segments: segments
415 .into_iter()
416 .map(|segment| self.bit_array_segment(segment))
417 .collect(),
418 },
419 Constant::Var {
420 location,
421 module,
422 name,
423 constructor,
424 type_,
425 } => Constant::Var {
426 location,
427 module,
428 name,
429 constructor: constructor
430 .map(|constructor| Box::new(self.value_constructor(*constructor))),
431 type_: self.type_(type_),
432 },
433 Constant::StringConcatenation {
434 location,
435 left,
436 right,
437 } => Constant::StringConcatenation {
438 location,
439 left: Box::new(self.constant(*left)),
440 right: Box::new(self.constant(*right)),
441 },
442 Constant::Invalid {
443 location,
444 type_,
445 extra_information,
446 } => Constant::Invalid {
447 location,
448 type_: self.type_(type_),
449 extra_information,
450 },
451 Constant::Todo {
452 location,
453 type_,
454 message,
455 } => Constant::Todo {
456 location,
457 type_: self.type_(type_),
458 message: message.map(|message| Box::new(self.constant(*message))),
459 },
460 }
461 }
462
463 fn bit_array_segment(
464 &mut self,
465 segment: BitArraySegment<TypedConstant, Arc<Type>>,
466 ) -> BitArraySegment<TypedConstant, Arc<Type>> {
467 let BitArraySegment {
468 location,
469 value,
470 options,
471 type_,
472 } = segment;
473
474 let value = Box::new(self.constant(*value));
475 let options = options
476 .into_iter()
477 .map(|option| self.bit_array_option(option))
478 .collect();
479 let type_ = self.type_(type_);
480
481 BitArraySegment {
482 location,
483 value,
484 options,
485 type_,
486 }
487 }
488
489 fn bit_array_option(
490 &mut self,
491 option: BitArrayOption<TypedConstant>,
492 ) -> BitArrayOption<TypedConstant> {
493 match option {
494 BitArrayOption::Bytes { .. }
495 | BitArrayOption::Int { .. }
496 | BitArrayOption::Float { .. }
497 | BitArrayOption::Bits { .. }
498 | BitArrayOption::Utf8 { .. }
499 | BitArrayOption::Utf16 { .. }
500 | BitArrayOption::Utf32 { .. }
501 | BitArrayOption::Utf8Codepoint { .. }
502 | BitArrayOption::Utf16Codepoint { .. }
503 | BitArrayOption::Utf32Codepoint { .. }
504 | BitArrayOption::Signed { .. }
505 | BitArrayOption::Unsigned { .. }
506 | BitArrayOption::Big { .. }
507 | BitArrayOption::Little { .. }
508 | BitArrayOption::Native { .. }
509 | BitArrayOption::Unit { .. } => option,
510 BitArrayOption::Size {
511 location,
512 value,
513 short_form,
514 } => BitArrayOption::Size {
515 location,
516 value: Box::new(self.constant(*value)),
517 short_form,
518 },
519 }
520 }
521
522 fn accessors_map(&mut self, accessors: AccessorsMap) -> AccessorsMap {
523 let AccessorsMap {
524 publicity,
525 type_,
526 shared_accessors,
527 variant_specific_accessors,
528 variant_positional_accessors,
529 } = accessors;
530
531 let type_ = self.type_(type_);
532 let shared_accessors = shared_accessors
533 .into_iter()
534 .map(|(label, accessor)| (label, self.record_accessor(accessor)))
535 .collect();
536 let variant_specific_accessors = variant_specific_accessors
537 .into_iter()
538 .map(|variant_accessors| {
539 variant_accessors
540 .into_iter()
541 .map(|(label, accessor)| (label, self.record_accessor(accessor)))
542 .collect()
543 })
544 .collect();
545
546 let variant_positional_accessors = variant_positional_accessors
547 .into_iter()
548 .map(|variant_accessors| {
549 variant_accessors
550 .into_iter()
551 .map(|type_| self.type_(type_))
552 .collect()
553 })
554 .collect();
555
556 AccessorsMap {
557 publicity,
558 type_,
559 shared_accessors,
560 variant_specific_accessors,
561 variant_positional_accessors,
562 }
563 }
564
565 fn record_accessor(&mut self, accessor: RecordAccessor) -> RecordAccessor {
566 let RecordAccessor {
567 index,
568 label,
569 type_,
570 documentation,
571 } = accessor;
572 RecordAccessor {
573 index,
574 label,
575 type_: self.type_(type_),
576 documentation,
577 }
578 }
579
580 fn type_alias(&mut self, type_: TypeAliasConstructor) -> TypeAliasConstructor {
581 let TypeAliasConstructor {
582 publicity,
583 module,
584 type_,
585 arity,
586 deprecation,
587 documentation,
588 origin,
589 parameters,
590 } = type_;
591
592 let type_ = self.type_(type_);
593 let parameters = parameters
594 .into_iter()
595 .map(|parameter| self.type_(parameter))
596 .collect();
597
598 TypeAliasConstructor {
599 publicity,
600 module,
601 type_,
602 arity,
603 deprecation,
604 documentation,
605 origin,
606 parameters,
607 }
608 }
609
610 fn type_(&mut self, type_: Arc<Type>) -> Arc<Type> {
611 let type_ = match Arc::unwrap_or_clone(type_) {
612 Type::Named {
613 publicity,
614 package,
615 module,
616 name,
617 arguments,
618 inferred_variant,
619 } => Type::Named {
620 publicity,
621 package,
622 module,
623 name,
624 arguments: arguments
625 .into_iter()
626 .map(|argument| self.type_(argument))
627 .collect(),
628 inferred_variant,
629 },
630 Type::Fn { arguments, return_ } => Type::Fn {
631 arguments: arguments
632 .into_iter()
633 .map(|argument| self.type_(argument))
634 .collect(),
635 return_: self.type_(return_),
636 },
637 Type::Var { type_ } => return self.type_var(&type_.borrow()),
638
639 Type::Tuple { elements } => Type::Tuple {
640 elements: elements
641 .into_iter()
642 .map(|element| self.type_(element))
643 .collect(),
644 },
645 };
646 Arc::new(type_)
647 }
648
649 fn type_var(&mut self, variable: &TypeVar) -> Arc<Type> {
650 match variable {
651 TypeVar::Link { type_ } => self.type_(type_.clone()),
652 TypeVar::Unbound { id } => type_::prelude::unbound_var(self.id(*id)),
653 TypeVar::Generic { id } => type_::prelude::generic_var(self.id(*id)),
654 }
655 }
656
657 fn id(&mut self, id: u64) -> u64 {
658 match self.remapped_variable_ids.get(&id) {
659 Some(new_id) => *new_id,
660 None => {
661 let new_id = self.ids.next();
662 _ = self.remapped_variable_ids.insert(id, new_id);
663 new_id
664 }
665 }
666 }
667}