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