Fork of daniellemaywood.uk/gleam — Wasm codegen work
20 kB
665 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 purity,
255 } => ValueConstructorVariant::ModuleFn {
256 name,
257 field_map,
258 module,
259 arity,
260 location,
261 documentation,
262 implementations,
263 external_erlang,
264 external_javascript,
265 purity,
266 },
267 ValueConstructorVariant::Record {
268 name,
269 arity,
270 field_map,
271 location,
272 module,
273 variants_count,
274 variant_index,
275 documentation,
276 } => ValueConstructorVariant::Record {
277 name,
278 arity,
279 field_map,
280 location,
281 module,
282 variants_count,
283 variant_index,
284 documentation,
285 },
286 }
287 }
288
289 fn constant(&mut self, constant: TypedConstant) -> TypedConstant {
290 match constant {
291 Constant::Int {
292 location,
293 value,
294 int_value,
295 } => Constant::Int {
296 location,
297 value,
298 int_value,
299 },
300 Constant::Float {
301 location,
302 value,
303 float_value,
304 } => Constant::Float {
305 location,
306 value,
307 float_value,
308 },
309 Constant::String { location, value } => Constant::String { location, value },
310 Constant::Tuple {
311 location,
312 elements,
313 type_,
314 } => Constant::Tuple {
315 location,
316 elements: elements
317 .into_iter()
318 .map(|element| self.constant(element))
319 .collect(),
320 type_: self.type_(type_),
321 },
322 Constant::List {
323 location,
324 elements,
325 type_,
326 tail,
327 } => Constant::List {
328 location,
329 elements: elements
330 .into_iter()
331 .map(|element| self.constant(element))
332 .collect(),
333 type_: self.type_(type_),
334 tail: tail.map(|tail| Box::new(self.constant(*tail))),
335 },
336 Constant::Record {
337 location,
338 module,
339 name,
340 arguments,
341 type_,
342 field_map,
343 record_constructor,
344 } => Constant::Record {
345 location,
346 module,
347 name,
348 arguments: arguments.map(|arguments| {
349 arguments
350 .into_iter()
351 .map(
352 |CallArg {
353 label,
354 location,
355 value,
356 implicit,
357 }| CallArg {
358 label,
359 location,
360 value: self.constant(value),
361 implicit,
362 },
363 )
364 .collect()
365 }),
366 type_: self.type_(type_),
367 field_map,
368 record_constructor: record_constructor
369 .map(|constructor| Box::new(self.value_constructor(*constructor))),
370 },
371 Constant::RecordUpdate {
372 location,
373 constructor_location,
374 module,
375 name,
376 record:
377 RecordBeingUpdated {
378 base: record,
379 location: record_location,
380 },
381 arguments,
382 type_,
383 field_map,
384 } => Constant::RecordUpdate {
385 location,
386 constructor_location,
387 module,
388 name,
389 record: RecordBeingUpdated {
390 base: Box::new(self.constant(*record)),
391 location: record_location,
392 },
393 arguments: arguments
394 .into_iter()
395 .map(
396 |RecordUpdateArg {
397 label,
398 location,
399 value,
400 }| RecordUpdateArg {
401 label,
402 location,
403 value: self.constant(value),
404 },
405 )
406 .collect(),
407 type_: self.type_(type_),
408 field_map,
409 },
410 Constant::BitArray { location, segments } => Constant::BitArray {
411 location,
412 segments: segments
413 .into_iter()
414 .map(|segment| self.bit_array_segment(segment))
415 .collect(),
416 },
417 Constant::Var {
418 location,
419 module,
420 name,
421 constructor,
422 type_,
423 } => Constant::Var {
424 location,
425 module,
426 name,
427 constructor: constructor
428 .map(|constructor| Box::new(self.value_constructor(*constructor))),
429 type_: self.type_(type_),
430 },
431 Constant::StringConcatenation {
432 location,
433 left,
434 right,
435 } => Constant::StringConcatenation {
436 location,
437 left: Box::new(self.constant(*left)),
438 right: Box::new(self.constant(*right)),
439 },
440 Constant::Invalid {
441 location,
442 type_,
443 extra_information,
444 } => Constant::Invalid {
445 location,
446 type_: self.type_(type_),
447 extra_information,
448 },
449 Constant::Todo {
450 location,
451 type_,
452 message,
453 } => Constant::Todo {
454 location,
455 type_: self.type_(type_),
456 message: message.map(|message| Box::new(self.constant(*message))),
457 },
458 }
459 }
460
461 fn bit_array_segment(
462 &mut self,
463 segment: BitArraySegment<TypedConstant, Arc<Type>>,
464 ) -> BitArraySegment<TypedConstant, Arc<Type>> {
465 let BitArraySegment {
466 location,
467 value,
468 options,
469 type_,
470 } = segment;
471
472 let value = Box::new(self.constant(*value));
473 let options = options
474 .into_iter()
475 .map(|option| self.bit_array_option(option))
476 .collect();
477 let type_ = self.type_(type_);
478
479 BitArraySegment {
480 location,
481 value,
482 options,
483 type_,
484 }
485 }
486
487 fn bit_array_option(
488 &mut self,
489 option: BitArrayOption<TypedConstant>,
490 ) -> BitArrayOption<TypedConstant> {
491 match option {
492 BitArrayOption::Bytes { .. }
493 | BitArrayOption::Int { .. }
494 | BitArrayOption::Float { .. }
495 | BitArrayOption::Bits { .. }
496 | BitArrayOption::Utf8 { .. }
497 | BitArrayOption::Utf16 { .. }
498 | BitArrayOption::Utf32 { .. }
499 | BitArrayOption::Utf8Codepoint { .. }
500 | BitArrayOption::Utf16Codepoint { .. }
501 | BitArrayOption::Utf32Codepoint { .. }
502 | BitArrayOption::Signed { .. }
503 | BitArrayOption::Unsigned { .. }
504 | BitArrayOption::Big { .. }
505 | BitArrayOption::Little { .. }
506 | BitArrayOption::Native { .. }
507 | BitArrayOption::Unit { .. } => option,
508 BitArrayOption::Size {
509 location,
510 value,
511 short_form,
512 } => BitArrayOption::Size {
513 location,
514 value: Box::new(self.constant(*value)),
515 short_form,
516 },
517 }
518 }
519
520 fn accessors_map(&mut self, accessors: AccessorsMap) -> AccessorsMap {
521 let AccessorsMap {
522 publicity,
523 type_,
524 shared_accessors,
525 variant_specific_accessors,
526 variant_positional_accessors,
527 } = accessors;
528
529 let type_ = self.type_(type_);
530 let shared_accessors = shared_accessors
531 .into_iter()
532 .map(|(label, accessor)| (label, self.record_accessor(accessor)))
533 .collect();
534 let variant_specific_accessors = variant_specific_accessors
535 .into_iter()
536 .map(|variant_accessors| {
537 variant_accessors
538 .into_iter()
539 .map(|(label, accessor)| (label, self.record_accessor(accessor)))
540 .collect()
541 })
542 .collect();
543
544 let variant_positional_accessors = variant_positional_accessors
545 .into_iter()
546 .map(|variant_accessors| {
547 variant_accessors
548 .into_iter()
549 .map(|type_| self.type_(type_))
550 .collect()
551 })
552 .collect();
553
554 AccessorsMap {
555 publicity,
556 type_,
557 shared_accessors,
558 variant_specific_accessors,
559 variant_positional_accessors,
560 }
561 }
562
563 fn record_accessor(&mut self, accessor: RecordAccessor) -> RecordAccessor {
564 let RecordAccessor {
565 index,
566 label,
567 type_,
568 documentation,
569 } = accessor;
570 RecordAccessor {
571 index,
572 label,
573 type_: self.type_(type_),
574 documentation,
575 }
576 }
577
578 fn type_alias(&mut self, type_: TypeAliasConstructor) -> TypeAliasConstructor {
579 let TypeAliasConstructor {
580 publicity,
581 module,
582 type_,
583 arity,
584 deprecation,
585 documentation,
586 origin,
587 parameters,
588 } = type_;
589
590 let type_ = self.type_(type_);
591 let parameters = parameters
592 .into_iter()
593 .map(|parameter| self.type_(parameter))
594 .collect();
595
596 TypeAliasConstructor {
597 publicity,
598 module,
599 type_,
600 arity,
601 deprecation,
602 documentation,
603 origin,
604 parameters,
605 }
606 }
607
608 fn type_(&mut self, type_: Arc<Type>) -> Arc<Type> {
609 let type_ = match Arc::unwrap_or_clone(type_) {
610 Type::Named {
611 publicity,
612 package,
613 module,
614 name,
615 arguments,
616 inferred_variant,
617 } => Type::Named {
618 publicity,
619 package,
620 module,
621 name,
622 arguments: arguments
623 .into_iter()
624 .map(|argument| self.type_(argument))
625 .collect(),
626 inferred_variant,
627 },
628 Type::Fn { arguments, return_ } => Type::Fn {
629 arguments: arguments
630 .into_iter()
631 .map(|argument| self.type_(argument))
632 .collect(),
633 return_: self.type_(return_),
634 },
635 Type::Var { type_ } => return self.type_var(&type_.borrow()),
636
637 Type::Tuple { elements } => Type::Tuple {
638 elements: elements
639 .into_iter()
640 .map(|element| self.type_(element))
641 .collect(),
642 },
643 };
644 Arc::new(type_)
645 }
646
647 fn type_var(&mut self, variable: &TypeVar) -> Arc<Type> {
648 match variable {
649 TypeVar::Link { type_ } => self.type_(type_.clone()),
650 TypeVar::Unbound { id } => type_::prelude::unbound_var(self.id(*id)),
651 TypeVar::Generic { id } => type_::prelude::generic_var(self.id(*id)),
652 }
653 }
654
655 fn id(&mut self, id: u64) -> u64 {
656 match self.remapped_variable_ids.get(&id) {
657 Some(new_id) => *new_id,
658 None => {
659 let new_id = self.ids.next();
660 _ = self.remapped_variable_ids.insert(id, new_id);
661 new_id
662 }
663 }
664 }
665}