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