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