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