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

Configure Feed

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

1// SPDX-License-Identifier: Apache-2.0 2// SPDX-FileCopyrightText: 2026 The Gleam contributors 3 4use ecow::EcoString; 5use itertools::Itertools; 6use num_bigint::BigInt; 7use num_traits::Zero; 8use regex::Regex; 9use std::sync::OnceLock; 10 11/// This is to raise an `unreachable` pretty printed error when we try producing 12/// some piece of code that is not allowed in the current position. 13macro_rules! invalid_code_for_position { 14 ($this:expr, $expected:literal) => { 15 unreachable!("{}", $this.error_with_position($expected)) 16 }; 17} 18 19/// This represent an erlang module name. 20/// Gleam modules use `/` as a separator, but when turned into erlang `@` is 21/// used as a separator instead. 22/// 23/// If we were to allow strings directly, a very common mistake to make would be 24/// to pass a Gleam module name to a function that's expecting an Erlang module 25/// name! 26/// 27/// With this those bugs cannot happen, and since this is a newtype wrapper its 28/// not adding any overhead over using plain strings. 29/// 30pub struct ErlangModuleName(EcoString); 31 32impl ErlangModuleName { 33 #[inline] 34 /// Creates a new erlang module name from a Gleam module name. 35 pub fn new(gleam_module_name: &str) -> Self { 36 Self(gleam_module_name.replace("/", "@").into()) 37 } 38} 39 40#[must_use] 41/// Represents an open function that has yet to be closed. 42/// A function definition is started with `ErlangBuilder::start_function` and 43/// _must_ be closed using `ErlangBuilder::end_function`. 44pub struct Function { 45 clauses: erlang_term_format::List, 46 statements: erlang_term_format::List, 47} 48 49#[must_use] 50/// Represents an open function call that has yet to be closed. 51pub struct Call { 52 arguments: erlang_term_format::List, 53} 54 55#[must_use] 56/// Represents an open case expression that has yet to be closed. 57pub struct Case { 58 branches: erlang_term_format::List, 59} 60 61#[must_use] 62/// Represents an open case clause pattern that has yet to be generated. 63pub struct ClausePattern { 64 pattern: erlang_term_format::List, 65 guards: erlang_term_format::List, 66 body: erlang_term_format::List, 67} 68 69#[must_use] 70/// Represents a set of clause guards that has yet to be closed. 71pub struct ClauseGuards { 72 guards: erlang_term_format::List, 73 body: erlang_term_format::List, 74} 75 76#[must_use] 77/// Represents an open clause body that has yet to be closed. 78pub struct ClauseBody { 79 body: erlang_term_format::List, 80} 81 82#[must_use] 83/// Represents an open tuple that has yet to be closed. 84pub struct Tuple { 85 items: erlang_term_format::List, 86} 87 88#[must_use] 89/// Represents an open map that has yet to be closed. 90pub struct Map { 91 items: erlang_term_format::List, 92} 93 94#[must_use] 95/// Represents an open bit array that has yet to be closed. 96pub struct BitArray { 97 segments: erlang_term_format::List, 98} 99 100#[must_use] 101/// Represents an open bit array pattern that has yet to be closed. 102pub struct BitArrayPattern { 103 segments: erlang_term_format::List, 104} 105 106#[must_use] 107/// Represents an open tuple type that has yet to be closed. 108pub struct TupleType { 109 items: erlang_term_format::List, 110} 111 112#[must_use] 113/// Represents an open tuple pattern that has yet to be closed. 114pub struct TuplePattern { 115 items: erlang_term_format::List, 116} 117 118#[must_use] 119/// Represents an open doc/moduledoc attribute. 120pub struct DocAttribute { 121 items: erlang_term_format::List, 122} 123 124#[must_use] 125/// Represents an open record attribute. 126pub struct RecordAttribute { 127 fields: erlang_term_format::List, 128} 129 130#[must_use] 131/// Represents an open function type annotation that has yet to be closed after 132/// generating the arguments types and the return type. 133pub struct FunctionType { 134 types: erlang_term_format::List, 135} 136 137#[must_use] 138/// Represents an open named type that has yet to be closed after generating 139/// the types it takes as an argument (if any). 140pub struct NamedType { 141 types: erlang_term_format::List, 142} 143 144#[must_use] 145/// Represents an open alternative type that has yet to be closed after 146/// generating all of its alternatives. 147pub struct UnionType { 148 alternatives: erlang_term_format::List, 149} 150 151#[must_use] 152/// Represents an open function type annotation that has yet to be closed after 153/// generating the arguments types and the return type. 154pub struct FunctionSpec { 155 representations: erlang_term_format::List, 156} 157 158#[must_use] 159/// Represents an open block that has yet to be closed after generating the 160/// statements that go inside it. 161pub struct Block { 162 statements: erlang_term_format::List, 163} 164 165#[must_use] 166/// Represents an open list of arguments' types in a function type annotation 167/// that has yet to be closed. 168pub struct FunctionTypeArguments { 169 types: erlang_term_format::List, 170 arguments: erlang_term_format::List, 171} 172 173/// All the possible specifiers that can be used in a bit array segment. 174pub enum BitArraySegmentSpecifier { 175 Utf8, 176 Utf16, 177 Utf32, 178 Integer, 179 Float, 180 Binary, 181 Bitstring, 182 Signed, 183 Unsigned, 184 Little, 185 Big, 186 Native, 187 Unit(u8), 188} 189 190/// A trait defining operations to describe the content of an Erlang module. 191/// 192/// This might look strange in places, for example why is there a `start_tuple` 193/// and `end_tuple` function, but lists are built using `cons_list` and not a 194/// `start_list` and `end_list` function? 195/// 196/// That's because this API has been made primarily to be able to generate 197/// the Erlang Abstract Format data structure. All the methods almost map 1:1 198/// to how Erlang constructs are represented in that format. 199/// 200/// You might want to keep a reference to it open as you go over this module, 201/// it's gonna be handy: 202/// https://www.erlang.org/doc/apps/erts/absform.html 203/// 204pub trait ErlangBuilder<Output> { 205 /// Creates a new `ErlangBuilder` data structure to generate Erlang code. 206 /// If a module name is provided this will also automatically take care of 207 /// generating the appropriate `-module` annotation at the very beginning. 208 /// 209 /// It's optional because it might not always be needed. For example when 210 /// producing `-record` annotations there's no need to have a module name. 211 /// 212 fn new(module_name: Option<ErlangModuleName>) -> Self; 213 214 /// Consumes the given `ErlangBuilder` turning it into some other 215 /// representation. 216 /// For example that might be a binary representation, or a textual pretty 217 /// printed one. 218 /// 219 fn into_output(self) -> Output; 220 221 /// Adds to the module an export attribute for the given exported functions. 222 /// 223 /// For example: 224 /// 225 /// ```ignore 226 /// builder.export_attribute(vec![("wibble", 1), ("wobble", 2)]); 227 /// ``` 228 /// 229 /// Corresponds to: 230 /// 231 /// ```erl 232 /// -export([wibble/1, wobble/2]). 233 /// ``` 234 /// 235 fn export_attribute<Name: AsRef<str>>( 236 &mut self, 237 exported: impl IntoIterator<Item = (Name, usize)>, 238 ); 239 240 /// Adds to the module an export_type attribute for the given exported types. 241 /// 242 /// For example: 243 /// 244 /// ```ignore 245 /// builder.export_attribute(vec![("wibble", 1), ("wobble", 2)]); 246 /// ``` 247 /// 248 /// Corresponds to: 249 /// 250 /// ```erl 251 /// -export_type([wibble/1, wobble/2]). 252 /// ``` 253 /// 254 fn export_type_attribute<Name: AsRef<str>>( 255 &mut self, 256 exported: impl IntoIterator<Item = (Name, usize)>, 257 ); 258 259 /// Starts a `-doc` attribute. 260 /// What is generated after calling this function will end up inside the 261 /// `-doc` attribute. 262 /// You'll most likely always put a string or the atom "false" inside it. 263 /// 264 /// For example: 265 /// 266 /// ```ignore 267 /// let doc = builder.start_doc_attribute(); 268 /// builder.atom("false"); 269 /// builder.close_doc_attribute(doc); 270 /// ``` 271 /// 272 /// Corresponds to: 273 /// 274 /// ```erl 275 /// -doc(false). 276 /// ``` 277 /// 278 fn start_doc_attribute(&mut self) -> DocAttribute; 279 280 /// Starts a `-moduledoc` attribute. 281 /// What is generated after calling this function will end up inside the 282 /// `-moduledoc` attribute. 283 /// You'll most likely always put a string or the atom "false" inside it. 284 /// 285 /// For example: 286 /// 287 /// ```ignore 288 /// let doc = builder.start_moduledoc_attribute(); 289 /// builder.atom("false"); 290 /// builder.close_doc_attribute(doc); 291 /// ``` 292 /// 293 /// Corresponds to: 294 /// 295 /// ```erl 296 /// -moduledoc(false). 297 /// ``` 298 /// 299 fn start_moduledoc_attribute(&mut self) -> DocAttribute; 300 301 /// This closes the currently open doc/moduledoc attribute. 302 /// Code generated after this is not gonna be part of it. 303 /// 304 fn end_doc_attribute(&mut self, attribute: DocAttribute); 305 306 /// This generates the code for a `-compile([]).` attribute where all the 307 /// strings produces by the given iterator are going to be passed as atom 308 /// literals. 309 /// 310 /// For example: 311 /// 312 /// ```ignore 313 /// builder.compile_attribute(vec!["no_warn", "inline"]); 314 /// ``` 315 /// 316 /// Corresponds to: 317 /// 318 /// ```erl 319 /// -compile([no_warn, inline]). 320 /// ``` 321 /// 322 fn compile_attribute<'a>(&mut self, arguments: impl IntoIterator<Item = &'a str>); 323 324 /// This generates a `-file` attribute. 325 /// For example: 326 /// 327 /// ```ignore 328 /// builder.file_attribute("wibble.gleam", 2.into()); 329 /// ``` 330 /// 331 /// Correspods to: 332 /// 333 /// ```erl 334 /// -file("wibble.gleam", 2) 335 /// ``` 336 /// 337 fn file_attribute(&mut self, file: &str, line: u32); 338 339 /// Starts a `-record` attribute. 340 /// After this you're supposed to generate a sequence of `record_field`, and 341 /// once you're done you should end it with `edn_record_attribute`. 342 /// 343 /// For example: 344 /// 345 /// ```ignore 346 /// let record = builder.start_record_attribute("wobble"); 347 /// builder.record_field(); 348 /// builder.atom("wibble"); 349 /// builder.literal_atom_type("ok"); 350 /// builder.close_record_attribute(record); 351 /// ``` 352 /// 353 /// Corresponds to: 354 /// 355 /// ```erl 356 /// -record(wobble, { wibble :: ok }). 357 /// ``` 358 /// 359 fn start_record_attribute(&mut self, record_name: &str) -> RecordAttribute; 360 361 /// This closes the currently open record attribute. 362 /// Code generated after this is not gonna be part of it. 363 /// 364 fn end_record_attribute(&mut self, record: RecordAttribute); 365 366 /// This creates a record field inside a record attribute. 367 /// After this you're supposed to generate two things: 368 /// - an atom representing the name of the field 369 /// - a type representing the type of the field 370 /// 371 /// For an example on how to use this you can check the 372 /// `start_record_attribute` docs. 373 fn record_field(&mut self); 374 375 /// This starts a function type spec. 376 /// Everything that is generated after this call is interpreted as the 377 /// annotated type of the function. So this should be followed by a single 378 /// function type. 379 /// 380 /// After that is complete, this has to be closed using `end_function_spec`. 381 /// 382 /// For example: 383 /// 384 /// ```ignore 385 /// let spec = builder.start_function_spec("wibble", 1) 386 /// let function_type = builder.start_function_type(); 387 /// builder.int_type(); 388 /// let function_type builder.end_function_type_arguments(function_type); 389 /// builder.variable_type("A"); 390 /// builder.end_function_type(function_type); 391 /// ``` 392 /// 393 /// Corresponds to: 394 /// 395 /// ```erl 396 /// -spec wibble(integer(), A) -> A. 397 /// ``` 398 /// 399 fn start_function_spec(&mut self, name: &str, arity: usize) -> FunctionSpec; 400 401 /// This closes the currently open function spec. 402 /// Code generated after this is not gonna be part of this function spec. 403 /// 404 fn end_function_spec(&mut self, function_spec: FunctionSpec); 405 406 /// This starts an Erlang type spec. 407 /// After this call you're expected to generate a single type; that's going 408 /// to be the definition of the type. 409 /// 410 /// For example: 411 /// 412 /// ```ignore 413 /// let spec = builder.start_type_spec(false, "wibble", ["A"]); 414 /// 415 /// let union = builder.start_union_type(); 416 /// builder.literal_atom_type("nil"); 417 /// 418 /// let list = builder.start_named_type("list"); 419 /// builder.type_variable("A") 420 /// builder.close_named_type(); 421 /// 422 /// builder.end_uniont_type(union); 423 /// ``` 424 /// 425 /// Corresponds to: 426 /// 427 /// ```erl 428 /// -spec wibble(A) :: nil | list(A). 429 /// ``` 430 /// 431 fn type_spec<Name: AsRef<str>>( 432 &mut self, 433 opaque: bool, 434 name: &str, 435 type_parameters: impl IntoIterator<Item = Name>, 436 ); 437 438 /// This starts a function type. 439 /// Any code generated after this is gonna be an argument type of the open 440 /// function type until `end_function_type_arguments` is called. 441 /// After that you should generate a single type that's gonna be the return 442 /// type, and then end the function. 443 /// 444 /// For example: 445 /// 446 /// ```ignore 447 /// let function_type = builder.start_function_type(); 448 /// builder.int_type(); 449 /// builder.variable_type("A"); 450 /// let function_type builder.end_function_type_arguments(function_type); 451 /// builder.variable_type("A"); 452 /// builder.end_function_type(function_type); 453 /// ``` 454 /// 455 /// Corresponds to: 456 /// 457 /// ```erl 458 /// (integer(), A) -> A. 459 /// ``` 460 /// 461 fn start_function_type(&mut self) -> FunctionTypeArguments; 462 463 /// This closes the currently open function type arguments list. 464 /// This means that the next type that is generated is going to be the 465 /// return type of the open function type. 466 /// 467 /// After that you should call `end_function_type` to close the function 468 /// type. 469 /// 470 fn end_function_type_arguments(&mut self, function_type: FunctionTypeArguments) 471 -> FunctionType; 472 473 /// This takes a function type and closes it. 474 /// Code generated after this is not gonna be part of this function type. 475 /// 476 fn end_function_type(&mut self, function_type: FunctionType); 477 478 /// This starts a named type (either defined previously in this module, or 479 /// a built-in Erlang type) with the given name. 480 /// Any code generated after this is gonna be an argument of the open 481 /// named type type until `end_named_type` is called. 482 /// 483 /// For example: 484 /// 485 /// ```ignore 486 /// let integer = builder.start_named_type("integer"); 487 /// builder.end_named_type(integer); 488 /// ``` 489 /// 490 /// Corresponds to: 491 /// 492 /// ```erl 493 /// integer(). 494 /// ``` 495 /// 496 fn start_named_type(&mut self, name: &str) -> NamedType; 497 498 /// This starts a remote named type with the given module and name. 499 /// Any code generated after this is gonna be an argument of the open 500 /// named type type until `end_named_type` is called. 501 /// 502 /// For example: 503 /// 504 /// ```ignore 505 /// let type_ = builder.start_remote_named_type("wibble", "wobble"); 506 /// builder.end_named_type(type_); 507 /// ``` 508 /// 509 /// Corresponds to: 510 /// 511 /// ```erl 512 /// wibble:wobble(). 513 /// ``` 514 /// 515 fn start_remote_named_type(&mut self, module: ErlangModuleName, name: &str) -> NamedType; 516 517 /// This takes a named type and closes it. 518 /// Code generated after this is not gonna be part of this named type. 519 /// 520 fn end_named_type(&mut self, named_type: NamedType); 521 522 /// This starts a tuple type. 523 /// Any code generated after this is gonna be one of the tuple items. 524 /// 525 /// For example: 526 /// 527 /// ```ignore 528 /// let tuple = builder.start_tuple_type(); 529 /// builder.literal_atom_type("nil"); 530 /// builder.literal_atom_type("ok"); 531 /// builder.end_tuple_type(tuple); 532 /// ``` 533 /// 534 /// Corresponds to the following Erlang type: 535 /// 536 /// ```erl 537 /// {nil, ok}. 538 /// ``` 539 /// 540 fn start_tuple_type(&mut self) -> TupleType; 541 542 /// This takes a tuple type and closes it. 543 /// Code generated after this is not gonna be part of this tuple type. 544 /// 545 fn end_tuple_type(&mut self, tuple: TupleType); 546 547 /// This starts a union type. 548 /// Any code generated after this is gonna be a possible alternative of this 549 /// type. 550 /// 551 /// For example: 552 /// 553 /// ```ignore 554 /// let ok_or_error = builder.start_union_type(); 555 /// builder.literal_atom_type("ok"); 556 /// builder.literal_atom_type("error"); 557 /// builder.end_union_type(ok_or_error); 558 /// ``` 559 /// 560 /// Corresponds to: 561 /// 562 /// ```erl 563 /// ok | error. 564 /// ``` 565 /// 566 fn start_union_type(&mut self) -> UnionType; 567 568 /// This takes a union type and closes it. 569 /// Code generated after this is not gonna be part of this union type. 570 /// 571 fn end_union_type(&mut self, union_type: UnionType); 572 573 /// This generated the code for a type variable with the given name. 574 /// 575 /// For example, if we were to define the type of the identity function we 576 /// could do it like this: 577 /// 578 /// ```ignore 579 /// let function = builder.start_function_type(); 580 /// builder.type_variable("A"); 581 /// let function = builder.end_function_type_arguments(); 582 /// builder.type_variable("A"); 583 /// builder.end_function(function); 584 /// ``` 585 /// 586 /// And it corresponds to: 587 /// 588 /// ```erl 589 /// (A) -> A. 590 /// ``` 591 /// 592 fn type_variable(&mut self, name: &str); 593 594 /// This generated the code for a literal atom type. 595 /// 596 /// For example, the annotation of a function returning the atom `nil` is 597 /// be defined like this: 598 /// 599 /// ```ignore 600 /// let function = builder.start_function_type(); 601 /// let function = builder.end_function_type_arguments(); 602 /// builder.literal_atom_type("nil"); 603 /// builder.end_function(function); 604 /// ``` 605 /// 606 /// And it corresponds to: 607 /// 608 /// ```erl 609 /// % type of a function returning nil! 610 /// () -> nil. 611 /// ``` 612 /// 613 fn literal_atom_type(&mut self, name: &str); 614 615 /// This starts a module function definition. 616 /// Any code generated after this is gonna be a statement of the open 617 /// function until `end_function` is called. 618 /// 619 /// For example: 620 /// 621 /// ```ignore 622 /// let function = builder.start_function("first_name", 0, vec![]); 623 /// builder.string("Giacomo"); 624 /// builder.end_function(function); 625 /// ``` 626 /// 627 /// Corresponds to: 628 /// 629 /// ```erl 630 /// first_name() -> ~"Giacomo". 631 /// ``` 632 /// 633 fn start_function<Name: AsRef<str>>( 634 &mut self, 635 name: &str, 636 arity: usize, 637 arguments_names: impl IntoIterator<Item = Name>, 638 ) -> Function; 639 640 /// This starts an expression defining an anonymous function. 641 /// Any code generated after this is gonna be a statement inside the 642 /// anonymous function's body until `end_anonymous_function` is called. 643 /// 644 /// For example: 645 /// 646 /// ```ignore 647 /// let function = builder.start_anonymous_function([]); 648 /// builder.string("Erlang rocks"); 649 /// builder.end_anonymous_function(function); 650 /// ``` 651 /// 652 /// Corresponds to: 653 /// 654 /// ```erl 655 /// fun() -> ~"Erlang rocks" end. 656 /// ``` 657 /// 658 fn start_anonymous_function<Name: AsRef<str>>( 659 &mut self, 660 arguments_names: impl IntoIterator<Item = Name>, 661 ) -> Function; 662 663 /// This takes a function and closes it. 664 /// Code generated after this is not gonna be part of this function. 665 /// 666 fn end_function(&mut self, function: Function); 667 668 /// This starts a block expression. 669 /// Any code generated after this is gonna be a statement inside the open 670 /// block. 671 /// 672 /// For example: 673 /// 674 /// ```ignore 675 /// let block = builder.start_block(); 676 /// builder.string("Giacomo"); 677 /// builder.int(1); 678 /// builder.end_block(block); 679 /// ``` 680 /// 681 /// Corresponds to: 682 /// 683 /// ```erl 684 /// begin 685 /// ~"Giacomo", 686 /// 1 687 /// end. 688 /// ``` 689 /// 690 fn start_block(&mut self) -> Block; 691 692 /// This takes a block and closes it. 693 /// Code generated after this is not gonna be part of this block. 694 /// 695 fn end_block(&mut self, block: Block); 696 697 /// This starts a remote call. 698 /// Any code generated after this is gonna be an argument of the open 699 /// function call `end_call` is called. 700 /// 701 /// For example: 702 /// 703 /// ```ignore 704 /// let call = builder.start_remote_call("io", "format"); 705 /// builder.string("Giacomo"); 706 /// builder.end_call(call); 707 /// ``` 708 /// 709 /// Corresponds to: 710 /// 711 /// ```erl 712 /// io:format(~"Giacomo"). 713 /// ``` 714 /// 715 fn start_remote_call(&mut self, module: ErlangModuleName, function: &str) -> Call; 716 717 /// This starts a function call. 718 /// The expression generated immediately after this is going to be the thing 719 /// that is called, followed by its arguments. 720 /// 721 /// For example: 722 /// 723 /// ```ignore 724 /// let call = builder.start_call(); 725 /// builder.atom("wibble") 726 /// builder.string("Hello"); 727 /// builder.string("Giacomo"); 728 /// builder.end_call(call); 729 /// ``` 730 /// 731 /// Corresponds to: 732 /// 733 /// ```erl 734 /// wibble(~"Hello", ~"Giacomo"). 735 /// ``` 736 /// 737 fn start_call(&mut self) -> Call; 738 739 /// This takes an open call and closes it. 740 /// Code generated after this is not gonna be an argument to this call. 741 /// 742 fn end_call(&mut self, call: Call); 743 744 /// This starts a tuple. 745 /// Any code generated after this is gonna be an item of the tuple. 746 /// 747 /// For example: 748 /// 749 /// ```ignore 750 /// let tuple = builder.start_tuple(); 751 /// builder.string("Hello"); 752 /// builder.int(1); 753 /// builder.end_tuple(tuple); 754 /// ``` 755 /// 756 /// Corresponds to: 757 /// 758 /// ```erl 759 /// { ~"Hello", 1 }. 760 /// ``` 761 /// 762 fn start_tuple(&mut self) -> Tuple; 763 764 /// This takes an open tuple and closes it. 765 /// Code generated after this is not gonna be an item of the tuple. 766 /// 767 fn end_tuple(&mut self, tuple: Tuple); 768 769 /// This starts an Erlang map. 770 /// After this call you can add fields to the map using the `map_field` 771 /// function. 772 /// 773 /// For example: 774 /// 775 /// ```ignore 776 /// let map = builder.start_map(); 777 /// 778 /// builder.map_field(); 779 /// builder.atom("gleam_error") 780 /// builder.atom("todo"); 781 /// 782 /// builder.map_field(); 783 /// builder.atom("line"); 784 /// builder.int(6.into()); 785 /// ``` 786 /// 787 /// Corresponds to: 788 /// 789 /// ```erl 790 /// #{ 791 /// gleam_error => todo, 792 /// line => 6 793 /// }. 794 /// ``` 795 /// 796 fn start_map(&mut self) -> Map; 797 798 /// This takes an open map and closes it. 799 /// Code generated after this is not gonna be a map field. 800 /// 801 fn end_map(&mut self, map: Map); 802 803 /// This is used to add new fields to an open map. 804 /// After calling this you must generate exactly two values: the first one 805 /// is going to be the key, while the second one is going to be the 806 /// associated value. 807 fn map_field(&mut self); 808 809 /// This starts an Erlang bitstring (that's a Gleam's BitArray). 810 /// Any code generated after this is gonna be a segment of the bitstring. 811 /// 812 /// For example: 813 /// 814 /// ```ignore 815 /// let bit_array = builder.start_bit_array(); 816 /// 817 /// builder.bit_array_segment(); 818 /// builder.int(1); 819 /// builder.atom("default"); 820 /// builder.atom("default"); 821 /// 822 /// builder.bit_array_segment(); 823 /// builder.string("hello"); 824 /// builder.atom("deafult"); 825 /// builder.atom("default"); 826 /// 827 /// builder.end_bit_array(bit_array); 828 /// ``` 829 /// 830 /// Corresponds to: 831 /// 832 /// ```erl 833 /// <<1, ~"hello">>. 834 /// ``` 835 /// 836 fn start_bit_array(&mut self) -> BitArray; 837 838 /// This takes an open bit array and closes it. 839 /// Code generated after this is not gonna be a segment of the bit array. 840 /// 841 fn end_bit_array(&mut self, bit_array: BitArray); 842 843 /// This starts a new bit array segment. Make sure to call it after 844 /// `start_bit_array`! 845 /// Bit array segments are a bit tricky, after calling this you're supposed 846 /// to generate three distinct bits in the following order: 847 /// 848 /// 1. The expression representing the bit array segment 849 /// 2. The expression representing the segment size (or the atom `default` 850 /// if you want to use... you guessed it, the default) 851 /// 3. A list of type specifiers (those are atoms like `utf8`, `binary`, 852 /// ...) or the atom `default` if you're ok with Erlang's default value, 853 /// those are generated using the `bit_array_segment_specifiers` function. 854 /// 855 /// After generating those three bits the segment is automatically over and 856 /// you can go on to the next one! 857 /// 858 /// If this API seems a bit tricky and easy to get wrong, it is! But this is 859 /// a low level API based on the shape of the Erlang Abstract Format itself, 860 /// we don't make the rules. 861 /// 862 /// If you wanna check an example of how this is used you can have a read at 863 /// the ones in `start_bit_array`. 864 fn bit_array_segment(&mut self); 865 866 /// This generates a specifiers list for the currently open bit array 867 /// segment. 868 /// You always have to call this function, even if the segment has no 869 /// specifiers; in that case you can pass this an empty list and the 870 /// Erlang's default will be applied. 871 /// 872 fn bit_array_segment_specifiers( 873 &mut self, 874 specifiers: impl IntoIterator<Item = BitArraySegmentSpecifier>, 875 ); 876 877 /// This creates a list. 878 /// The next two generated values are going to be respectively the first 879 /// item and the tail of the list. 880 /// 881 /// For example: 882 /// 883 /// ```ignore 884 /// builder.cons_list(); 885 /// builder.variable("Hello"); 886 /// builder.cons_list(); 887 /// builder.string("Giacomo"); 888 /// builder.empty_list(); 889 /// ``` 890 /// 891 /// Corresponds to: 892 /// 893 /// ```erl 894 /// [Hello | [ ~"Giacomo" | []]]. 895 /// % Which, with some syntax sugar, is how we represent a list with two 896 /// % elements: 897 /// % [Hello, ~"Giacomo"] 898 /// ``` 899 /// 900 fn cons_list(&mut self); 901 902 /// This creates an empty list. 903 /// 904 fn empty_list(&mut self); 905 906 /// This starts a new case expression. 907 /// After this function is called you're supposed to first generate a single 908 /// expression; that's going to be the case subject being matched on. 909 /// 910 /// After that you're supposed to generate the case branches using the 911 /// `start_case_clause` function. 912 /// 913 /// For example: 914 /// 915 /// ```ignore 916 /// let case = builder.start_case(); 917 /// builder.variable("wibble"); 918 /// 919 /// let clause = builder.start_case_clause(); 920 /// builder.discard_pattern(); 921 /// let clause = builder.end_clause_pattern(); 922 /// let clause = builder.end_clause_guards(); 923 /// builder.int(1.into()); 924 /// builder.end_clause_body(); 925 /// 926 /// builder.end_case(case); 927 /// ``` 928 /// 929 /// Corresponds to: 930 /// 931 /// ```erl 932 /// case Wibble of 933 /// _ -> 1 934 /// end. 935 /// ``` 936 /// 937 fn start_case(&mut self) -> Case; 938 939 /// This ends an open case expression. 940 /// Any code generated after this is not going to be part of it. 941 /// 942 fn end_case(&mut self, case: Case); 943 944 /// This starts a new case clause inside a case expression. 945 /// After this is called you must generate a single pattern and then call 946 /// `end_clause_pattern`. 947 /// 948 /// For an example on how to generate a full case clause check the 949 /// `start_case` documentation. 950 fn start_case_clause(&mut self) -> ClausePattern; 951 952 /// This ends the case clause's pattern. After this you should generate the 953 /// clause guards and then call `end_clause_guards`. 954 /// If the clause you're generating has no guards you can immediately call 955 /// that function without generating anything inbetween. 956 fn end_clause_pattern(&mut self, clause_pattern: ClausePattern) -> ClauseGuards; 957 958 /// This ends the case clause's guards. Anything that is generated after 959 /// this is going to be a statement inside the current case clause until 960 /// `end_clause_body` is called. 961 fn end_clause_guards(&mut self, clause_guards: ClauseGuards) -> ClauseBody; 962 963 /// This takes an open clause body and ends it. 964 /// After this you can start generating new case clauses, or end the 965 /// currently open case expression if this was the last clause! 966 fn end_clause_body(&mut self, clause_body: ClauseBody); 967 968 /// This creates a variable expression with the given name. 969 /// For example: 970 /// 971 /// ```erl 972 /// wibble(X) -> X. 973 /// % ^ This here! 974 /// ``` 975 /// 976 fn variable(&mut self, name: &str); 977 978 /// This generated the code that is going to apply the given unary operator 979 /// to the expression that is going to be generated next. 980 /// For example: 981 /// 982 /// ```ignore 983 /// builder.unary_operator("-"); 984 /// builder.variable("X"); 985 /// ``` 986 /// 987 /// Corresponds to: 988 /// 989 /// ```erl 990 /// -X. 991 /// ``` 992 /// 993 fn unary_operator(&mut self, operator: &str); 994 995 /// This generated the code that is going to apply the given binary operator 996 /// to the two expressions generated after it. 997 /// For example: 998 /// 999 /// ```ignore 1000 /// builder.binary_operator("+"); 1001 /// builder.variable("X"); 1002 /// builder.int(1); 1003 /// ``` 1004 /// 1005 /// Corresponds to: 1006 /// 1007 /// ```erl 1008 /// X + 1. 1009 /// ``` 1010 /// 1011 fn binary_operator(&mut self, operator: &'static str); 1012 1013 /// This generates the code for a function reference. 1014 /// For example: 1015 /// 1016 /// ```ignore 1017 /// builder.function_reference(None, "wibble", 1); 1018 /// builder.function_reference(Some("io"), "format", 2); 1019 /// ``` 1020 /// 1021 /// Correspond to: 1022 /// 1023 /// ```erl 1024 /// fun wibble/1, 1025 /// fun io:format/2. 1026 /// ``` 1027 /// 1028 fn function_reference(&mut self, module: Option<ErlangModuleName>, name: &str, arity: usize); 1029 1030 /// This is used to create the code that corresponds to an assignment. 1031 /// A call to this function should always be followed by the generation of 1032 /// a pattern (the left-hand side of the assignment), and of an expression 1033 /// (the right-hand side of the assignment). 1034 /// 1035 /// For example: 1036 /// 1037 /// ```ignore 1038 /// builder.match_operator(); 1039 /// builder.variable_pattern("X"); 1040 /// builder.int(1); 1041 /// ``` 1042 /// 1043 /// Corresponds to: 1044 /// 1045 /// ```erl 1046 /// X = 1. 1047 /// ``` 1048 /// 1049 fn match_operator(&mut self); 1050 1051 /// This is used to create the code that corresponds to a match pattern. 1052 /// A call to this function should always be followed by the generation of 1053 /// a pattern (the left-hand side of the assignment), and of another pattern 1054 /// (the right-hand side of the assignment). 1055 /// 1056 /// For example: 1057 /// 1058 /// ```ignore 1059 /// builder.match_pattern(); 1060 /// builder.int_pattern(1); 1061 /// builder.variable_pattern("X"); 1062 /// ``` 1063 /// 1064 /// Corresponds to: 1065 /// 1066 /// ```erl 1067 /// 1 = X. 1068 /// ``` 1069 /// 1070 /// You could use this to compare equality of arbitrary complex patterns: 1071 /// `{1, A, [_, _]} = {X, Y, [A | _]}` however you'll most likely ever need 1072 /// this only when generating code for Gleam's "as" patterns where the right 1073 /// hand side is just a variable pattern. 1074 /// 1075 fn match_pattern(&mut self); 1076 1077 /// This creates a variable pattern with the given name. 1078 /// For example: 1079 /// 1080 /// ```erl 1081 /// wibble() -> 1082 /// X = 1. 1083 /// % ^ This here! 1084 /// ``` 1085 /// 1086 fn variable_pattern(&mut self, name: &str); 1087 1088 /// This creates a discard pattern. 1089 /// For example: 1090 /// 1091 /// ```erl 1092 /// wibble() -> 1093 /// _ = 1. 1094 /// % ^ This here! 1095 /// ``` 1096 /// 1097 fn discard_pattern(&mut self); 1098 1099 /// This creates an integer pattern. 1100 /// For example: 1101 /// 1102 /// ```erl 1103 /// wibble() -> 1104 /// 1 = X. 1105 /// % ^ This here! 1106 /// ``` 1107 /// 1108 fn int_pattern(&mut self, number: BigInt); 1109 1110 /// This creates an integer pattern. 1111 /// For example: 1112 /// 1113 /// ```erl 1114 /// wibble() -> 1115 /// 1 = X. 1116 /// % ^ This here! 1117 /// ``` 1118 /// 1119 fn float_pattern(&mut self, number: f64); 1120 1121 /// This creates a string pattern. 1122 /// For example: 1123 /// 1124 /// ```erl 1125 /// wibble() -> 1126 /// <<"Hello"/utf8>> = X. 1127 /// % ^^^^^^^^^^^^^^^^ This here! 1128 /// ``` 1129 /// 1130 fn string_pattern(&mut self, content: &str); 1131 1132 /// This creates an atom pattern. 1133 /// For example: 1134 /// 1135 /// ```erl 1136 /// wibble() -> 1137 /// ok = X. 1138 /// % ^^ This here! 1139 /// ``` 1140 /// 1141 fn atom_pattern(&mut self, name: &str); 1142 1143 /// This starts a tuple pattern. 1144 /// Any code generated after this is gonna be an item of the tuple pattern. 1145 /// 1146 /// For example: 1147 /// 1148 /// ```ignore 1149 /// let tuple = builder.start_tuple_pattern(); 1150 /// builder.int_pattern(1); 1151 /// builder.discard_pattern(); 1152 /// builder.end_tuple(tuple); 1153 /// ``` 1154 /// 1155 /// Corresponds to the following pattern: 1156 /// 1157 /// ```erl 1158 /// {~"Hello", _}. 1159 /// ``` 1160 /// 1161 fn start_tuple_pattern(&mut self) -> TuplePattern; 1162 1163 /// This takes an open tuple pattern and closes it. 1164 /// Any code generated after this is not gonna be part of that pattern. 1165 fn end_tuple_pattern(&mut self, tuple: TuplePattern); 1166 1167 /// This starts an Erlang bitstring (that's a Gleam's BitArray) pattern. 1168 /// Any code generated after this is gonna be a segment of the pattern. 1169 /// 1170 /// For example: 1171 /// 1172 /// ```ignore 1173 /// let bit_array = builder.start_bit_array_pattern(); 1174 /// 1175 /// builder.bit_array_pattern_segment(); 1176 /// builder.int_pattern(1); 1177 /// builder.atom("default"); 1178 /// builder.atom("default"); 1179 /// 1180 /// builder.bit_array_pattern_segment(); 1181 /// builder.discard_pattern(); 1182 /// builder.atom("deafult"); 1183 /// builder.atom("default"); 1184 /// 1185 /// builder.end_bit_array_pattern(bit_array); 1186 /// ``` 1187 /// 1188 /// Corresponds to the following pattern: 1189 /// 1190 /// ```erl 1191 /// <<1, _>>. 1192 /// ``` 1193 /// 1194 fn start_bit_array_pattern(&mut self) -> BitArrayPattern; 1195 1196 /// This takes an open bit array pattern and closes it. 1197 /// Code generated after this is not gonna be a segment of the bit array. 1198 /// 1199 fn end_bit_array_pattern(&mut self, bit_array: BitArrayPattern); 1200 1201 /// This creates a list pattern. 1202 /// The next two generated values are going to be respectively the pattern 1203 /// for the first item and the pattern for the tail of the list. 1204 /// 1205 /// For example: 1206 /// 1207 /// ```ignore 1208 /// builder.cons_list_pattern(); 1209 /// builder.discard_pattern(); 1210 /// builder.cons_list_pattern(); 1211 /// builder.string("Louis"); 1212 /// builder.empty_list_pattern(); 1213 /// ``` 1214 /// 1215 /// Corresponds to the following pattern: 1216 /// 1217 /// ```erl 1218 /// [_ | [ ~"Louis" | []]]. 1219 /// % Which, with some syntax sugar, is how we represent a pattern matching 1220 /// % on a list with two elements, where the second element is the string 1221 /// % ~"Louis": 1222 /// % [_, ~"Louis"] 1223 /// ``` 1224 /// 1225 fn cons_list_pattern(&mut self); 1226 1227 /// This creates a pattern matching on the empty list. 1228 /// 1229 fn empty_list_pattern(&mut self); 1230 1231 /// This creates a string literal, where the string is represented as a 1232 /// bit array with the utf8 bytes making up the string. 1233 /// This is how Gleam string literals are represented in Erlang. 1234 /// 1235 /// For example: 1236 /// 1237 /// ```ignore 1238 /// builder.string("ksiąskę"); 1239 /// ``` 1240 /// 1241 /// Corresponds to: 1242 /// 1243 /// ```erl 1244 /// ~"ksiąskę". 1245 /// % Which is the same as <<"ksiąskę"/utf8>> 1246 /// % Or the same as writing the bytes directly: 1247 /// % <<107, 115, 105, 196, 133, 115, 107, 196, 153>> 1248 /// ``` 1249 /// 1250 fn string(&mut self, string: &str); 1251 1252 /// This creates an integer literal from the given value. 1253 /// 1254 /// For example: 1255 /// 1256 /// ```ignore 1257 /// builder.int(BigInt::from(2)) 1258 /// ``` 1259 /// 1260 /// Corresponds to: 1261 /// 1262 /// ```erl 1263 /// 2. 1264 /// ``` 1265 /// 1266 fn int(&mut self, value: BigInt); 1267 1268 /// This creates a float literal from the given value. 1269 /// 1270 /// For example: 1271 /// 1272 /// ```ignore 1273 /// builder.float(1.2) 1274 /// ``` 1275 /// 1276 /// Corresponds to: 1277 /// 1278 /// ```erl 1279 /// 1.2. 1280 /// ``` 1281 /// 1282 fn float(&mut self, value: f64); 1283 1284 /// This creates a literal atom with the given name. 1285 /// 1286 /// For example: 1287 /// 1288 /// ```ignore 1289 /// builder.atom("wibble") 1290 /// ``` 1291 /// 1292 /// Corresponds to: 1293 /// 1294 /// ```erl 1295 /// wibble. 1296 /// ``` 1297 /// 1298 fn atom(&mut self, name: &str); 1299} 1300 1301/// A structure that implements the `ErlangBuilder` trait and produces a nice 1302/// and readable Erlang source string. 1303#[derive(Debug)] 1304pub struct ErlangSourceBuilder { 1305 code: String, 1306 /// This keeps track of what we're generating 1307 position: Vec<ErlangSourceBuilderPosition>, 1308 /// The current indentation to use when generating stuff like case 1309 /// expressions, block statements, etc. 1310 indentation: usize, 1311} 1312 1313/// This is used to keep track of the current position when generating pretty 1314/// printed code from an `ErlangSourceBuilder`. 1315#[derive(Debug)] 1316enum ErlangSourceBuilderPosition { 1317 /// We're generating a top level documentation attribute like `-doc(false)`, 1318 /// or `-moduledoc(~"wibble wobble")`. 1319 DocAttribute, 1320 1321 /// We're generating a function spec like `-spec wibble(atom()) -> atom()`. 1322 FunctionSpec, 1323 1324 /// We're generating code for a type spec like 1325 /// `-type wibble() :: {ok, integer()}`. 1326 TypeSpec { expected: TypeSpecExpectedItem }, 1327 1328 /// We're generating a function type, there's a couple of things that make 1329 /// it up that we will need to generate: its arguments and the return type. 1330 /// Which one we're expecting to see is described by the `expected` field. 1331 FunctionType { 1332 expected: ExpectedFunctionTypeItem, 1333 /// If a function type doesn't appear at the top level as a spec 1334 /// annotation, then we must wrap it in a `fun(...)`. For example: 1335 /// 1336 /// ```erl 1337 /// % in a spec annotation it simply comes after the function name: 1338 /// -spec wibble () -> integer(). 1339 /// wibble() -> 11. 1340 /// 1341 /// % but inside another type it has to be wrapped in `fun(...)`: 1342 /// -spec wobble () -> fun(() -> integer()) 1343 /// wobble() -> fun wibble/0. 1344 /// ``` 1345 /// 1346 /// This is `true` if the type has to be wrapped in `fun(...)` 1347 needs_wrapping: bool, 1348 }, 1349 1350 /// We're generating a named type like `integer()`, or `list(atom())`. 1351 NamedType { 1352 /// This is `true` is the first type argument of the named type has not 1353 /// been generated yet. 1354 first: bool, 1355 }, 1356 1357 /// We're generating a union type like `integer() | atom()`. 1358 UnionType { 1359 /// This is `true` is the first alternative of the union type has not 1360 /// been generated yet. 1361 first: bool, 1362 }, 1363 1364 /// We're generating a tuple type like `{integer(), atom()}`. 1365 TupleType { 1366 /// This is `true` is the first item of the tuple type has not been 1367 /// generated yet. 1368 first: bool, 1369 }, 1370 1371 /// We're generating the statements of a function. 1372 FunctionStatement { 1373 /// This is `true` if the first statement has not been generated yet. 1374 first: bool, 1375 }, 1376 1377 /// We're generating the statements of an anonymous function. 1378 AnonymousFunctionStatement { 1379 /// This is `true` if the first statement has not been generated yet. 1380 first: bool, 1381 }, 1382 1383 /// We're generating code for a match operator like `X = 1`. 1384 /// This is something that happens in multiple steps: first the pattern on 1385 /// the left hand side, second the expression on the right. 1386 MatchOperator { 1387 /// This keeps track of what we need to generate next. 1388 expected: ExpectedMatchSide, 1389 }, 1390 1391 /// We're generating code for a match pattern like `[1, A | _] = List`. 1392 /// This is something that happens in multiple steps: first the pattern on 1393 /// the left hand side, second the pattern on the right hand side. 1394 MatchPattern { 1395 /// This keeps track of what we need to generate next. 1396 expected: ExpectedMatchPatternSide, 1397 }, 1398 1399 /// We're generating a list. 1400 List { 1401 /// This is telling us if we're generating a list expression, or a list 1402 /// pattern. 1403 kind: ListKind, 1404 /// The list item we're expecting to see next. 1405 expected: ExpectedListItem, 1406 }, 1407 1408 /// We're generating code for a unary operator. We're waiting for the 1409 /// expression to apply the operator to. 1410 UnaryOperator, 1411 1412 /// We're generating a tuple. 1413 Tuple { 1414 /// This is `true` is the first tuple item has not been generated yet. 1415 first: bool, 1416 }, 1417 1418 /// We're generating a tuple pattern. 1419 TuplePattern { 1420 /// This is `true` if the first pattern of the tuple has not been 1421 /// generated ywt. 1422 first: bool, 1423 }, 1424 1425 /// We're generating the segments of a bit array. 1426 BitArray { 1427 /// Whether we're dealing with a bit array pattern, or a bit array 1428 /// expression. 1429 kind: BitArrayKind, 1430 1431 /// This is `true` if the first segment has not been generated yet. 1432 first: bool, 1433 }, 1434 1435 /// We're generating code for a segment of a bit array, like `10:1/signed`. 1436 BitArraySegment { 1437 expected: BitArraySegmentExpectedItem, 1438 /// This is `true` if the value of the bit array segment needs to be wrapped 1439 /// in parentheses. For example function calls need to be wrapped, or they 1440 /// would result in invalid Erlang being produced. 1441 /// 1442 /// ```erl 1443 /// <<x()/binary>> % This is a syntax error! 1444 /// <<(x())/binary>> % This is fine. 1445 /// ``` 1446 /// 1447 segment_value_needs_wrapping: bool, 1448 segment_size_needs_wrapping: bool, 1449 }, 1450 1451 /// We're generating a `begin ... end` block. 1452 Block { 1453 /// This is `true` is the first statement of the block has not been 1454 /// generated yet. 1455 first: bool, 1456 }, 1457 1458 /// We're generating code for a function call like `wibble(1, 2)`. 1459 /// This needs to happen in steps: first we generate the function being 1460 /// called (that could be any arbitrary expression after all), then we 1461 /// generate the arguments it's being called with. 1462 FunctionCall { 1463 expected: ExpectedCallItem, 1464 /// This is `true` if the thing that is being called needs to be wrapped 1465 /// in parentheses. This appears to be needed in just one case: if we 1466 /// are calling another function call expression. For example: 1467 /// 1468 /// ```erl 1469 /// wibble()() % this is invalid Erlang 1470 /// (wibble())() % this is valid Erlang 1471 /// ``` 1472 /// 1473 /// Actually this seems to be needed for OTP versions up to 28, in OTP 1474 /// 29 we can simply write `wibble()()`. However, since we have to 1475 /// support OTP 28 we will add the wrapping when needed. 1476 /// 1477 called_item_needs_wrapping: bool, 1478 }, 1479 1480 /// We're generating code for a binary operator like `1 + 3`. 1481 BinaryOperator { 1482 expected: ExpectedBinaryOperatorSide, 1483 /// Wether this binary operation needs to be wrapped in parentheses or 1484 /// not. 1485 needs_wrapping: bool, 1486 operator: &'static str, 1487 }, 1488 1489 /// We're generating code for a case expression. 1490 Case { expected: ExpectedCaseItem }, 1491 /// We're generating code for a case clause. 1492 CaseClause { expected: ExpectedCaseClauseItem }, 1493 /// We're generating the key-value pairs of a map. 1494 Map { 1495 /// This is `true` if no key-value pair has been generated yet. 1496 first: bool, 1497 }, 1498 /// We're generating a key-value pair inside a map. 1499 MapField { expected: MapFieldExpectedItem }, 1500 /// We're generating the fields of a record attribute. 1501 RecordAttribute { 1502 /// This is `true` if no field has been generated yet. 1503 first: bool, 1504 }, 1505 /// We're generating the field of a record attribute. That needs to happen 1506 /// in two steps: first we generate the name, second we generate the type of 1507 /// the field. 1508 RecordField { expected: ExpectedRecordFieldItem }, 1509} 1510 1511#[derive(Debug, Eq, PartialEq)] 1512enum ListKind { 1513 /// We're generating a list pattern. 1514 Pattern, 1515 /// We're generating a list expression. 1516 Expression, 1517} 1518 1519#[derive(Debug, Eq, PartialEq, Copy, Clone)] 1520enum BitArrayKind { 1521 /// We're generating a bit array pattern. 1522 Pattern, 1523 /// We're generating a bit array expression. 1524 Expression, 1525} 1526 1527/// A map field is made of two things: a key, and a value. It's not an item that 1528/// is closed explicitly with a `end_map_field` function. It is implicitly over 1529/// after two expressions are generated. So we need to keep track of what we're 1530/// expecting to be generated next. 1531#[derive(Debug)] 1532enum MapFieldExpectedItem { 1533 Key, 1534 Value, 1535} 1536 1537/// A record field is made of two things: a name, and a type. It's not an item 1538/// that is closed explicitly with a `end_record_field` function. 1539/// It is implicitly over after those two things are generated. 1540/// So we need to keep track of which we're expecting to be generated next. 1541#[derive(Debug)] 1542enum ExpectedRecordFieldItem { 1543 Name, 1544 Type, 1545} 1546 1547/// Generating a case clause is done in three separate steps: first we generate 1548/// a single pattern, then we have to generate the guards for the clause, 1549/// finally we will be generating the statements making up the clause's body. 1550/// 1551#[derive(Debug)] 1552enum ExpectedCaseClauseItem { 1553 Pattern, 1554 Guards { 1555 /// This is true if no guard has been generated yet. 1556 first: bool, 1557 }, 1558 Body { 1559 /// This is true if no body statement has been generated yet. 1560 first: bool, 1561 }, 1562} 1563 1564/// Generating a case expression is done in two steps: first we generate the 1565/// subject being matched on, then we generate the branches of the case 1566/// expression. 1567/// 1568#[derive(Debug)] 1569enum ExpectedCaseItem { 1570 /// We're waiting for the expression to be matched on to be generated. 1571 Subject, 1572 /// We've generated the expression to be matched on, and now are waiting for 1573 /// the case branches to be generated. 1574 Branches { 1575 /// This is `true` is no branch has been generated yet. 1576 first: bool, 1577 }, 1578} 1579 1580/// When generating a binary operator, that is made of three parts: the operator 1581/// and the left and right hand sides. 1582/// The way the Erlang Abstract Format works, we first generate the operator, 1583/// and then the two sides. 1584/// This is used to keep track which side we're expecting to see and properly 1585/// pretty print the output. 1586/// 1587#[derive(Debug)] 1588enum ExpectedBinaryOperatorSide { 1589 Left, 1590 Right, 1591 BinaryOperatorIsOver, 1592} 1593 1594/// When generating a bit array segment we need to generate exactly three 1595/// things: the value, the size, and the type specifiers. 1596/// This keeps track of which one we're expecting to be generated next. 1597/// 1598#[derive(Debug)] 1599enum BitArraySegmentExpectedItem { 1600 Value { 1601 /// This is telling us if the value of the segment has to be a pattern 1602 /// or an expression. 1603 kind: BitArrayKind, 1604 }, 1605 Size, 1606 Specifiers, 1607} 1608 1609/// When generating a function call, that is made of two parts: the function to 1610/// be called (that could be a simple literal atom, denoting a function from the 1611/// current module, or any expression), and its arguments. 1612/// 1613#[derive(Debug)] 1614enum ExpectedCallItem { 1615 /// We're waiting for the function to be called to be generated 1616 FunctionToBeCalled, 1617 /// The function to be called was generated, now we're waiting for its 1618 /// arguments. 1619 Arguments { first: bool }, 1620} 1621 1622/// When generating a function type, that is made of two parts: the type 1623/// arguments of the function, and the return type. 1624/// 1625#[derive(Debug)] 1626enum ExpectedFunctionTypeItem { 1627 Arguments { first: bool }, 1628 ReturnType, 1629} 1630 1631/// Type specs don't have a "end_" function. They are implicitly over once a 1632/// type is generated. This is used to keep track of what we're expecting to 1633/// see. 1634/// 1635#[derive(Debug)] 1636enum TypeSpecExpectedItem { 1637 TypeDefinition, 1638 TypeSpecIsOver, 1639} 1640 1641/// A match operator is made of two sides: `X = 1`. A pattern and an expression. 1642/// 1643#[derive(Debug)] 1644enum ExpectedMatchSide { 1645 /// We're waiting for the pattern on the left hand side of an assignment to 1646 /// be generated. 1647 Pattern, 1648 /// We're waiting for the expression on the right hand side of an assignment 1649 /// to be generated. 1650 Expression, 1651} 1652 1653/// An as pattern is made of two sides: `[1, _ | _] = List`. 1654/// A pattern and a variable pattern for the name. 1655/// 1656#[derive(Debug)] 1657enum ExpectedMatchPatternSide { 1658 /// We're waiting for the pattern on the left hand side of the match pattern 1659 /// to be generated. 1660 Left, 1661 /// We're waiting for the pattern on the right hand side of the match 1662 /// pattern to be generated. 1663 Right, 1664} 1665 1666/// Lists are built by cons cells, so when building a list we will do something 1667/// like this: `[a | [b | []]]`. 1668/// This is telling us if we're expecting the first item, the second list, or if 1669/// the list is actually over. 1670/// 1671#[derive(Debug)] 1672enum ExpectedListItem { 1673 First, 1674 Rest, 1675 ListIsOver, 1676} 1677 1678static UNICODE_ESCAPE_SEQUENCE_PATTERN: OnceLock<Regex> = OnceLock::new(); 1679 1680/// How does pretty printing work? Here's a high level overview of how it works: 1681/// 1682/// - when a new element is generated we call the `new_x` method. 1683/// If I'm generating an integer (or any expression) I call `new_expression`; 1684/// if I'm generating a pattern I call `new_pattern`. 1685/// - The `new_x` functions make sure that we're allowed to generate that 1686/// element in the current context (for example if I'm generating a tuple type 1687/// I can't start generating expression)! 1688/// - The `new_x` functions also make sure to add any code that is needed before 1689/// this new expression we're about to generate given the current context. 1690/// For example, say we're generating the items of a tuple, and we add another 1691/// one: first the call to `new_expression` is going to make sure to add 1692/// a comma to separate the previous item from the new one. 1693/// 1694/// - Then we can start pushing the code needed to generate whatever it is we 1695/// are generating. If it's something simple like an integer we can just push 1696/// its string representation. 1697/// - There's also plenty of elements that are not "self-closing" and will be 1698/// generated in multiple steps (like function calls, tuples with multiple 1699/// items, binary operators, ...). In that case we can push a new `position` 1700/// to update the current context and keep track of what we're doing! 1701/// - Whenever we reach a `end_x` function we can pop the position we pushed on 1702/// the stack. That's the moment we can add whatever is needed to "close" one 1703/// of those complex elements. For example if I'm done generating a function's 1704/// body I can add a full stop at the end of it; if I'm done generating a 1705/// tuple I can add the final `}` after all the elements, and so on... 1706/// 1707/// - There's one final tricky bit. Not all elements that are generated in 1708/// multiple steps have a `end_x` function (for example binary operators and 1709/// assignments). Those will end after a specific sequence of elements is 1710/// generated. 1711/// For example, if I call `self.match_operator` I know that it will be over 1712/// after the next pattern and expression are generated: 1713/// 1714/// ```ignore 1715/// // X = 1 1716/// builder.match_operator() 1717/// builder.variable_pattern("X") 1718/// builder.int(1) 1719/// ``` 1720/// 1721/// Notice how here we don't have a `start_match_operator` and 1722/// `end_match_operator`. As you'll see in the implementation these will 1723/// require a bit of extra book-keeping in the `new_x` functions. 1724/// 1725impl ErlangBuilder<String> for ErlangSourceBuilder { 1726 fn new(module: Option<ErlangModuleName>) -> Self { 1727 Self { 1728 code: if let Some(module) = module { 1729 format!("-module({}).\n", quote_atom_name(&module.0)) 1730 } else { 1731 String::new() 1732 }, 1733 indentation: 0, 1734 position: vec![], 1735 } 1736 } 1737 1738 fn into_output(mut self) -> String { 1739 self.close_currently_open_item(); 1740 self.code.push('\n'); 1741 self.code 1742 } 1743 1744 fn export_attribute<'a, Name: AsRef<str>>( 1745 &mut self, 1746 exported: impl IntoIterator<Item = (Name, usize)>, 1747 ) { 1748 // If there's no item in the iterator we don't add the attribute at all. 1749 let mut exported = exported.into_iter().peekable(); 1750 if exported.peek().is_none() { 1751 return; 1752 } 1753 1754 self.new_top_level_form(); 1755 1756 self.code.push_str("-export(["); 1757 let mut first = true; 1758 for (name, arity) in exported { 1759 if first { 1760 first = false; 1761 } else { 1762 self.code.push_str(", "); 1763 } 1764 1765 self.code.push_str(&quote_atom_name(name.as_ref())); 1766 self.code.push('/'); 1767 self.code.push_str(&arity.to_string()) 1768 } 1769 self.code.push_str("]).\n"); 1770 } 1771 1772 fn export_type_attribute<'a, Name: AsRef<str>>( 1773 &mut self, 1774 exported: impl IntoIterator<Item = (Name, usize)>, 1775 ) { 1776 // If there's no item in the iterator we don't add the attribute at all. 1777 let mut exported = exported.into_iter().peekable(); 1778 if exported.peek().is_none() { 1779 return; 1780 } 1781 1782 self.new_top_level_form(); 1783 1784 self.code.push_str("-export_type(["); 1785 let mut first = true; 1786 for (name, arity) in exported { 1787 if first { 1788 first = false; 1789 } else { 1790 self.code.push_str(", "); 1791 } 1792 1793 self.code.push_str(&quote_atom_name(name.as_ref())); 1794 self.code.push('/'); 1795 self.code.push_str(&arity.to_string()) 1796 } 1797 self.code.push_str("]).\n"); 1798 } 1799 1800 fn start_doc_attribute(&mut self) -> DocAttribute { 1801 self.new_top_level_form(); 1802 self.code.push_str("-doc("); 1803 self.position 1804 .push(ErlangSourceBuilderPosition::DocAttribute); 1805 DocAttribute { 1806 items: ErlangSourceBuilder::dummy_list(), 1807 } 1808 } 1809 1810 fn start_moduledoc_attribute(&mut self) -> DocAttribute { 1811 self.new_top_level_form(); 1812 self.code.push_str("-moduledoc("); 1813 self.position 1814 .push(ErlangSourceBuilderPosition::DocAttribute); 1815 DocAttribute { 1816 items: ErlangSourceBuilder::dummy_list(), 1817 } 1818 } 1819 1820 fn end_doc_attribute(&mut self, attribute: DocAttribute) { 1821 self.close_currently_open_item(); 1822 attribute.items.consume(); 1823 } 1824 1825 fn compile_attribute<'a>(&mut self, arguments: impl IntoIterator<Item = &'a str>) { 1826 self.new_top_level_form(); 1827 1828 self.code.push_str("-compile(["); 1829 1830 let mut first = true; 1831 for argument in arguments { 1832 if first { 1833 first = false; 1834 } else { 1835 self.code.push_str(", "); 1836 } 1837 1838 self.code.push_str(argument); 1839 } 1840 self.code.push_str("]).\n"); 1841 } 1842 1843 fn file_attribute(&mut self, file: &str, line: u32) { 1844 self.new_top_level_form(); 1845 self.code.push_str("\n-file(\""); 1846 self.code.push_str(file); 1847 self.code.push_str("\", "); 1848 self.code.push_str(&line.to_string()); 1849 self.code.push_str(")."); 1850 } 1851 1852 fn start_record_attribute(&mut self, record_name: &str) -> RecordAttribute { 1853 self.new_top_level_form(); 1854 self.code.push_str("-record("); 1855 self.code.push_str(&quote_atom_name(record_name)); 1856 self.code.push_str(", {"); 1857 self.indentation += INDENT; 1858 self.position 1859 .push(ErlangSourceBuilderPosition::RecordAttribute { first: true }); 1860 1861 RecordAttribute { 1862 fields: ErlangSourceBuilder::dummy_list(), 1863 } 1864 } 1865 1866 fn end_record_attribute(&mut self, record: RecordAttribute) { 1867 self.close_currently_open_item(); 1868 record.fields.consume(); 1869 } 1870 1871 fn record_field(&mut self) { 1872 self.new_record_field(); 1873 self.position 1874 .push(ErlangSourceBuilderPosition::RecordField { 1875 expected: ExpectedRecordFieldItem::Name, 1876 }); 1877 } 1878 1879 fn start_function_spec(&mut self, name: &str, _arity: usize) -> FunctionSpec { 1880 self.new_top_level_form(); 1881 self.code.push_str("\n-spec "); 1882 self.code.push_str(&quote_atom_name(name)); 1883 self.position 1884 .push(ErlangSourceBuilderPosition::FunctionSpec); 1885 FunctionSpec { 1886 representations: ErlangSourceBuilder::dummy_list(), 1887 } 1888 } 1889 1890 fn end_function_spec(&mut self, function_spec: FunctionSpec) { 1891 self.close_currently_open_item(); 1892 function_spec.representations.consume(); 1893 } 1894 1895 fn type_spec<Name: AsRef<str>>( 1896 &mut self, 1897 opaque: bool, 1898 name: &str, 1899 type_variables: impl IntoIterator<Item = Name>, 1900 ) { 1901 self.new_top_level_form(); 1902 self.code.push('\n'); 1903 self.code 1904 .push_str(if opaque { "-opaque " } else { "-type " }); 1905 self.code.push_str(&quote_atom_name(name)); 1906 self.code.push('('); 1907 1908 let mut first = true; 1909 for type_variable in type_variables { 1910 if first { 1911 first = false 1912 } else { 1913 self.code.push_str(", ") 1914 } 1915 self.code.push_str(type_variable.as_ref()) 1916 } 1917 self.code.push_str(") :: "); 1918 self.position.push(ErlangSourceBuilderPosition::TypeSpec { 1919 expected: TypeSpecExpectedItem::TypeDefinition, 1920 }); 1921 } 1922 1923 fn start_function_type(&mut self) -> FunctionTypeArguments { 1924 self.new_type(); 1925 1926 let needs_wrapping = 1927 if let Some(ErlangSourceBuilderPosition::FunctionSpec) = self.position.last() { 1928 self.code.push('('); 1929 false 1930 } else { 1931 self.code.push_str("fun(("); 1932 true 1933 }; 1934 1935 self.position 1936 .push(ErlangSourceBuilderPosition::FunctionType { 1937 expected: ExpectedFunctionTypeItem::Arguments { first: true }, 1938 needs_wrapping, 1939 }); 1940 1941 FunctionTypeArguments { 1942 types: ErlangSourceBuilder::dummy_list(), 1943 arguments: ErlangSourceBuilder::dummy_list(), 1944 } 1945 } 1946 1947 fn end_function_type_arguments( 1948 &mut self, 1949 function_type: FunctionTypeArguments, 1950 ) -> FunctionType { 1951 self.close_currently_open_item(); 1952 function_type.arguments.consume(); 1953 FunctionType { 1954 types: function_type.types, 1955 } 1956 } 1957 1958 fn end_function_type(&mut self, function_type: FunctionType) { 1959 self.close_currently_open_item(); 1960 function_type.types.consume(); 1961 } 1962 1963 fn start_named_type(&mut self, name: &str) -> NamedType { 1964 self.new_type(); 1965 self.position 1966 .push(ErlangSourceBuilderPosition::NamedType { first: true }); 1967 self.code.push_str(&quote_atom_name(name)); 1968 self.code.push('('); 1969 1970 NamedType { 1971 types: ErlangSourceBuilder::dummy_list(), 1972 } 1973 } 1974 1975 fn start_remote_named_type(&mut self, module: ErlangModuleName, name: &str) -> NamedType { 1976 self.new_type(); 1977 self.position 1978 .push(ErlangSourceBuilderPosition::NamedType { first: true }); 1979 self.code.push_str(&quote_atom_name(&module.0)); 1980 self.code.push(':'); 1981 self.code.push_str(&quote_atom_name(name)); 1982 self.code.push('('); 1983 1984 NamedType { 1985 types: ErlangSourceBuilder::dummy_list(), 1986 } 1987 } 1988 1989 fn end_named_type(&mut self, named_type: NamedType) { 1990 self.close_currently_open_item(); 1991 named_type.types.consume(); 1992 } 1993 1994 fn start_tuple_type(&mut self) -> TupleType { 1995 self.new_type(); 1996 self.position 1997 .push(ErlangSourceBuilderPosition::TupleType { first: true }); 1998 self.code.push('{'); 1999 2000 TupleType { 2001 items: ErlangSourceBuilder::dummy_list(), 2002 } 2003 } 2004 2005 fn end_tuple_type(&mut self, tuple: TupleType) { 2006 self.close_currently_open_item(); 2007 tuple.items.consume(); 2008 } 2009 2010 fn start_union_type(&mut self) -> UnionType { 2011 self.new_type(); 2012 self.position 2013 .push(ErlangSourceBuilderPosition::UnionType { first: true }); 2014 2015 UnionType { 2016 alternatives: ErlangSourceBuilder::dummy_list(), 2017 } 2018 } 2019 2020 fn end_union_type(&mut self, union_type: UnionType) { 2021 self.close_currently_open_item(); 2022 union_type.alternatives.consume(); 2023 } 2024 2025 fn type_variable(&mut self, name: &str) { 2026 self.new_type(); 2027 self.code.push_str(name); 2028 } 2029 2030 fn literal_atom_type(&mut self, name: &str) { 2031 self.new_type(); 2032 self.code.push_str(&quote_atom_name(name)); 2033 } 2034 2035 fn start_function<Name: AsRef<str>>( 2036 &mut self, 2037 name: &str, 2038 _arity: usize, 2039 arguments_names: impl IntoIterator<Item = Name>, 2040 ) -> Function { 2041 self.new_top_level_form(); 2042 self.code.push_str(&quote_atom_name(name)); 2043 self.code.push('('); 2044 2045 let mut first = true; 2046 for argument in arguments_names { 2047 if !first { 2048 self.code.push_str(", ") 2049 } else { 2050 first = false; 2051 } 2052 self.code.push_str(argument.as_ref()) 2053 } 2054 2055 self.code.push_str(") ->"); 2056 self.indentation += INDENT; 2057 self.position 2058 .push(ErlangSourceBuilderPosition::FunctionStatement { first: true }); 2059 2060 Function { 2061 clauses: ErlangSourceBuilder::dummy_list(), 2062 statements: ErlangSourceBuilder::dummy_list(), 2063 } 2064 } 2065 2066 fn start_anonymous_function<Name: AsRef<str>>( 2067 &mut self, 2068 arguments_names: impl IntoIterator<Item = Name>, 2069 ) -> Function { 2070 self.new_expression(); 2071 self.code.push_str("fun("); 2072 2073 let mut first = true; 2074 for argument in arguments_names { 2075 if !first { 2076 self.code.push_str(", ") 2077 } else { 2078 first = false; 2079 } 2080 self.code.push_str(argument.as_ref()) 2081 } 2082 2083 self.code.push_str(") ->"); 2084 self.indentation += INDENT; 2085 self.position 2086 .push(ErlangSourceBuilderPosition::AnonymousFunctionStatement { first: true }); 2087 2088 Function { 2089 clauses: ErlangSourceBuilder::dummy_list(), 2090 statements: ErlangSourceBuilder::dummy_list(), 2091 } 2092 } 2093 2094 fn end_function(&mut self, function: Function) { 2095 self.close_currently_open_item(); 2096 function.clauses.consume(); 2097 function.statements.consume(); 2098 } 2099 2100 fn start_block(&mut self) -> Block { 2101 self.new_expression(); 2102 self.code.push_str("begin"); 2103 self.indentation += INDENT; 2104 self.position 2105 .push(ErlangSourceBuilderPosition::Block { first: true }); 2106 2107 Block { 2108 statements: ErlangSourceBuilder::dummy_list(), 2109 } 2110 } 2111 2112 fn end_block(&mut self, block: Block) { 2113 self.close_currently_open_item(); 2114 block.statements.consume(); 2115 } 2116 2117 fn start_remote_call(&mut self, module: ErlangModuleName, function: &str) -> Call { 2118 self.pop_leftover_items(); 2119 2120 // If this function call we're generating is itself being called then 2121 // it is going to need to be wrapped in parentheses to be valid in 2122 // OTP 28: it is not ok to write `wibble()()`, but we have to write 2123 // `(wibble())()`. 2124 if let Some(ErlangSourceBuilderPosition::FunctionCall { 2125 expected: ExpectedCallItem::FunctionToBeCalled, 2126 called_item_needs_wrapping, 2127 }) = self.position.last_mut() 2128 { 2129 *called_item_needs_wrapping = true; 2130 }; 2131 2132 self.new_expression(); 2133 self.code.push_str(&quote_atom_name(&module.0)); 2134 self.code.push(':'); 2135 self.code.push_str(&quote_atom_name(function)); 2136 self.position 2137 .push(ErlangSourceBuilderPosition::FunctionCall { 2138 expected: ExpectedCallItem::Arguments { first: true }, 2139 called_item_needs_wrapping: false, 2140 }); 2141 Call { 2142 arguments: ErlangSourceBuilder::dummy_list(), 2143 } 2144 } 2145 2146 fn start_call(&mut self) -> Call { 2147 self.pop_leftover_items(); 2148 2149 // If this function call we're generating is itself being called then 2150 // it is going to need to be wrapped in parentheses to be valid in 2151 // OTP 28: it is not ok to write `wibble()()`, but we have to write 2152 // `(wibble())()`. 2153 if let Some(ErlangSourceBuilderPosition::FunctionCall { 2154 expected: ExpectedCallItem::FunctionToBeCalled, 2155 called_item_needs_wrapping, 2156 }) = self.position.last_mut() 2157 { 2158 *called_item_needs_wrapping = true; 2159 }; 2160 2161 self.new_expression(); 2162 self.position 2163 .push(ErlangSourceBuilderPosition::FunctionCall { 2164 expected: ExpectedCallItem::FunctionToBeCalled, 2165 called_item_needs_wrapping: false, 2166 }); 2167 Call { 2168 arguments: ErlangSourceBuilder::dummy_list(), 2169 } 2170 } 2171 2172 fn end_call(&mut self, call: Call) { 2173 self.close_currently_open_item(); 2174 call.arguments.consume(); 2175 } 2176 2177 fn start_tuple(&mut self) -> Tuple { 2178 self.new_expression(); 2179 self.code.push('{'); 2180 self.position 2181 .push(ErlangSourceBuilderPosition::Tuple { first: true }); 2182 2183 Tuple { 2184 items: ErlangSourceBuilder::dummy_list(), 2185 } 2186 } 2187 2188 fn end_tuple(&mut self, tuple: Tuple) { 2189 self.close_currently_open_item(); 2190 tuple.items.consume(); 2191 } 2192 2193 fn start_map(&mut self) -> Map { 2194 self.new_expression(); 2195 self.code.push_str("#{"); 2196 self.indentation += INDENT; 2197 self.position 2198 .push(ErlangSourceBuilderPosition::Map { first: true }); 2199 Map { 2200 items: ErlangSourceBuilder::dummy_list(), 2201 } 2202 } 2203 2204 fn end_map(&mut self, map: Map) { 2205 self.close_currently_open_item(); 2206 map.items.consume(); 2207 } 2208 2209 fn map_field(&mut self) { 2210 self.new_map_field(); 2211 self.position.push(ErlangSourceBuilderPosition::MapField { 2212 expected: MapFieldExpectedItem::Key, 2213 }); 2214 } 2215 2216 fn start_bit_array(&mut self) -> BitArray { 2217 self.do_not_wrap_if_segment_value_or_size(); 2218 self.new_expression(); 2219 self.code.push_str("<<"); 2220 self.position.push(ErlangSourceBuilderPosition::BitArray { 2221 kind: BitArrayKind::Expression, 2222 first: true, 2223 }); 2224 2225 BitArray { 2226 segments: ErlangSourceBuilder::dummy_list(), 2227 } 2228 } 2229 2230 fn end_bit_array(&mut self, bit_array: BitArray) { 2231 self.close_currently_open_item(); 2232 bit_array.segments.consume(); 2233 } 2234 2235 fn bit_array_segment(&mut self) { 2236 let kind = self.new_bit_array_segment(); 2237 self.position 2238 .push(ErlangSourceBuilderPosition::BitArraySegment { 2239 expected: BitArraySegmentExpectedItem::Value { kind }, 2240 // We assume all values are going to have to be wrapped, better 2241 // be safe than sorry! 2242 // We will turn this off only for certain expressions we know 2243 // are safe to not wrap, like bare integers and strings. 2244 segment_value_needs_wrapping: true, 2245 segment_size_needs_wrapping: true, 2246 }) 2247 } 2248 2249 fn bit_array_segment_specifiers( 2250 &mut self, 2251 specifiers: impl IntoIterator<Item = BitArraySegmentSpecifier>, 2252 ) { 2253 self.pop_leftover_items(); 2254 let Some(ErlangSourceBuilderPosition::BitArraySegment { 2255 expected: BitArraySegmentExpectedItem::Specifiers, 2256 segment_value_needs_wrapping, 2257 segment_size_needs_wrapping, 2258 }) = self.position.last_mut() 2259 else { 2260 invalid_code_for_position!(self, "bit array segment specifier"); 2261 }; 2262 2263 if *segment_value_needs_wrapping { 2264 self.code.push(')'); 2265 *segment_value_needs_wrapping = false; 2266 } else if *segment_size_needs_wrapping { 2267 self.code.push(')'); 2268 *segment_size_needs_wrapping = false; 2269 } 2270 2271 let mut first_specifier = true; 2272 let specifiers = specifiers.into_iter().sorted_by(|one, other| { 2273 if let BitArraySegmentSpecifier::Unit(_) = one { 2274 std::cmp::Ordering::Greater 2275 } else if let BitArraySegmentSpecifier::Unit(_) = other { 2276 std::cmp::Ordering::Less 2277 } else { 2278 std::cmp::Ordering::Equal 2279 } 2280 }); 2281 2282 for specifier in specifiers { 2283 let string = match specifier { 2284 BitArraySegmentSpecifier::Utf8 => "utf8", 2285 BitArraySegmentSpecifier::Utf16 => "utf16", 2286 BitArraySegmentSpecifier::Utf32 => "utf32", 2287 BitArraySegmentSpecifier::Integer => "integer", 2288 BitArraySegmentSpecifier::Float => "float", 2289 BitArraySegmentSpecifier::Binary => "binary", 2290 BitArraySegmentSpecifier::Bitstring => "bitstring", 2291 BitArraySegmentSpecifier::Signed => "signed", 2292 BitArraySegmentSpecifier::Unsigned => "unsigned", 2293 BitArraySegmentSpecifier::Little => "little", 2294 BitArraySegmentSpecifier::Big => "big", 2295 BitArraySegmentSpecifier::Native => "native", 2296 BitArraySegmentSpecifier::Unit(unit) => &format!("unit:{unit}"), 2297 }; 2298 if first_specifier { 2299 first_specifier = false; 2300 self.code.push('/'); 2301 } else { 2302 self.code.push('-') 2303 } 2304 self.code.push_str(string); 2305 } 2306 2307 self.position.pop(); 2308 } 2309 2310 fn cons_list(&mut self) { 2311 self.cons_list_of_kind(ListKind::Expression); 2312 } 2313 2314 fn empty_list(&mut self) { 2315 self.empty_list_of_kind(ListKind::Expression); 2316 } 2317 2318 fn start_case(&mut self) -> Case { 2319 self.new_expression(); 2320 self.code.push_str("case "); 2321 self.position.push(ErlangSourceBuilderPosition::Case { 2322 expected: ExpectedCaseItem::Subject, 2323 }); 2324 2325 Case { 2326 branches: ErlangSourceBuilder::dummy_list(), 2327 } 2328 } 2329 2330 fn end_case(&mut self, case: Case) { 2331 self.close_currently_open_item(); 2332 case.branches.consume(); 2333 } 2334 2335 fn start_case_clause(&mut self) -> ClausePattern { 2336 self.new_case_clause(); 2337 self.position.push(ErlangSourceBuilderPosition::CaseClause { 2338 expected: ExpectedCaseClauseItem::Pattern, 2339 }); 2340 ClausePattern { 2341 pattern: ErlangSourceBuilder::dummy_list(), 2342 guards: ErlangSourceBuilder::dummy_list(), 2343 body: ErlangSourceBuilder::dummy_list(), 2344 } 2345 } 2346 2347 fn end_clause_pattern(&mut self, clause_pattern: ClausePattern) -> ClauseGuards { 2348 self.close_currently_open_item(); 2349 self.position.push(ErlangSourceBuilderPosition::CaseClause { 2350 expected: ExpectedCaseClauseItem::Guards { first: true }, 2351 }); 2352 clause_pattern.pattern.consume(); 2353 ClauseGuards { 2354 guards: clause_pattern.guards, 2355 body: clause_pattern.body, 2356 } 2357 } 2358 2359 fn end_clause_guards(&mut self, clause_guards: ClauseGuards) -> ClauseBody { 2360 self.close_currently_open_item(); 2361 self.indentation += INDENT; 2362 self.position.push(ErlangSourceBuilderPosition::CaseClause { 2363 expected: ExpectedCaseClauseItem::Body { first: true }, 2364 }); 2365 2366 clause_guards.guards.consume(); 2367 ClauseBody { 2368 body: clause_guards.body, 2369 } 2370 } 2371 2372 fn end_clause_body(&mut self, clause_body: ClauseBody) { 2373 self.close_currently_open_item(); 2374 clause_body.body.consume(); 2375 } 2376 2377 fn variable(&mut self, name: &str) { 2378 self.do_not_wrap_if_segment_value_or_size(); 2379 self.new_expression(); 2380 self.code.push_str(name); 2381 } 2382 2383 fn unary_operator(&mut self, operator: &str) { 2384 self.new_expression(); 2385 self.code.push_str(operator); 2386 self.code.push(' '); 2387 self.position 2388 .push(ErlangSourceBuilderPosition::UnaryOperator) 2389 } 2390 2391 fn binary_operator(&mut self, operator: &'static str) { 2392 self.new_expression(); 2393 2394 // If this new binary operator we're generating is part of a bigger 2395 // binary operator (it doesn't matter if on the left or right-hand 2396 // side), then we want to wrap it in parentheses to avoid precedence 2397 // confusion! 2398 let needs_wrapping = match self.position.last() { 2399 Some(ErlangSourceBuilderPosition::BinaryOperator { .. }) => { 2400 self.code.push('('); 2401 true 2402 } 2403 Some(_) | None => false, 2404 }; 2405 2406 self.position 2407 .push(ErlangSourceBuilderPosition::BinaryOperator { 2408 expected: ExpectedBinaryOperatorSide::Left, 2409 needs_wrapping, 2410 operator, 2411 }) 2412 } 2413 2414 fn function_reference(&mut self, module: Option<ErlangModuleName>, name: &str, arity: usize) { 2415 self.new_expression(); 2416 self.code.push_str("fun "); 2417 if let Some(module) = module { 2418 self.code.push_str(&quote_atom_name(&module.0)); 2419 self.code.push(':'); 2420 } 2421 self.code.push_str(&quote_atom_name(name)); 2422 self.code.push('/'); 2423 self.code.push_str(&arity.to_string()); 2424 } 2425 2426 fn match_operator(&mut self) { 2427 self.new_expression(); 2428 self.position 2429 .push(ErlangSourceBuilderPosition::MatchOperator { 2430 expected: ExpectedMatchSide::Pattern, 2431 }); 2432 } 2433 2434 fn match_pattern(&mut self) { 2435 self.new_pattern(); 2436 self.position 2437 .push(ErlangSourceBuilderPosition::MatchPattern { 2438 expected: ExpectedMatchPatternSide::Left, 2439 }) 2440 } 2441 2442 fn variable_pattern(&mut self, name: &str) { 2443 self.do_not_wrap_if_segment_value_or_size(); 2444 self.new_pattern(); 2445 self.code.push_str(name); 2446 } 2447 2448 fn discard_pattern(&mut self) { 2449 self.do_not_wrap_if_segment_value_or_size(); 2450 self.new_pattern(); 2451 self.code.push('_'); 2452 } 2453 2454 fn int_pattern(&mut self, number: BigInt) { 2455 self.do_not_wrap_if_segment_value_or_size(); 2456 self.new_pattern(); 2457 self.code.push_str(&number.to_string()); 2458 } 2459 2460 fn float_pattern(&mut self, number: f64) { 2461 self.do_not_wrap_if_segment_value_or_size(); 2462 self.new_pattern(); 2463 2464 self.code.push_str(&format_float(number)) 2465 } 2466 2467 fn string_pattern(&mut self, content: &str) { 2468 self.do_not_wrap_if_segment_value_or_size(); 2469 self.new_pattern(); 2470 self.do_print_string_content(content); 2471 } 2472 2473 fn atom_pattern(&mut self, name: &str) { 2474 self.new_pattern(); 2475 self.code.push_str(&quote_atom_name(name)); 2476 } 2477 2478 fn start_tuple_pattern(&mut self) -> TuplePattern { 2479 self.new_pattern(); 2480 self.code.push('{'); 2481 self.position 2482 .push(ErlangSourceBuilderPosition::TuplePattern { first: true }); 2483 TuplePattern { 2484 items: ErlangSourceBuilder::dummy_list(), 2485 } 2486 } 2487 2488 fn end_tuple_pattern(&mut self, tuple: TuplePattern) { 2489 self.close_currently_open_item(); 2490 tuple.items.consume(); 2491 } 2492 2493 fn start_bit_array_pattern(&mut self) -> BitArrayPattern { 2494 self.new_pattern(); 2495 self.code.push_str("<<"); 2496 self.position.push(ErlangSourceBuilderPosition::BitArray { 2497 kind: BitArrayKind::Pattern, 2498 first: true, 2499 }); 2500 2501 BitArrayPattern { 2502 segments: ErlangSourceBuilder::dummy_list(), 2503 } 2504 } 2505 2506 fn end_bit_array_pattern(&mut self, bit_array: BitArrayPattern) { 2507 self.close_currently_open_item(); 2508 bit_array.segments.consume(); 2509 } 2510 2511 fn cons_list_pattern(&mut self) { 2512 self.cons_list_of_kind(ListKind::Pattern); 2513 } 2514 2515 fn empty_list_pattern(&mut self) { 2516 self.empty_list_of_kind(ListKind::Pattern); 2517 } 2518 2519 fn string(&mut self, content: &str) { 2520 self.do_not_wrap_if_segment_value_or_size(); 2521 self.new_expression(); 2522 self.do_print_string_content(content); 2523 } 2524 2525 fn int(&mut self, number: BigInt) { 2526 self.do_not_wrap_if_segment_value_or_size(); 2527 self.new_expression(); 2528 self.code.push_str(&number.to_string()); 2529 } 2530 2531 fn float(&mut self, number: f64) { 2532 self.do_not_wrap_if_segment_value_or_size(); 2533 self.new_expression(); 2534 self.code.push_str(&format_float(number)); 2535 } 2536 2537 fn atom(&mut self, name: &str) { 2538 // There's one special case where we actually don't want to push the 2539 // atom's text at all. That's when we're generating the `default` atom 2540 // as the size of a bit array segment. 2541 // That's how we can tell in the Erlang Abstract Format that the size 2542 // should be the default value, but it's not actually spelled out in 2543 // textual Erlang code. 2544 if let Some(ErlangSourceBuilderPosition::BitArraySegment { 2545 expected: expected @ BitArraySegmentExpectedItem::Size, 2546 segment_value_needs_wrapping, 2547 segment_size_needs_wrapping, 2548 }) = self.position.last_mut() 2549 { 2550 // We are new expecting to see the specifiers list 2551 *expected = BitArraySegmentExpectedItem::Specifiers; 2552 if *segment_value_needs_wrapping { 2553 self.code.push(')'); 2554 *segment_value_needs_wrapping = false; 2555 } 2556 // We have the default atom as a size, that means we don't have to 2557 // print anything at all! The size doesn't need any wrapping because 2558 // there's no size at all. 2559 *segment_size_needs_wrapping = false; 2560 } else { 2561 self.new_expression(); 2562 self.code.push_str(&quote_atom_name(name)); 2563 } 2564 } 2565} 2566 2567fn format_float(number: f64) -> String { 2568 if number.is_zero() { 2569 if number.is_sign_negative() { 2570 String::from("-0.0") 2571 } else { 2572 String::from("+0.0") 2573 } 2574 } else if number.fract().is_zero() { 2575 format!("{number:.1}") 2576 } else { 2577 format!("{number}") 2578 } 2579} 2580 2581const INDENT: usize = 4; 2582 2583impl ErlangSourceBuilder { 2584 fn dummy_list() -> erlang_term_format::List { 2585 erlang_term_format::List::new(0) 2586 } 2587 2588 /// This has to be called before generating any new top level form: those 2589 /// are specs like `-spec`, `-type`, `-opaque`, doc attributes like 2590 /// `-doc` and `-moduledoc`, and function definitions. 2591 /// This allows the code generator to: 2592 /// - check for inconsistencies and panic (for example if we're generating 2593 /// a top level form not at the top level scope). 2594 /// - update the current context. 2595 /// - add all the code that needs to go before this expression we're about 2596 /// to generate, based on the current context. 2597 /// 2598 fn new_top_level_form(&mut self) { 2599 self.pop_leftover_items(); 2600 if !self.position.is_empty() { 2601 invalid_code_for_position!(self, "top level form"); 2602 } 2603 } 2604 2605 /// This has to be called before generating any expression! 2606 /// This allows the code generator to: 2607 /// - check for inconsistencies and panic (for example if we're generating 2608 /// expressions in the wrong place). 2609 /// - update the current context. 2610 /// - add all the code that needs to go before this expression we're about 2611 /// to generate, based on the current context. 2612 /// 2613 fn new_expression(&mut self) { 2614 self.pop_leftover_items(); 2615 let Some(position) = self.position.last_mut() else { 2616 invalid_code_for_position!(self, "expression"); 2617 }; 2618 2619 match position { 2620 ErlangSourceBuilderPosition::DocAttribute => (), 2621 2622 ErlangSourceBuilderPosition::RecordField { 2623 expected: expected @ ExpectedRecordFieldItem::Name, 2624 } => *expected = ExpectedRecordFieldItem::Type, 2625 2626 ErlangSourceBuilderPosition::Case { 2627 expected: expected @ ExpectedCaseItem::Subject, 2628 } => *expected = ExpectedCaseItem::Branches { first: true }, 2629 2630 ErlangSourceBuilderPosition::FunctionCall { 2631 expected: expected @ ExpectedCallItem::FunctionToBeCalled, 2632 called_item_needs_wrapping, 2633 } => { 2634 if *called_item_needs_wrapping { 2635 self.code.push('('); 2636 }; 2637 *expected = ExpectedCallItem::Arguments { first: true } 2638 } 2639 2640 ErlangSourceBuilderPosition::FunctionCall { 2641 expected: ExpectedCallItem::Arguments { first }, 2642 called_item_needs_wrapping, 2643 } => { 2644 if *called_item_needs_wrapping { 2645 *called_item_needs_wrapping = false; 2646 self.code.push(')'); 2647 } 2648 if *first { 2649 self.code.push('(') 2650 } else { 2651 self.code.push_str(", "); 2652 } 2653 *first = false; 2654 } 2655 ErlangSourceBuilderPosition::Tuple { first } => { 2656 if !*first { 2657 self.code.push_str(", "); 2658 } 2659 *first = false; 2660 } 2661 2662 // We're expecting the list's head. We don't have to add 2663 // anything! 2664 ErlangSourceBuilderPosition::List { 2665 expected: expected @ ExpectedListItem::First, 2666 kind: ListKind::Expression, 2667 } => *expected = ExpectedListItem::Rest, 2668 2669 ErlangSourceBuilderPosition::List { 2670 expected: expected @ ExpectedListItem::Rest, 2671 kind: ListKind::Expression, 2672 } => { 2673 *expected = ExpectedListItem::ListIsOver; 2674 self.code.push_str(" | ") 2675 } 2676 2677 ErlangSourceBuilderPosition::BinaryOperator { 2678 expected: expected @ ExpectedBinaryOperatorSide::Left, 2679 .. 2680 } => *expected = ExpectedBinaryOperatorSide::Right, 2681 2682 ErlangSourceBuilderPosition::BinaryOperator { 2683 expected: expected @ ExpectedBinaryOperatorSide::Right, 2684 operator, 2685 .. 2686 } => { 2687 *expected = ExpectedBinaryOperatorSide::BinaryOperatorIsOver; 2688 self.code.push(' '); 2689 self.code.push_str(operator); 2690 self.code.push(' '); 2691 } 2692 2693 ErlangSourceBuilderPosition::FunctionStatement { first } 2694 | ErlangSourceBuilderPosition::AnonymousFunctionStatement { first } 2695 | ErlangSourceBuilderPosition::Block { first } 2696 | ErlangSourceBuilderPosition::CaseClause { 2697 expected: ExpectedCaseClauseItem::Body { first }, 2698 } => { 2699 if !*first { 2700 self.code.push(','); 2701 } 2702 *first = false; 2703 self.code.push('\n'); 2704 self.push_indentation(); 2705 } 2706 2707 ErlangSourceBuilderPosition::BitArraySegment { 2708 expected: 2709 expected @ BitArraySegmentExpectedItem::Value { 2710 kind: BitArrayKind::Expression, 2711 }, 2712 segment_value_needs_wrapping, 2713 .. 2714 } => { 2715 if *segment_value_needs_wrapping { 2716 self.code.push('('); 2717 } 2718 *expected = BitArraySegmentExpectedItem::Size 2719 } 2720 2721 ErlangSourceBuilderPosition::BitArraySegment { 2722 expected: expected @ BitArraySegmentExpectedItem::Size, 2723 segment_value_needs_wrapping, 2724 segment_size_needs_wrapping, 2725 } => { 2726 if *segment_value_needs_wrapping { 2727 self.code.push(')'); 2728 // We've finished wrapping the value, we set this to 2729 // false so we don't add other parentheses when we get 2730 // to the specifiers list! 2731 *segment_value_needs_wrapping = false; 2732 } 2733 *expected = BitArraySegmentExpectedItem::Specifiers; 2734 self.code.push(':'); 2735 if *segment_size_needs_wrapping { 2736 self.code.push('('); 2737 } 2738 } 2739 2740 ErlangSourceBuilderPosition::CaseClause { 2741 expected: 2742 ExpectedCaseClauseItem::Guards { 2743 first: first @ true, 2744 }, 2745 } => { 2746 *first = false; 2747 self.code.push_str(" when "); 2748 } 2749 2750 ErlangSourceBuilderPosition::MapField { expected } => match expected { 2751 MapFieldExpectedItem::Key => *expected = MapFieldExpectedItem::Value, 2752 // We've generated a key and now the value is being generated. 2753 // So we need to add the `=>` separating key and value and we 2754 // can pop this position that is now complete. 2755 MapFieldExpectedItem::Value => { 2756 self.code.push_str(" => "); 2757 self.position.pop(); 2758 } 2759 }, 2760 2761 // We were expecting an expression and someone is about to generate 2762 // it, we can pop this off the stack and need to add the ` = ` 2763 // separating the previous pattern from this new expression. 2764 ErlangSourceBuilderPosition::MatchOperator { 2765 expected: ExpectedMatchSide::Expression, 2766 } => { 2767 self.code.push_str(" = "); 2768 self.position.pop(); 2769 } 2770 // We were expecting an expression and someone generated it, we can 2771 // now pop this off the stack. 2772 ErlangSourceBuilderPosition::UnaryOperator { .. } => { 2773 self.position.pop(); 2774 } 2775 2776 // Expressions are not allowed in any of these positions. 2777 ErlangSourceBuilderPosition::Case { 2778 expected: ExpectedCaseItem::Branches { .. }, 2779 } 2780 | ErlangSourceBuilderPosition::List { 2781 expected: ExpectedListItem::ListIsOver, 2782 kind: ListKind::Expression, 2783 } 2784 | ErlangSourceBuilderPosition::BitArray { .. } 2785 | ErlangSourceBuilderPosition::MatchOperator { 2786 expected: ExpectedMatchSide::Pattern, 2787 } 2788 | ErlangSourceBuilderPosition::CaseClause { 2789 expected: ExpectedCaseClauseItem::Pattern, 2790 } 2791 | ErlangSourceBuilderPosition::TuplePattern { .. } 2792 | ErlangSourceBuilderPosition::MatchPattern { .. } 2793 | ErlangSourceBuilderPosition::FunctionSpec 2794 | ErlangSourceBuilderPosition::TypeSpec { .. } 2795 | ErlangSourceBuilderPosition::NamedType { .. } 2796 | ErlangSourceBuilderPosition::FunctionType { .. } 2797 | ErlangSourceBuilderPosition::UnionType { .. } 2798 | ErlangSourceBuilderPosition::RecordField { 2799 expected: ExpectedRecordFieldItem::Type, 2800 } 2801 | ErlangSourceBuilderPosition::TupleType { .. } 2802 | ErlangSourceBuilderPosition::Map { .. } 2803 | ErlangSourceBuilderPosition::RecordAttribute { .. } 2804 | ErlangSourceBuilderPosition::CaseClause { 2805 expected: ExpectedCaseClauseItem::Guards { first: false }, 2806 } 2807 | ErlangSourceBuilderPosition::BitArraySegment { 2808 expected: BitArraySegmentExpectedItem::Specifiers, 2809 .. 2810 } 2811 | ErlangSourceBuilderPosition::BitArraySegment { 2812 expected: 2813 BitArraySegmentExpectedItem::Value { 2814 kind: BitArrayKind::Pattern, 2815 }, 2816 .. 2817 } 2818 | ErlangSourceBuilderPosition::BinaryOperator { 2819 expected: ExpectedBinaryOperatorSide::BinaryOperatorIsOver, 2820 .. 2821 } 2822 | ErlangSourceBuilderPosition::List { 2823 kind: ListKind::Pattern, 2824 .. 2825 } => invalid_code_for_position!(self, "expression"), 2826 } 2827 } 2828 2829 /// This has to be called before generating any type! 2830 /// This allows the code generator to: 2831 /// - check for inconsistencies and panic (for example if we're generating 2832 /// types in the wrong place). 2833 /// - update the current context. 2834 /// - add all the code that needs to go before this type we're about 2835 /// to generate, based on the current context. 2836 /// 2837 fn new_type(&mut self) { 2838 self.pop_leftover_items(); 2839 let Some(position) = self.position.last_mut() else { 2840 invalid_code_for_position!(self, "type"); 2841 }; 2842 2843 match position { 2844 ErlangSourceBuilderPosition::FunctionSpec => {} 2845 ErlangSourceBuilderPosition::FunctionType { 2846 expected: ExpectedFunctionTypeItem::ReturnType, 2847 needs_wrapping: _, 2848 } => {} 2849 2850 ErlangSourceBuilderPosition::TypeSpec { 2851 expected: expected @ TypeSpecExpectedItem::TypeDefinition, 2852 } => { 2853 *expected = TypeSpecExpectedItem::TypeSpecIsOver; 2854 } 2855 2856 ErlangSourceBuilderPosition::FunctionType { 2857 expected: ExpectedFunctionTypeItem::Arguments { first }, 2858 needs_wrapping: _, 2859 } 2860 | ErlangSourceBuilderPosition::TupleType { first } 2861 | ErlangSourceBuilderPosition::NamedType { first } => { 2862 if !*first { 2863 self.code.push_str(", ") 2864 } 2865 *first = false 2866 } 2867 2868 ErlangSourceBuilderPosition::UnionType { first } => { 2869 if !*first { 2870 self.code.push_str(" | ") 2871 } 2872 *first = false 2873 } 2874 2875 ErlangSourceBuilderPosition::RecordField { 2876 expected: ExpectedRecordFieldItem::Type, 2877 } => { 2878 self.code.push_str(" :: "); 2879 self.position.pop(); 2880 } 2881 2882 ErlangSourceBuilderPosition::FunctionCall { .. } 2883 | ErlangSourceBuilderPosition::Block { .. } 2884 | ErlangSourceBuilderPosition::Tuple { .. } 2885 | ErlangSourceBuilderPosition::BitArray { .. } 2886 | ErlangSourceBuilderPosition::BitArraySegment { .. } 2887 | ErlangSourceBuilderPosition::List { .. } 2888 | ErlangSourceBuilderPosition::FunctionStatement { .. } 2889 | ErlangSourceBuilderPosition::AnonymousFunctionStatement { .. } 2890 | ErlangSourceBuilderPosition::DocAttribute 2891 | ErlangSourceBuilderPosition::UnaryOperator { .. } 2892 | ErlangSourceBuilderPosition::Case { .. } 2893 | ErlangSourceBuilderPosition::BinaryOperator { .. } 2894 | ErlangSourceBuilderPosition::CaseClause { .. } 2895 | ErlangSourceBuilderPosition::Map { .. } 2896 | ErlangSourceBuilderPosition::MapField { .. } 2897 | ErlangSourceBuilderPosition::RecordField { 2898 expected: ExpectedRecordFieldItem::Name, 2899 } 2900 | ErlangSourceBuilderPosition::MatchOperator { 2901 expected: ExpectedMatchSide::Expression, 2902 } 2903 | ErlangSourceBuilderPosition::RecordAttribute { .. } 2904 | ErlangSourceBuilderPosition::TypeSpec { 2905 expected: TypeSpecExpectedItem::TypeSpecIsOver, 2906 } 2907 | ErlangSourceBuilderPosition::MatchOperator { 2908 expected: ExpectedMatchSide::Pattern, 2909 } 2910 | ErlangSourceBuilderPosition::MatchPattern { .. } 2911 | ErlangSourceBuilderPosition::TuplePattern { .. } => { 2912 invalid_code_for_position!(self, "type") 2913 } 2914 } 2915 } 2916 2917 /// This has to be called before generating any pattern! 2918 /// This allows the code generator to: 2919 /// - check for inconsistencies and panic (for example if we're generating 2920 /// patterns in the wrong place). 2921 /// - update the current context. 2922 /// - add all the code that needs to go before this type we're about 2923 /// to generate, based on the current context. 2924 /// 2925 fn new_pattern(&mut self) { 2926 self.pop_leftover_items(); 2927 let Some(position) = self.position.last_mut() else { 2928 invalid_code_for_position!(self, "pattern"); 2929 }; 2930 2931 match position { 2932 // We're expecting the list's head. We don't have to add 2933 // anything! 2934 ErlangSourceBuilderPosition::List { 2935 kind: ListKind::Pattern, 2936 expected: expected @ ExpectedListItem::First, 2937 } => *expected = ExpectedListItem::Rest, 2938 2939 ErlangSourceBuilderPosition::List { 2940 kind: ListKind::Pattern, 2941 expected: expected @ ExpectedListItem::Rest, 2942 } => { 2943 *expected = ExpectedListItem::ListIsOver; 2944 self.code.push_str(" | ") 2945 } 2946 2947 ErlangSourceBuilderPosition::BitArraySegment { 2948 segment_value_needs_wrapping, 2949 segment_size_needs_wrapping: _, 2950 expected: 2951 expected @ BitArraySegmentExpectedItem::Value { 2952 kind: BitArrayKind::Pattern, 2953 }, 2954 } => { 2955 if *segment_value_needs_wrapping { 2956 self.code.push('('); 2957 } 2958 *expected = BitArraySegmentExpectedItem::Size 2959 } 2960 2961 // We were waiting for the pattern to be generated, now we're done 2962 // and can start generating an expression for the right-hand side. 2963 ErlangSourceBuilderPosition::MatchOperator { 2964 expected: expected @ ExpectedMatchSide::Pattern, 2965 } => { 2966 *expected = ExpectedMatchSide::Expression; 2967 } 2968 2969 // We were waiting for the pattern and a pattern has been generated. 2970 // We don't change this ourselves since the pattern has to be closed 2971 // explicitly calling `end_clause_pattern`. 2972 // We don't have to do anything here! 2973 ErlangSourceBuilderPosition::CaseClause { 2974 expected: ExpectedCaseClauseItem::Pattern, 2975 } => (), 2976 ErlangSourceBuilderPosition::TuplePattern { first } => { 2977 if *first { 2978 *first = false; 2979 } else { 2980 self.code.push_str(", ") 2981 } 2982 } 2983 ErlangSourceBuilderPosition::MatchPattern { expected } => match expected { 2984 ExpectedMatchPatternSide::Left => *expected = ExpectedMatchPatternSide::Right, 2985 // The right hand side is about to be generated so we have to 2986 // push the ` = ` to separate it from the left hand side, and we 2987 // can remove this position since the match pattern has now been 2988 // completed. 2989 ExpectedMatchPatternSide::Right => { 2990 self.code.push_str(" = "); 2991 self.position.pop(); 2992 } 2993 }, 2994 2995 ErlangSourceBuilderPosition::FunctionCall { .. } 2996 | ErlangSourceBuilderPosition::Block { .. } 2997 | ErlangSourceBuilderPosition::FunctionStatement { .. } 2998 | ErlangSourceBuilderPosition::AnonymousFunctionStatement { .. } 2999 | ErlangSourceBuilderPosition::List { 3000 kind: ListKind::Expression, 3001 .. 3002 } 3003 | ErlangSourceBuilderPosition::BitArray { .. } 3004 | ErlangSourceBuilderPosition::BitArraySegment { 3005 expected: 3006 BitArraySegmentExpectedItem::Size 3007 | BitArraySegmentExpectedItem::Specifiers 3008 | BitArraySegmentExpectedItem::Value { 3009 kind: BitArrayKind::Expression, 3010 }, 3011 .. 3012 } 3013 | ErlangSourceBuilderPosition::UnaryOperator { .. } 3014 | ErlangSourceBuilderPosition::BinaryOperator { .. } 3015 | ErlangSourceBuilderPosition::Case { .. } 3016 | ErlangSourceBuilderPosition::Map { .. } 3017 | ErlangSourceBuilderPosition::MapField { .. } 3018 | ErlangSourceBuilderPosition::MatchOperator { 3019 expected: ExpectedMatchSide::Expression, 3020 } 3021 | ErlangSourceBuilderPosition::Tuple { .. } 3022 | ErlangSourceBuilderPosition::FunctionType { .. } 3023 | ErlangSourceBuilderPosition::FunctionSpec 3024 | ErlangSourceBuilderPosition::TypeSpec { .. } 3025 | ErlangSourceBuilderPosition::NamedType { .. } 3026 | ErlangSourceBuilderPosition::UnionType { .. } 3027 | ErlangSourceBuilderPosition::TupleType { .. } 3028 | ErlangSourceBuilderPosition::RecordField { .. } 3029 | ErlangSourceBuilderPosition::DocAttribute 3030 | ErlangSourceBuilderPosition::RecordAttribute { .. } 3031 | ErlangSourceBuilderPosition::List { 3032 kind: ListKind::Pattern, 3033 expected: ExpectedListItem::ListIsOver, 3034 } 3035 | ErlangSourceBuilderPosition::CaseClause { 3036 expected: ExpectedCaseClauseItem::Guards { .. }, 3037 } 3038 | ErlangSourceBuilderPosition::CaseClause { 3039 expected: ExpectedCaseClauseItem::Body { .. }, 3040 } => { 3041 invalid_code_for_position!(self, "pattern"); 3042 } 3043 } 3044 } 3045 3046 fn close_currently_open_item(&mut self) { 3047 self.pop_leftover_items(); 3048 let Some(position) = self.position.pop() else { 3049 return; 3050 }; 3051 3052 match position { 3053 // When we're done generating statements for a function we need to 3054 // add one final `.` to the last statement. Then we also want to 3055 // add an empty line to make our code breath a bit better. 3056 ErlangSourceBuilderPosition::FunctionStatement { .. } => { 3057 self.indentation -= INDENT; 3058 self.code.push_str(".\n") 3059 } 3060 // When we're done generating statements for an anonymous function 3061 // we need to add the closing `end` after the last statement on a 3062 // new line. 3063 ErlangSourceBuilderPosition::AnonymousFunctionStatement { .. } => { 3064 self.indentation -= INDENT; 3065 self.code.push('\n'); 3066 self.push_indentation(); 3067 self.code.push_str("end") 3068 } 3069 // When we're done generating statements for a block we need to add 3070 // the closing `end`, and reduce the nesting level. 3071 ErlangSourceBuilderPosition::Block { .. } => { 3072 self.indentation -= INDENT; 3073 self.code.push('\n'); 3074 self.push_indentation(); 3075 self.code.push_str("end"); 3076 } 3077 // When we're done generating code for a function spec we want to 3078 // add a `.` and go to a new line so we can start generating the 3079 // function itself. 3080 ErlangSourceBuilderPosition::FunctionSpec => self.code.push_str(".\n"), 3081 // When we're done generating the arguments of a function we need 3082 // to add the closed parentheses for the function call! 3083 ErlangSourceBuilderPosition::FunctionCall { 3084 expected: ExpectedCallItem::Arguments { first }, 3085 called_item_needs_wrapping, 3086 } => { 3087 if called_item_needs_wrapping { 3088 self.code.push(')') 3089 } 3090 3091 // If the function is closed with no arguments being generated 3092 // then we will need to add both the open and closed 3093 // parentheses. That's because the open paren is added when the 3094 // first argument is generated. 3095 if first { 3096 self.code.push_str("()") 3097 } else { 3098 self.code.push(')') 3099 } 3100 } 3101 3102 // When we're done generating the items of a tuple we need 3103 // to add the closed curly brace to actually close the tuple. 3104 ErlangSourceBuilderPosition::TupleType { .. } 3105 | ErlangSourceBuilderPosition::Tuple { .. } 3106 | ErlangSourceBuilderPosition::TuplePattern { .. } => self.code.push('}'), 3107 // When we're done generating a bit array we can add its closing 3108 // element. 3109 ErlangSourceBuilderPosition::BitArray { .. } => self.code.push_str(">>"), 3110 3111 // When the function type arguments are over we add what we need for 3112 // the return type. 3113 ErlangSourceBuilderPosition::FunctionType { 3114 expected: ExpectedFunctionTypeItem::Arguments { .. }, 3115 needs_wrapping, 3116 } => { 3117 // After popping the argument, we now need to wait for the 3118 // return type! 3119 self.position 3120 .push(ErlangSourceBuilderPosition::FunctionType { 3121 expected: ExpectedFunctionTypeItem::ReturnType, 3122 needs_wrapping, 3123 }); 3124 self.code.push_str(") -> ") 3125 } 3126 // When a named type is over we need to add the closing parentheses. 3127 ErlangSourceBuilderPosition::NamedType { .. } => self.code.push(')'), 3128 // If we close a function type we need to check what the current 3129 // state is. If we were generating this for a type spec we're done. 3130 // But if we were generating this as a type inside another we need to 3131 // add one further parentheses to close the `fun(...)` around the 3132 // function type. 3133 // 3134 // ```erl 3135 // % in a spec annotation it simply comes after the function name: 3136 // -spec wibble () -> integer(). 3137 // wibble() -> 11. 3138 // 3139 // % but inside another type it has to be wrapped in `fun(...)`: 3140 // -spec wobble () -> fun(() -> integer()) 3141 // % ^ We're adding this bit here! 3142 // wobble() -> fun wibble/0. 3143 // ``` 3144 ErlangSourceBuilderPosition::FunctionType { 3145 expected: ExpectedFunctionTypeItem::ReturnType, 3146 needs_wrapping, 3147 } => { 3148 if needs_wrapping { 3149 self.code.push(')') 3150 } 3151 } 3152 // There's nothing left to do when a union type ends. 3153 ErlangSourceBuilderPosition::UnionType { .. } => (), 3154 // When a doc attribute is closed we need to add the closed 3155 // parentheses and a newline. 3156 ErlangSourceBuilderPosition::DocAttribute => self.code.push_str(").\n"), 3157 // When a case expression is over, we need to add the closing `end`. 3158 ErlangSourceBuilderPosition::Case { 3159 expected: ExpectedCaseItem::Branches { .. }, 3160 } => { 3161 self.indentation -= INDENT; 3162 self.code.push('\n'); 3163 self.push_indentation(); 3164 self.code.push_str("end"); 3165 } 3166 3167 ErlangSourceBuilderPosition::CaseClause { expected } => match expected { 3168 ExpectedCaseClauseItem::Pattern => (), 3169 // When the guards of a case clause are over we need to add the 3170 // arrow before the body is generated. 3171 ExpectedCaseClauseItem::Guards { .. } => self.code.push_str(" ->"), 3172 ExpectedCaseClauseItem::Body { .. } => { 3173 self.indentation -= INDENT; 3174 } 3175 }, 3176 // We're done with a map, we can add the closed parentheses and 3177 // reduce nesting. 3178 ErlangSourceBuilderPosition::Map { .. } => { 3179 self.indentation -= INDENT; 3180 self.code.push('\n'); 3181 self.push_indentation(); 3182 self.code.push('}'); 3183 } 3184 ErlangSourceBuilderPosition::RecordAttribute { .. } => { 3185 self.indentation -= INDENT; 3186 self.code.push('\n'); 3187 self.push_indentation(); 3188 self.code.push_str("})."); 3189 } 3190 3191 ErlangSourceBuilderPosition::MapField { .. } 3192 | ErlangSourceBuilderPosition::RecordField { .. } 3193 | ErlangSourceBuilderPosition::MatchPattern { .. } 3194 | ErlangSourceBuilderPosition::UnaryOperator { .. } 3195 | ErlangSourceBuilderPosition::List { .. } 3196 | ErlangSourceBuilderPosition::BinaryOperator { .. } 3197 | ErlangSourceBuilderPosition::MatchOperator { .. } 3198 | ErlangSourceBuilderPosition::TypeSpec { .. } 3199 | ErlangSourceBuilderPosition::BitArraySegment { .. } 3200 | ErlangSourceBuilderPosition::Case { 3201 expected: ExpectedCaseItem::Subject, 3202 } 3203 | ErlangSourceBuilderPosition::FunctionCall { 3204 // If we try and close a function for which no called item was 3205 // generated, then that's an error! 3206 expected: ExpectedCallItem::FunctionToBeCalled, 3207 .. 3208 } => invalid_code_for_position!(self, "pop leftover item"), 3209 } 3210 } 3211 3212 /// Given the content of something that has to end up inside an Erlang 3213 /// literal string `~"..."` this escapes its content based on 3214 /// position-specific rules: depending where we will be putting the string 3215 /// (and so depending where it comes from) it might need different things to 3216 /// be escaped! 3217 /// 3218 /// For example, if we're given the content of a literal Gleam string, we 3219 /// know that some charachters like double quotes are going to be escaped 3220 /// already: 3221 /// 3222 /// ```gleam 3223 /// let some_gleam_string = "wibble\"wobble" 3224 /// ``` 3225 /// 3226 /// After all, if those weren't escaped our Gleam program would have a 3227 /// syntax error and not compile! 3228 /// 3229 /// However, there's other pieces of syntax that might be turned into 3230 /// literal Erlang strings: doc comments. In that case those can contain 3231 /// unescaped characters. For example: 3232 /// 3233 /// ```gleam 3234 /// /// This is a doc comment that has unescaped double quotes "" 3235 /// ``` 3236 /// 3237 /// If we were to just take that comment's content and put it in an Erlang 3238 /// string with no escaping that would produce invalid code! 3239 /// 3240 fn escape_string_content(&self, content: &str) -> String { 3241 let position = self 3242 .position 3243 .last() 3244 .expect("escaping string in the top level scope"); 3245 3246 match position { 3247 ErlangSourceBuilderPosition::FunctionSpec 3248 | ErlangSourceBuilderPosition::TypeSpec { .. } 3249 | ErlangSourceBuilderPosition::FunctionType { .. } 3250 | ErlangSourceBuilderPosition::NamedType { .. } 3251 | ErlangSourceBuilderPosition::UnionType { .. } 3252 | ErlangSourceBuilderPosition::RecordAttribute { .. } 3253 | ErlangSourceBuilderPosition::TupleType { .. } => { 3254 invalid_code_for_position!(self, "escaping string") 3255 } 3256 3257 ErlangSourceBuilderPosition::FunctionCall { .. } 3258 | ErlangSourceBuilderPosition::FunctionStatement { .. } 3259 | ErlangSourceBuilderPosition::AnonymousFunctionStatement { .. } 3260 | ErlangSourceBuilderPosition::List { .. } 3261 | ErlangSourceBuilderPosition::UnaryOperator { .. } 3262 | ErlangSourceBuilderPosition::Tuple { .. } 3263 | ErlangSourceBuilderPosition::TuplePattern { .. } 3264 | ErlangSourceBuilderPosition::BitArray { .. } 3265 | ErlangSourceBuilderPosition::BitArraySegment { .. } 3266 | ErlangSourceBuilderPosition::Block { .. } 3267 | ErlangSourceBuilderPosition::BinaryOperator { .. } 3268 | ErlangSourceBuilderPosition::Case { .. } 3269 | ErlangSourceBuilderPosition::CaseClause { .. } 3270 | ErlangSourceBuilderPosition::Map { .. } 3271 | ErlangSourceBuilderPosition::MapField { .. } 3272 | ErlangSourceBuilderPosition::MatchPattern { .. } 3273 | ErlangSourceBuilderPosition::RecordField { .. } 3274 | ErlangSourceBuilderPosition::MatchOperator { .. } => { 3275 // When pretty printing we want the resulting code to be regular 3276 // executable Erlang code. 3277 // If we're tasked with escaping the content of a literal string 3278 // expression we need to turn Gleam's `\u` sequences into 3279 // Erlang's `\x`. 3280 UNICODE_ESCAPE_SEQUENCE_PATTERN 3281 .get_or_init(|| { 3282 Regex::new(r#"(\\+)(u)"#) 3283 .expect("Unicode escape sequence regex cannot be constructed") 3284 }) 3285 // `\\u`-s should not be affected, so that "\\u..." is not converted to 3286 // "\\x...". That's why capturing groups is used to exclude cases that 3287 // shouldn't be replaced. 3288 .replace_all(content, |caps: &regex::Captures<'_>| { 3289 let slashes = caps.get(1).map_or("", |match_| match_.as_str()); 3290 if slashes.len().is_multiple_of(2) { 3291 format!("{slashes}u") 3292 } else { 3293 format!("{slashes}x") 3294 } 3295 }) 3296 .into() 3297 } 3298 3299 ErlangSourceBuilderPosition::DocAttribute => { 3300 // Escaping strings generated inside doc attributes is a little 3301 // different: since their content doesn't come from a Gleam 3302 // literal string but freeform text, their content might contain 3303 // all sorts of unescaped characters. 3304 content.replace("\\", "\\\\").replace("\"", "\\\"") 3305 } 3306 } 3307 } 3308 3309 #[must_use] 3310 fn new_bit_array_segment(&mut self) -> BitArrayKind { 3311 self.pop_leftover_items(); 3312 let Some(ErlangSourceBuilderPosition::BitArray { first, kind }) = self.position.last_mut() 3313 else { 3314 invalid_code_for_position!(self, "bit array segment") 3315 }; 3316 3317 if *first { 3318 *first = false; 3319 } else { 3320 self.code.push_str(", "); 3321 } 3322 3323 *kind 3324 } 3325 3326 fn new_case_clause(&mut self) { 3327 self.pop_leftover_items(); 3328 let Some(ErlangSourceBuilderPosition::Case { 3329 expected: ExpectedCaseItem::Branches { first }, 3330 }) = self.position.last_mut() 3331 else { 3332 invalid_code_for_position!(self, "case clause") 3333 }; 3334 3335 if *first { 3336 *first = false; 3337 self.code.push_str(" of\n"); 3338 self.indentation += INDENT; 3339 } else { 3340 self.code.push_str(";\n\n"); 3341 } 3342 self.code.push_str(&" ".repeat(self.indentation)) 3343 } 3344 3345 fn new_map_field(&mut self) { 3346 self.pop_leftover_items(); 3347 let Some(ErlangSourceBuilderPosition::Map { first }) = self.position.last_mut() else { 3348 invalid_code_for_position!(self, "map field"); 3349 }; 3350 3351 if *first { 3352 *first = false; 3353 self.code.push('\n'); 3354 } else { 3355 self.code.push_str(",\n") 3356 } 3357 self.code.push_str(&" ".repeat(self.indentation)) 3358 } 3359 3360 /// You can call this before generating any expression (before the 3361 /// `new_expression` call) if we can skip wrapping it in parentheses when it 3362 /// appears as a bitstring segment value. 3363 /// This is opt-out rather than opt-in: it's always safe to wrap everything, 3364 /// but it leads to slightly uglier code for some values like bare integers. 3365 /// For example: 3366 /// 3367 /// ```erl 3368 /// <<(1)/signed>> 3369 /// % ^ ^ Those are not needed at all! 3370 /// ``` 3371 /// 3372 /// So for those values that you know are safe and would look better you can 3373 /// use this function. 3374 /// 3375 fn do_not_wrap_if_segment_value_or_size(&mut self) { 3376 self.pop_leftover_items(); 3377 // If we're about to generate a bit array segment value, or a size, 3378 // then we can skip the wrapping, otherwise this is not needed at all! 3379 match self.position.last_mut() { 3380 Some(ErlangSourceBuilderPosition::BitArraySegment { 3381 segment_value_needs_wrapping, 3382 expected: BitArraySegmentExpectedItem::Value { .. }, 3383 .. 3384 }) => *segment_value_needs_wrapping = false, 3385 Some(ErlangSourceBuilderPosition::BitArraySegment { 3386 segment_size_needs_wrapping, 3387 expected: BitArraySegmentExpectedItem::Size, 3388 .. 3389 }) => *segment_size_needs_wrapping = false, 3390 _ => (), 3391 } 3392 } 3393 3394 /// This can be used to output the content of a string wether that is a 3395 /// pattern or an expression! 3396 fn do_print_string_content(&mut self, content: &str) { 3397 let content = self.escape_string_content(content); 3398 // If we're generating a string as a bit array segment value we want to 3399 // output slightly different code: rather than a bit array we want to 3400 // output a regular string with no modifiers which are going to be added 3401 // later as the segment is created 3402 if let Some(ErlangSourceBuilderPosition::BitArraySegment { 3403 // the call to `new_expression` at the beginning is going to advance 3404 // the state to expect the `::Size`, that means the code we are 3405 // outputting now was expected to be the the `::Value` of the bit 3406 // array segment! 3407 // We can't move the `new_expression` call down, that _must_ be the 3408 // first thing we do, so we check to see if the size if the next 3409 // thing we're expecting to see. 3410 expected: BitArraySegmentExpectedItem::Size, 3411 segment_value_needs_wrapping: _, 3412 segment_size_needs_wrapping: _, 3413 }) = self.position.last() 3414 { 3415 self.code.push('"'); 3416 self.code.push_str(&content); 3417 self.code.push('"'); 3418 } else { 3419 self.code.push_str("~\""); 3420 self.code.push_str(&content); 3421 self.code.push('"'); 3422 } 3423 } 3424 3425 fn cons_list_of_kind(&mut self, list_kind: ListKind) { 3426 self.pop_leftover_items(); 3427 match self.position.last_mut() { 3428 // If we were expecting the rest of a list and we generate a new 3429 // cons cell we can keep adding commas to separate items: we want 3430 // to show `[1, 2, 3]` rather than `[1 | [2 | [3 | []]]]` 3431 Some(ErlangSourceBuilderPosition::List { 3432 kind, 3433 expected: expected @ ExpectedListItem::Rest, 3434 }) if *kind == list_kind => { 3435 *expected = ExpectedListItem::First; 3436 self.code.push_str(", "); 3437 } 3438 // Otherwise we have to properly start a new list: push the `[` and 3439 // wait for the first item to be generated. 3440 Some(_) | None => { 3441 match list_kind { 3442 ListKind::Pattern => self.new_pattern(), 3443 ListKind::Expression => self.new_expression(), 3444 } 3445 self.code.push('['); 3446 self.position.push(ErlangSourceBuilderPosition::List { 3447 kind: list_kind, 3448 expected: ExpectedListItem::First, 3449 }); 3450 } 3451 } 3452 } 3453 3454 fn empty_list_of_kind(&mut self, list_kind: ListKind) { 3455 self.pop_leftover_items(); 3456 match self.position.last_mut() { 3457 // If we were building a cons list and were expecting the end of the 3458 // list then we have to special case this: we don't want to render 3459 // it as: `[1, 2 | []]`, but as `[1, 2]`. 3460 Some(ErlangSourceBuilderPosition::List { 3461 kind, 3462 expected: ExpectedListItem::Rest, 3463 }) if *kind == list_kind => { 3464 // Crucially we don't want to call `new_expression` here: we 3465 // don't want the default handling. 3466 self.code.push(']'); 3467 // The list is over, so we pop it away. 3468 self.position.pop(); 3469 } 3470 Some(_) | None => { 3471 match list_kind { 3472 ListKind::Pattern => self.new_pattern(), 3473 ListKind::Expression => self.new_expression(), 3474 } 3475 self.code.push_str("[]"); 3476 } 3477 } 3478 } 3479 3480 /// This has to be called before any `new_x` function. This takes care of 3481 /// removing all leftover items that do not self close. 3482 /// 3483 /// That happens when there's some node that requires code to be pushed 3484 /// _after_ it is over and it is not closed manually with a `end_x` 3485 /// function. 3486 fn pop_leftover_items(&mut self) { 3487 let Some(position) = self.position.last() else { 3488 return; 3489 }; 3490 3491 match position { 3492 ErlangSourceBuilderPosition::TypeSpec { 3493 expected: TypeSpecExpectedItem::TypeSpecIsOver, 3494 } => { 3495 self.code.push_str(".\n"); 3496 self.position.pop(); 3497 self.pop_leftover_items(); 3498 } 3499 3500 // The expression we're generating is preceded by a list 3501 // that has been closed. Lists are a bit tricky because they 3502 // are built as a list of cons cells, so we can't really 3503 // tell when a list is over until we get to the next 3504 // expression. 3505 ErlangSourceBuilderPosition::List { 3506 expected: ExpectedListItem::ListIsOver, 3507 .. 3508 } => { 3509 self.code.push(']'); 3510 // We remove this leftover list... 3511 self.position.pop(); 3512 // ...and then we can keep going until there's no leftover 3513 // items left. 3514 self.pop_leftover_items(); 3515 } 3516 3517 // Like with lists, we don't really know when a binary operator is 3518 // over until we get to the following operation (or we try closing 3519 // the current item and notice there's a closed operator left). 3520 // Also, just like lists, we might still need to add some 3521 // parentheses _after_ the operator is over. 3522 ErlangSourceBuilderPosition::BinaryOperator { 3523 expected: ExpectedBinaryOperatorSide::BinaryOperatorIsOver, 3524 needs_wrapping, 3525 .. 3526 } => { 3527 // If needed add the closing parentheses... 3528 if *needs_wrapping { 3529 self.code.push(')'); 3530 } 3531 // ...we remove this leftover binary operator... 3532 self.position.pop(); 3533 // ...and then we can keep going until there's no leftover items 3534 // left. 3535 self.pop_leftover_items(); 3536 } 3537 3538 // All of these items are not leftovers. They are either still open, 3539 // require manual closing, or things that don't need closing at all! 3540 ErlangSourceBuilderPosition::NamedType { .. } 3541 | ErlangSourceBuilderPosition::UnionType { .. } 3542 | ErlangSourceBuilderPosition::TupleType { .. } 3543 | ErlangSourceBuilderPosition::FunctionStatement { .. } 3544 | ErlangSourceBuilderPosition::AnonymousFunctionStatement { .. } 3545 | ErlangSourceBuilderPosition::DocAttribute 3546 | ErlangSourceBuilderPosition::FunctionSpec 3547 | ErlangSourceBuilderPosition::Tuple { .. } 3548 | ErlangSourceBuilderPosition::TuplePattern { .. } 3549 | ErlangSourceBuilderPosition::BitArray { .. } 3550 | ErlangSourceBuilderPosition::Map { .. } 3551 | ErlangSourceBuilderPosition::Block { .. } 3552 | ErlangSourceBuilderPosition::UnaryOperator { .. } 3553 | ErlangSourceBuilderPosition::FunctionType { 3554 expected: 3555 ExpectedFunctionTypeItem::Arguments { .. } | ExpectedFunctionTypeItem::ReturnType, 3556 .. 3557 } 3558 | ErlangSourceBuilderPosition::TypeSpec { 3559 expected: TypeSpecExpectedItem::TypeDefinition, 3560 } 3561 | ErlangSourceBuilderPosition::MapField { 3562 expected: MapFieldExpectedItem::Key | MapFieldExpectedItem::Value, 3563 } 3564 | ErlangSourceBuilderPosition::List { 3565 expected: ExpectedListItem::First | ExpectedListItem::Rest, 3566 .. 3567 } 3568 | ErlangSourceBuilderPosition::BitArraySegment { 3569 expected: 3570 BitArraySegmentExpectedItem::Size 3571 | BitArraySegmentExpectedItem::Specifiers 3572 | BitArraySegmentExpectedItem::Value { .. }, 3573 .. 3574 } 3575 | ErlangSourceBuilderPosition::FunctionCall { 3576 expected: ExpectedCallItem::Arguments { .. } | ExpectedCallItem::FunctionToBeCalled, 3577 .. 3578 } 3579 | ErlangSourceBuilderPosition::MatchPattern { 3580 expected: ExpectedMatchPatternSide::Left | ExpectedMatchPatternSide::Right, 3581 } 3582 | ErlangSourceBuilderPosition::Case { 3583 expected: ExpectedCaseItem::Subject | ExpectedCaseItem::Branches { .. }, 3584 } 3585 | ErlangSourceBuilderPosition::CaseClause { 3586 expected: 3587 ExpectedCaseClauseItem::Pattern 3588 | ExpectedCaseClauseItem::Guards { .. } 3589 | ExpectedCaseClauseItem::Body { .. }, 3590 } 3591 | ErlangSourceBuilderPosition::BinaryOperator { 3592 expected: ExpectedBinaryOperatorSide::Left | ExpectedBinaryOperatorSide::Right, 3593 .. 3594 } 3595 | ErlangSourceBuilderPosition::RecordAttribute { .. } 3596 | ErlangSourceBuilderPosition::MatchOperator { 3597 expected: ExpectedMatchSide::Expression | ExpectedMatchSide::Pattern, 3598 } 3599 | ErlangSourceBuilderPosition::RecordField { .. } => (), 3600 } 3601 } 3602 3603 fn new_record_field(&mut self) { 3604 self.pop_leftover_items(); 3605 let Some(ErlangSourceBuilderPosition::RecordAttribute { first }) = self.position.last_mut() 3606 else { 3607 panic!("tried generating record field outside of record attribute"); 3608 }; 3609 3610 if *first { 3611 *first = false; 3612 } else { 3613 self.code.push(','); 3614 } 3615 self.code.push('\n'); 3616 self.push_indentation(); 3617 } 3618 3619 fn push_indentation(&mut self) { 3620 for _ in 0..self.indentation { 3621 self.code.push(' '); 3622 } 3623 } 3624 3625 /// This produces a pretty printed error message including the current 3626 /// position. 3627 fn error_with_position(&self, expected: &str) -> String { 3628 let position = self.position.last(); 3629 format!("tried {expected}, position: {position:?}") 3630 } 3631} 3632 3633/// This wraps an atom name in between single quotes if needed. 3634fn quote_atom_name(name: &str) -> String { 3635 if is_erlang_reserved_word(name) { 3636 // Escape because of keyword collision 3637 format!("'{name}'") 3638 } else if atom_name_regex().is_match(name) { 3639 String::from(name) 3640 } else { 3641 // Escape because of characters contained 3642 format!("'{name}'") 3643 } 3644} 3645 3646static ATOM_NAME_REGEX: OnceLock<Regex> = OnceLock::new(); 3647 3648fn atom_name_regex() -> &'static Regex { 3649 ATOM_NAME_REGEX.get_or_init(|| Regex::new(r"^[a-z][a-z0-9_@]*$").expect("atom RE regex")) 3650} 3651 3652fn is_erlang_reserved_word(name: &str) -> bool { 3653 matches!( 3654 name, 3655 "!" | "receive" 3656 | "bnot" 3657 | "div" 3658 | "rem" 3659 | "band" 3660 | "bor" 3661 | "bxor" 3662 | "bsl" 3663 | "bsr" 3664 | "not" 3665 | "and" 3666 | "or" 3667 | "xor" 3668 | "orelse" 3669 | "andalso" 3670 | "when" 3671 | "end" 3672 | "fun" 3673 | "try" 3674 | "catch" 3675 | "after" 3676 | "begin" 3677 | "let" 3678 | "query" 3679 | "cond" 3680 | "if" 3681 | "of" 3682 | "case" 3683 | "maybe" 3684 | "else" 3685 ) 3686}