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

Configure Feed

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

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