Fork of daniellemaywood.uk/gleam — Wasm codegen work
1

Configure Feed

Select the types of activity you want to include in your feed.

gleam / compiler-core / src / metadata.rs
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}