diff --git a/Cargo.lock b/Cargo.lock index e887677b8..c6824f3ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -864,7 +864,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "erlang-abstract-format" +name = "erlang-generation" version = "1.0.0" dependencies = [ "ecow", @@ -1245,7 +1245,7 @@ dependencies = [ "debug-ignore", "dirs-next", "ecow", - "erlang-abstract-format", + "erlang-generation", "flate2", "futures", "gen-lsp-types", diff --git a/Cargo.toml b/Cargo.toml index b941fb9a1..7bd5eba5e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ members = [ "pretty-arena", "format", "erlang-term-format", - "erlang-abstract-format", + "erlang-generation", ] # common dependencies @@ -88,4 +88,3 @@ num-traits = "0.2.19" unicode-segmentation = "1.13.2" # Checksums xxhash-rust = { version = "0", features = ["xxh3"] } - diff --git a/compiler-core/Cargo.toml b/compiler-core/Cargo.toml index d875fc9f1..a3b494718 100644 --- a/compiler-core/Cargo.toml +++ b/compiler-core/Cargo.toml @@ -60,7 +60,7 @@ flate2.workspace = true futures.workspace = true hexpm = { path = "../hexpm" } pretty-arena = { path = "../pretty-arena" } -erlang-abstract-format = { path = "../erlang-abstract-format" } +erlang-generation = { path = "../erlang-generation" } http.workspace = true im.workspace = true itertools.workspace = true diff --git a/compiler-core/src/erlang.rs b/compiler-core/src/erlang.rs index ebedb2573..a38f77a15 100644 --- a/compiler-core/src/erlang.rs +++ b/compiler-core/src/erlang.rs @@ -19,7 +19,9 @@ use crate::{ }; use camino::Utf8Path; use ecow::{EcoString, eco_format}; -use erlang_abstract_format::{BitArraySegmentSpecifier, Eaf, ErlangModuleName, PrettyEaf}; +use erlang_generation::{ + BitArraySegmentSpecifier, ErlangBuilder, ErlangModuleName, ErlangSourceBuilder, +}; use itertools::Itertools; use num_bigint::BigInt; use num_traits::Signed; @@ -32,10 +34,10 @@ use std::{collections::HashMap, ops::Deref, sync::Arc}; #[must_use] struct RuntimeError { /// This is the map that is going to be thrown by the `erlang:error` call. - error_map: erlang_abstract_format::Map, + error_map: erlang_generation::Map, /// This is the call to `erlang:error` that will throw the error, with the /// map as an argument. - erlang_error_call: erlang_abstract_format::Call, + erlang_error_call: erlang_generation::Call, } /// Represents all the different kind of runtime errors that Gleam can raise. @@ -211,7 +213,7 @@ impl<'a> Generator<'a> { } } - fn module_document(&mut self, eaf: &mut impl Eaf) { + fn module_document(&mut self, builder: &mut impl ErlangBuilder) { // We need to know which private functions are referenced in importable // constants so that we can export them anyway in the generated Erlang. // This is because otherwise when the constant is used in another module it @@ -221,7 +223,7 @@ impl<'a> Generator<'a> { // We add a `-compile` attribute at the top of each module to instruct // the Erlang compiler. - eaf.compile_attribute([ + builder.compile_attribute([ "no_auto_import", "nowarn_ignored", "nowarn_unused_vars", @@ -232,49 +234,53 @@ impl<'a> Generator<'a> { // We then need to add an `-export` attribute for all the module's // public functions. - eaf.export_attribute( + builder.export_attribute( (self.module.definitions.functions.iter()) .filter_map(|function| function_export(function, &overridden_publicity)), ); // We do the same but with types. - eaf.export_type_attribute(self.module.definitions.custom_types.iter().map(type_export)); + builder.export_type_attribute(self.module.definitions.custom_types.iter().map(type_export)); // We also add a `-module_doc` comment at the beginning of the module // with its documentation. - self.module_documentation(eaf); + self.module_documentation(builder); // Then we generate `-type` definitions for the module's types. for custom_type in &self.module.definitions.custom_types { - self.type_definition(eaf, custom_type); + self.type_definition(builder, custom_type); } // And finally generate all the functions that the module defined. for function in &self.module.definitions.functions { - FunctionGenerator::new(function, self).module_function(eaf, function); + FunctionGenerator::new(function, self).module_function(builder, function); } } - fn module_documentation(&mut self, eaf: &mut impl Eaf) { + fn module_documentation(&mut self, builder: &mut impl ErlangBuilder) { if self.module.type_info.is_internal { // The module is internal so we need to add a `-moduledoc(false).` // attribute to make sure its documentation is hidden. - let doc = eaf.start_moduledoc_attribute(); - eaf.atom("false"); - eaf.end_doc_attribute(doc); + let doc = builder.start_moduledoc_attribute(); + builder.atom("false"); + builder.end_doc_attribute(doc); } else if self.module.documentation.is_empty() { // The module is not internal, but it has no docs. // We don't have to do anything. } else { // The module has some documentation that we're going to include // with a `-moduledoc` attribute. - let doc = eaf.start_moduledoc_attribute(); + let doc = builder.start_moduledoc_attribute(); let documentation = &self.module.documentation.iter().join("\n"); - eaf.string(documentation); - eaf.end_doc_attribute(doc); + builder.string(documentation); + builder.end_doc_attribute(doc); }; } - fn type_definition(&self, eaf: &mut impl Eaf, custom_type: &TypedCustomType) { + fn type_definition( + &self, + builder: &mut impl ErlangBuilder, + custom_type: &TypedCustomType, + ) { let TypedCustomType { name, constructors, @@ -287,7 +293,7 @@ impl<'a> Generator<'a> { let name = erl_safe_type_name(to_snake_case(name)); // We start the type spec. - eaf.type_spec( + builder.type_spec( *opaque, &name, typed_parameters @@ -307,42 +313,43 @@ impl<'a> Generator<'a> { // it corresponds to in Erlang. // In that case all type variables are phantom type variables! ([], _) if let Some((module, type_name, _)) = external_erlang => { - let type_ = eaf.start_remote_named_type(ErlangModuleName::new(&module), type_name); + let type_ = + builder.start_remote_named_type(ErlangModuleName::new(&module), type_name); for type_variable in phantom_type_variables { - eaf.type_variable(&type_variable); + builder.type_variable(&type_variable); } - eaf.end_named_type(type_); + builder.end_named_type(type_); } // This is an external type with no external annotation and no // phantom type variables. It is just `any()`. ([], false) => { - let any = eaf.start_named_type("any"); - eaf.end_named_type(any); + let any = builder.start_named_type("any"); + builder.end_named_type(any); } // This is an external type with no external annotation and some // phantom type variables, we need to add an alternative to use // them: `any() | {gleam_phantom, A, B, ...}` ([], true) => { - let union = eaf.start_union_type(); - let any = eaf.start_named_type("any"); - eaf.end_named_type(any); - self.phantom_type(eaf, phantom_type_variables); - eaf.end_union_type(union); + let union = builder.start_union_type(); + let any = builder.start_named_type("any"); + builder.end_named_type(any); + self.phantom_type(builder, phantom_type_variables); + builder.end_union_type(union); } // This is an external type with a single constructor, no need to // make it a union. - ([constructor], false) => self.constructor_type(eaf, constructor), + ([constructor], false) => self.constructor_type(builder, constructor), // This is an external type with multiple constructors, we have to // turn it into a union! (constructors, has_phantom_type_variables) => { - let union = eaf.start_union_type(); + let union = builder.start_union_type(); for constructor in constructors { - self.constructor_type(eaf, constructor); + self.constructor_type(builder, constructor); } if has_phantom_type_variables { - self.phantom_type(eaf, phantom_type_variables); + self.phantom_type(builder, phantom_type_variables); } - eaf.end_union_type(union); + builder.end_union_type(union); } } } @@ -361,24 +368,24 @@ impl<'a> Generator<'a> { /// fn constructor_type( &self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, constructor: &RecordConstructor>, ) { let constructor_atom = to_snake_case(&constructor.name); if constructor.arguments.is_empty() { // A constructor with no fields becomes a regular atom on the Erlang // target. - eaf.literal_atom_type(&constructor_atom); + builder.literal_atom_type(&constructor_atom); } else { // Othwerwise, it is a tuple tagged with the atom with the // constructor name. let generator = TypeGenerator::new(&self.module.name); - let tuple = eaf.start_tuple_type(); - eaf.literal_atom_type(&constructor_atom); + let tuple = builder.start_tuple_type(); + builder.literal_atom_type(&constructor_atom); for argument in &constructor.arguments { - generator.type_(eaf, &argument.type_); + generator.type_(builder, &argument.type_); } - eaf.end_tuple_type(tuple); + builder.end_tuple_type(tuple); } } @@ -406,15 +413,15 @@ impl<'a> Generator<'a> { /// fn phantom_type( &self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, phantom_type_variables: Vec, ) { - let phantom_tuple = eaf.start_tuple_type(); - eaf.literal_atom_type("gleam_phantom"); + let phantom_tuple = builder.start_tuple_type(); + builder.literal_atom_type("gleam_phantom"); for phantom_type_variable in phantom_type_variables { - eaf.type_variable(&phantom_type_variable); + builder.type_variable(&phantom_type_variable); } - eaf.end_tuple_type(phantom_tuple); + builder.end_tuple_type(phantom_tuple); } } @@ -569,7 +576,11 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { /// if there's no code to be generated at all! /// For example if the function is unused, or if the function is a private /// Erlang external (in which case, it would be inlined instead). - fn module_function(&mut self, eaf: &mut impl Eaf, function: &'a TypedFunction) { + fn module_function( + &mut self, + builder: &mut impl ErlangBuilder, + function: &'a TypedFunction, + ) { // We don't generate any code for unused functions. if self .module_generator @@ -595,14 +606,14 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { let function_name = EcoString::from(escape_erlang_existing_name(self.function_name)); // Then we add the function's documentation and type annotation. - eaf.file_attribute( + builder.file_attribute( &self.module_generator.module_source_path, self.module_generator .line_numbers .line_number(function.location.start), ); - self.function_spec_attribute(eaf, &function_name, function); - self.function_doc_attribute(eaf, function); + self.function_spec_attribute(builder, &function_name, function); + self.function_doc_attribute(builder, function); // Finally we start generating code for the function itself, how we do // it depends if the function is external or not. @@ -612,9 +623,9 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // its statements. None => { let arguments = self.function_arguments_names(&function.arguments, false); - let open_function = eaf.start_function(&function_name, arity, arguments); - self.statement_sequence(eaf, &function.body); - eaf.end_function(open_function); + let open_function = builder.start_function(&function_name, arity, arguments); + self.statement_sequence(builder, &function.body); + builder.end_function(open_function); } // An external function consists of just a remote call being @@ -623,14 +634,15 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { let arguments = self .function_arguments_names(&function.arguments, true) .collect_vec(); - let open_function = eaf.start_function(&function_name, arity, arguments.clone()); - let call = - eaf.start_remote_call(ErlangModuleName::new(&module), external_function_name); + let open_function = + builder.start_function(&function_name, arity, arguments.clone()); + let call = builder + .start_remote_call(ErlangModuleName::new(&module), external_function_name); for argument in arguments { - eaf.variable(&argument); + builder.variable(&argument); } - eaf.end_call(call); - eaf.end_function(open_function); + builder.end_call(call); + builder.end_function(open_function); } } } @@ -639,7 +651,7 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { /// fn function_spec_attribute( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, function_name: &EcoString, function: &'a Function, TypedExpr>, ) { @@ -657,18 +669,22 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { let generator = TypeGenerator::new(module_name).with_var_usages(var_usages); // We can then start generating the function spec. - let spec = eaf.start_function_spec(function_name, function.arguments.len()); - let function_type = eaf.start_function_type(); + let spec = builder.start_function_spec(function_name, function.arguments.len()); + let function_type = builder.start_function_type(); for argument in &function.arguments { - generator.type_(eaf, &argument.type_) + generator.type_(builder, &argument.type_) } - let function_type = eaf.end_function_type_arguments(function_type); - generator.type_(eaf, &function.return_type); - eaf.end_function_type(function_type); - eaf.end_function_spec(spec); + let function_type = builder.end_function_type_arguments(function_type); + generator.type_(builder, &function.return_type); + builder.end_function_type(function_type); + builder.end_function_spec(spec); } - fn function_doc_attribute(&self, eaf: &mut impl Eaf, function: &TypedFunction) { + fn function_doc_attribute( + &self, + builder: &mut impl ErlangBuilder, + function: &TypedFunction, + ) { // If a function is marked as internal or comes from an internal module // we want to hide its documentation in the Erlang shell! // So the doc directive will look like this: `-doc(false).` @@ -676,15 +692,15 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { self.module_generator.module.type_info.is_internal || function.publicity.is_internal(); if is_internal { - let attribute = eaf.start_doc_attribute(); - eaf.atom("false"); - eaf.end_doc_attribute(attribute); + let attribute = builder.start_doc_attribute(); + builder.atom("false"); + builder.end_doc_attribute(attribute); } else if let Some((_, documentation)) = &function.documentation && !documentation.is_empty() { - let attribute = eaf.start_doc_attribute(); - eaf.string(documentation); - eaf.end_doc_attribute(attribute); + let attribute = builder.start_doc_attribute(); + builder.string(documentation); + builder.end_doc_attribute(attribute); } } @@ -742,18 +758,18 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { fn statement_sequence( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, statements: &'a [TypedStatement], ) { // We go over each statement one by one and produce the code they need. for i in 0..statements.len() { match statements.get(i).expect("statement in range") { - Statement::Expression(expression) => self.expr(eaf, expression), - Statement::Use(use_) => self.expr(eaf, &use_.call), - Statement::Assert(assert) => self.assert(eaf, assert), + Statement::Expression(expression) => self.expr(builder, expression), + Statement::Use(use_) => self.expr(builder, &use_.call), + Statement::Assert(assert) => self.assert(builder, assert), Statement::Assignment(assignment) => match &assignment.kind { AssignmentKind::Let | AssignmentKind::Generated => { - self.let_(eaf, &assignment.value, &assignment.pattern) + self.let_(builder, &assignment.value, &assignment.pattern) } // Let asserts are slightly different from everything else: // A let assert is compiled to a case expression where we @@ -783,7 +799,7 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { message, location, .. } => { return self.let_assert( - eaf, + builder, &assignment.value, &assignment.pattern, message.as_ref(), @@ -796,17 +812,21 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { } } - fn expr(&mut self, eaf: &mut impl Eaf, expression: &'a TypedExpr) { + fn expr( + &mut self, + builder: &mut impl ErlangBuilder, + expression: &'a TypedExpr, + ) { match expression { // // Simple scalar values, and blocks. // - TypedExpr::Int { int_value, .. } => eaf.int(int_value.clone()), - TypedExpr::Float { float_value, .. } => eaf.float(float_value.value()), - TypedExpr::String { value, .. } => eaf.string(value), + TypedExpr::Int { int_value, .. } => builder.int(int_value.clone()), + TypedExpr::Float { float_value, .. } => builder.float(float_value.value()), + TypedExpr::String { value, .. } => builder.string(value), TypedExpr::Var { name, constructor, .. - } => self.var(eaf, name, constructor), + } => self.var(builder, name, constructor), TypedExpr::Block { statements, .. } => { // If the block has a single expression we don't bother wrapping // it in an additional `begin ... end` block. @@ -814,11 +834,11 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { if statements.len() == 1 && let Statement::Expression(expression) = statements.first() { - self.maybe_block_expr(eaf, expression); + self.maybe_block_expr(builder, expression); } else { - let block = eaf.start_block(); - self.statement_sequence(eaf, statements); - eaf.end_block(block) + let block = builder.start_block(); + self.statement_sequence(builder, statements); + builder.end_block(block) } } @@ -826,60 +846,60 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // Operators. // TypedExpr::NegateBool { value, .. } => { - eaf.unary_operator("not"); - self.maybe_block_expr(eaf, value) + builder.unary_operator("not"); + self.maybe_block_expr(builder, value) } TypedExpr::NegateInt { value, .. } => { - eaf.unary_operator("-"); - self.maybe_block_expr(eaf, value) + builder.unary_operator("-"); + self.maybe_block_expr(builder, value) } TypedExpr::BinOp { operator, left, right, .. - } => self.bin_op(eaf, operator, left, right), + } => self.bin_op(builder, operator, left, right), // // BitArrays, Lists, and Tuples. // TypedExpr::BitArray { segments, .. } => { - let bit_array = eaf.start_bit_array(); + let bit_array = builder.start_bit_array(); for segment in segments { - self.bit_array_expression_segment(eaf, segment); + self.bit_array_expression_segment(builder, segment); } - eaf.end_bit_array(bit_array); + builder.end_bit_array(bit_array); } TypedExpr::List { elements, tail, .. } => { // We generate all the items of the list as cons cells. for element in elements { - eaf.cons_list(); - self.maybe_block_expr(eaf, element); + builder.cons_list(); + self.maybe_block_expr(builder, element); } // Finally we close the list with the tail, or an empty list // (so that we're sure we're building proper Erlang lists). if let Some(tail) = tail { - self.maybe_block_expr(eaf, tail); + self.maybe_block_expr(builder, tail); } else { - eaf.empty_list(); + builder.empty_list(); } } TypedExpr::Tuple { elements, .. } => { - let tuple = eaf.start_tuple(); + let tuple = builder.start_tuple(); for element in elements { - self.maybe_block_expr(eaf, element); + self.maybe_block_expr(builder, element); } - eaf.end_tuple(tuple) + builder.end_tuple(tuple) } // // Accessing data inside tuples, and records. // They're all tuple accesses at the end of the day! // - TypedExpr::TupleIndex { tuple, index, .. } => self.tuple_index(eaf, tuple, *index), + TypedExpr::TupleIndex { tuple, index, .. } => self.tuple_index(builder, tuple, *index), TypedExpr::RecordAccess { record, index, .. } | TypedExpr::PositionalAccess { record, index, .. } => { - self.tuple_index(eaf, record, index + 1) + self.tuple_index(builder, record, index + 1) } // @@ -888,7 +908,7 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { TypedExpr::ModuleSelect { constructor: ModuleValueConstructor::Record { name, arity: 0, .. }, .. - } => eaf.atom(&to_snake_case(name)), + } => builder.atom(&to_snake_case(name)), TypedExpr::RecordUpdate { updated_record_assigned_name, updated_record, @@ -899,14 +919,14 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // If the record value itself needs to be bound to a variable // before the update, we define it. if let Some(name) = updated_record_assigned_name.as_ref() { - eaf.match_operator(); - eaf.variable_pattern( + builder.match_operator(); + builder.variable_pattern( &self.new_erlang_variable(name, updated_record.location()), ); - self.maybe_block_expr(eaf, updated_record); + self.maybe_block_expr(builder, updated_record); } // Then a record update is simply a call! - self.call(eaf, constructor, arguments) + self.call(builder, constructor, arguments) } // @@ -917,15 +937,15 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { } => { let outer_scope = self.taken_names.clone(); let argument_names = self.function_arguments_names(arguments, false); - let function = eaf.start_anonymous_function(argument_names); - self.statement_sequence(eaf, body); - eaf.end_function(function); + let function = builder.start_anonymous_function(argument_names); + self.statement_sequence(builder, body); + builder.end_function(function); self.taken_names = outer_scope; } TypedExpr::ModuleSelect { constructor: ModuleValueConstructor::Record { name, arity, .. }, .. - } => self.record_builder_anonymous_function(eaf, name, *arity as usize), + } => self.record_builder_anonymous_function(builder, name, *arity as usize), TypedExpr::ModuleSelect { type_, constructor: @@ -936,7 +956,7 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { | ModuleValueConstructor::Fn { module, name, .. }, .. } => match type_::collapse_links(type_.clone()).as_ref() { - Type::Fn { arguments, .. } => eaf.function_reference( + Type::Fn { arguments, .. } => builder.function_reference( Some(ErlangModuleName::new(&module)), escape_erlang_existing_name(name), arguments.len(), @@ -944,21 +964,21 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { Type::Named { .. } | Type::Var { .. } | Type::Tuple { .. } => { let name = escape_erlang_existing_name(name); - let call = eaf.start_remote_call(ErlangModuleName::new(&module), name); - eaf.end_call(call); + let call = builder.start_remote_call(ErlangModuleName::new(&module), name); + builder.end_call(call); } }, // // Calling functions. // - TypedExpr::Call { fun, arguments, .. } => self.call(eaf, fun, arguments), + TypedExpr::Call { fun, arguments, .. } => self.call(builder, fun, arguments), TypedExpr::Pipeline { first_value, assignments, finally, .. - } => self.pipeline(eaf, first_value, assignments, finally), + } => self.pipeline(builder, first_value, assignments, finally), // // Todo, panic, and echo. @@ -967,23 +987,23 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { message, location, .. } => { let error = self.start_runtime_error( - eaf, + builder, RuntimeErrorKind::Todo, *location, message.as_deref(), ); - self.end_runtime_error(eaf, error); + self.end_runtime_error(builder, error); } TypedExpr::Panic { location, message, .. } => { let error = self.start_runtime_error( - eaf, + builder, RuntimeErrorKind::Panic, *location, message.as_deref(), ); - self.end_runtime_error(eaf, error); + self.end_runtime_error(builder, error); } TypedExpr::Echo { expression, @@ -991,7 +1011,7 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { message, .. } => self.echo( - eaf, + builder, *location, message.as_deref(), EchoPrintedValue::Expression { @@ -1007,14 +1027,14 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { TypedExpr::ModuleSelect { constructor: ModuleValueConstructor::Constant { literal, .. }, .. - } => self.inlined_constant(eaf, literal), + } => self.inlined_constant(builder, literal), // // Control flow. // TypedExpr::Case { subjects, clauses, .. - } => self.case(eaf, subjects, clauses), + } => self.case(builder, subjects, clauses), // // Something went wrong! @@ -1027,92 +1047,92 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { fn echo( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, echo_location: SrcSpan, message: Option<&'a TypedExpr>, printed_value: EchoPrintedValue<'a>, ) { self.module_generator.echo_used = true; - let call = eaf.start_call(); - eaf.atom("echo"); + let call = builder.start_call(); + builder.atom("echo"); // Echo has 4 arguments: the expression to print... match printed_value { - EchoPrintedValue::PipeStep { name } => eaf.variable(&name), - EchoPrintedValue::Expression { value } => self.maybe_block_expr(eaf, value), + EchoPrintedValue::PipeStep { name } => builder.variable(&name), + EchoPrintedValue::Expression { value } => self.maybe_block_expr(builder, value), } // ...the message to print (or nil if there's no message)... if let Some(message) = message { - self.maybe_block_expr(eaf, message); + self.maybe_block_expr(builder, message); } else { - eaf.atom("nil") + builder.atom("nil") } // ...the filepath of this module... - eaf.string(&self.module_generator.module_source_path); + builder.string(&self.module_generator.module_source_path); // ...and the line number of the expression. - eaf.int( + builder.int( self.module_generator .line_numbers .line_number(echo_location.start) .into(), ); - eaf.end_call(call); + builder.end_call(call); } /// This starts a call to `erlang:error` with a map representing a Gleam /// runtime error of the given kind. /// Some fields are mandatory and always added, but if you need to add more - /// fields you can still do so by calling `eaf.map_field()`. + /// fields you can still do so by calling `builder.map_field()`. /// /// After you're done generating those additional fields remember you _must_ /// call `end_runtime_error` before generating any other piece of code! /// fn start_runtime_error( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, error_kind: RuntimeErrorKind, location: SrcSpan, message: Option<&'a TypedExpr>, ) -> RuntimeError { - let call = eaf.start_remote_call(ErlangModuleName::new("erlang"), "error"); - let map = eaf.start_map(); + let call = builder.start_remote_call(ErlangModuleName::new("erlang"), "error"); + let map = builder.start_map(); - eaf.map_field(); - eaf.atom("gleam_error"); - eaf.atom(match error_kind { + builder.map_field(); + builder.atom("gleam_error"); + builder.atom(match error_kind { RuntimeErrorKind::Todo => "todo", RuntimeErrorKind::Panic => "panic", RuntimeErrorKind::Assert => "assert", RuntimeErrorKind::LetAssert => "let_assert", }); - eaf.map_field(); - eaf.atom("message"); + builder.map_field(); + builder.atom("message"); if let Some(message) = message { - self.maybe_block_expr(eaf, message); + self.maybe_block_expr(builder, message); } else { - eaf.string(error_kind.default_error_message()) + builder.string(error_kind.default_error_message()) } - eaf.map_field(); - eaf.atom("file"); - eaf.string(&self.module_generator.module_source_path); + builder.map_field(); + builder.atom("file"); + builder.string(&self.module_generator.module_source_path); - eaf.map_field(); - eaf.atom("module"); - eaf.string(&self.module_generator.module.name); + builder.map_field(); + builder.atom("module"); + builder.string(&self.module_generator.module.name); - eaf.map_field(); - eaf.atom("function"); - eaf.string(self.function_name); + builder.map_field(); + builder.atom("function"); + builder.string(self.function_name); - eaf.map_field(); - eaf.atom("line"); - eaf.int( + builder.map_field(); + builder.atom("line"); + builder.int( self.module_generator .line_numbers .line_number(location.start) @@ -1126,35 +1146,43 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { } /// This closes an open runtime error. - fn end_runtime_error(&self, eaf: &mut impl Eaf, runtime_error: RuntimeError) { - eaf.end_map(runtime_error.error_map); - eaf.end_call(runtime_error.erlang_error_call); + fn end_runtime_error( + &self, + builder: &mut impl ErlangBuilder, + runtime_error: RuntimeError, + ) { + builder.end_map(runtime_error.error_map); + builder.end_call(runtime_error.erlang_error_call); } - fn maybe_block_expr(&mut self, eaf: &mut impl Eaf, expression: &'a TypedExpr) { + fn maybe_block_expr( + &mut self, + builder: &mut impl ErlangBuilder, + expression: &'a TypedExpr, + ) { if needs_begin_end_wrapping(expression) { - let block = eaf.start_block(); - self.expr(eaf, expression); - eaf.end_block(block); + let block = builder.start_block(); + self.expr(builder, expression); + builder.end_block(block); } else { - self.expr(eaf, expression); + self.expr(builder, expression); } } fn let_( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, value: &'a TypedExpr, pattern: &'a TypedPattern, ) { - eaf.match_operator(); - PatternGenerator::new(self).pattern(eaf, pattern); - self.maybe_block_expr(eaf, value) + builder.match_operator(); + PatternGenerator::new(self).pattern(builder, pattern); + self.maybe_block_expr(builder, value) } fn let_assert( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, value: &'a TypedExpr, pattern: &'a TypedPattern, message: Option<&'a TypedExpr>, @@ -1164,31 +1192,31 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // If the pattern will never fail, like a tuple or a simple variable, we // simply treat it as if it were a `let` assignment. if pattern.always_matches() { - self.let_(eaf, value, pattern); - self.statement_sequence(eaf, following_statements); + self.let_(builder, value, pattern); + self.statement_sequence(builder, following_statements); return; } // Otherwise we turn the let assert into a case expression with two // branches: one for the asserted pattern, and one catch all to throw an // exception in case the pattern doesn't match. - let case = eaf.start_case(); - self.maybe_block_expr(eaf, value); + let case = builder.start_case(); + self.maybe_block_expr(builder, value); // This is the first branch for when the asserted pattern matches: it's // going to run all the remaining statements in its body. if !following_statements.is_empty() { // If there's statements after this let assert we want to generate // them. - let clause = eaf.start_case_clause(); + let clause = builder.start_case_clause(); let mut generator = PatternGenerator::new(self); - generator.pattern(eaf, pattern); - let clause = eaf.end_clause_pattern(clause); - let clause = eaf.end_clause_guards(clause); + generator.pattern(builder, pattern); + let clause = builder.end_clause_pattern(clause); + let clause = builder.end_clause_guards(clause); let variables_to_add_later = generator.variables_to_add_later; - self.pattern_assignments(eaf, variables_to_add_later); - self.statement_sequence(eaf, following_statements); - eaf.end_clause_body(clause); + self.pattern_assignments(builder, variables_to_add_later); + self.statement_sequence(builder, following_statements); + builder.end_clause_body(clause); } else { // If there's no statements following the let assert, that means // that it's the last statement in the block and we need to return @@ -1203,57 +1231,58 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // _ -> erlang:error(...) // end // ``` - let clause = eaf.start_case_clause(); + let clause = builder.start_case_clause(); let matched_value_name = self.new_throwaway_variable(); - eaf.match_pattern(); + builder.match_pattern(); let mut generator = PatternGenerator::new(self); - generator.pattern(eaf, pattern); - eaf.variable_pattern(&matched_value_name); + generator.pattern(builder, pattern); + builder.variable_pattern(&matched_value_name); - let clause = eaf.end_clause_pattern(clause); - let clause = eaf.end_clause_guards(clause); - eaf.variable(&matched_value_name); - eaf.end_clause_body(clause); + let clause = builder.end_clause_pattern(clause); + let clause = builder.end_clause_guards(clause); + builder.variable(&matched_value_name); + builder.end_clause_body(clause); } // This is the catch all branch to throw an error otherwise. - let clause = eaf.start_case_clause(); + let clause = builder.start_case_clause(); let value_name = self.new_throwaway_variable(); - eaf.variable_pattern(&value_name); - let clause = eaf.end_clause_pattern(clause); - let clause = eaf.end_clause_guards(clause); - let error = self.start_runtime_error(eaf, RuntimeErrorKind::LetAssert, location, message); + builder.variable_pattern(&value_name); + let clause = builder.end_clause_pattern(clause); + let clause = builder.end_clause_guards(clause); + let error = + self.start_runtime_error(builder, RuntimeErrorKind::LetAssert, location, message); // We want to add some additional fields to the error map: - eaf.map_field(); - eaf.atom("value"); - eaf.variable(&value_name); + builder.map_field(); + builder.atom("value"); + builder.variable(&value_name); - eaf.map_field(); - eaf.atom("start"); - eaf.int(location.start.into()); + builder.map_field(); + builder.atom("start"); + builder.int(location.start.into()); - eaf.map_field(); - eaf.atom("end"); - eaf.int(value.location().end.into()); + builder.map_field(); + builder.atom("end"); + builder.int(value.location().end.into()); - eaf.map_field(); - eaf.atom("pattern_start"); - eaf.int(pattern.location().start.into()); + builder.map_field(); + builder.atom("pattern_start"); + builder.int(pattern.location().start.into()); - eaf.map_field(); - eaf.atom("pattern_end"); - eaf.int(pattern.location().end.into()); + builder.map_field(); + builder.atom("pattern_end"); + builder.int(pattern.location().end.into()); - self.end_runtime_error(eaf, error); - eaf.end_clause_body(clause); + self.end_runtime_error(builder, error); + builder.end_clause_body(clause); - eaf.end_case(case); + builder.end_case(case); } fn pipeline( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, first_value: &'a TypedPipelineAssignment, assignments: &'a [(TypedPipelineAssignment, PipelineAssignmentKind)], finally: &'a TypedExpr, @@ -1277,9 +1306,9 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // A pipeline step always ends up assigned to a variable. // So we start by generating `_pipe = ...`, followed by the // expression. - eaf.match_operator(); + builder.match_operator(); let name = self.new_erlang_variable(&assignment.name, assignment.location); - eaf.variable_pattern(&name); + builder.variable_pattern(&name); // In case of a pipe we need to manually pass the previous step to // echo as an argument. @@ -1291,7 +1320,7 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { } = assignment.value.as_ref() { self.echo( - eaf, + builder, *location, message.as_deref(), EchoPrintedValue::PipeStep { @@ -1301,7 +1330,7 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { }, ) } else { - self.maybe_block_expr(eaf, &assignment.value); + self.maybe_block_expr(builder, &assignment.value); previous_step_variable_name = Some(name); }; } @@ -1317,7 +1346,7 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { } = finally { self.echo( - eaf, + builder, *location, message.as_deref(), EchoPrintedValue::PipeStep { @@ -1326,11 +1355,15 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { }, ) } else { - self.expr(eaf, finally) + self.expr(builder, finally) } } - fn assert(&mut self, eaf: &mut impl Eaf, assert: &'a TypedAssert) { + fn assert( + &mut self, + builder: &mut impl ErlangBuilder, + assert: &'a TypedAssert, + ) { let Assert { value, location, @@ -1352,10 +1385,10 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // Writing asserts on binops requires some extra care, check // out their docs! BinOp::And => { - return self.assert_and(eaf, left, right, message.as_ref(), *location); + return self.assert_and(builder, left, right, message.as_ref(), *location); } BinOp::Or => { - return self.assert_or(eaf, left, right, message.as_ref(), *location); + return self.assert_or(builder, left, right, message.as_ref(), *location); } BinOp::Eq => "=:=", @@ -1384,9 +1417,9 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // track of those names. let left = if !left.is_var() { let name = self.new_throwaway_variable(); - eaf.match_operator(); - eaf.variable_pattern(&name); - self.maybe_block_expr(eaf, left); + builder.match_operator(); + builder.variable_pattern(&name); + self.maybe_block_expr(builder, left); AssertionExpression::from_throwaway_variable(name, left) } else { AssertionExpression::from_expression(left) @@ -1394,47 +1427,47 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { let right = if !right.is_var() { let name = self.new_throwaway_variable(); - eaf.match_operator(); - eaf.variable_pattern(&name); - self.maybe_block_expr(eaf, right); + builder.match_operator(); + builder.variable_pattern(&name); + self.maybe_block_expr(builder, right); AssertionExpression::from_throwaway_variable(name, right) } else { AssertionExpression::from_expression(right) }; - let case = eaf.start_case(); + let case = builder.start_case(); // Then we need to apply the operator. If any of the two sides // has been bound to a variable we can use that name directly! - eaf.binary_operator(erlang_operator); - self.runtime_value(eaf, &left); - self.runtime_value(eaf, &right); + builder.binary_operator(erlang_operator); + self.runtime_value(builder, &left); + self.runtime_value(builder, &right); // If the operator evaluates to true the assertion succeeded. // We can just return nil. - let clause = eaf.start_case_clause(); - eaf.atom_pattern("true"); - let clause = eaf.end_clause_pattern(clause); - let clause = eaf.end_clause_guards(clause); - eaf.atom("nil"); - eaf.end_clause_body(clause); + let clause = builder.start_case_clause(); + builder.atom_pattern("true"); + let clause = builder.end_clause_pattern(clause); + let clause = builder.end_clause_guards(clause); + builder.atom("nil"); + builder.end_clause_body(clause); // Otherwise we want to throw a runtime error! - let clause = eaf.start_case_clause(); - eaf.atom_pattern("false"); - let clause = eaf.end_clause_pattern(clause); - let clause = eaf.end_clause_guards(clause); + let clause = builder.start_case_clause(); + builder.atom_pattern("false"); + let clause = builder.end_clause_pattern(clause); + let clause = builder.end_clause_guards(clause); self.assert_binary_operator_error( - eaf, + builder, *operator, left, right, message.as_ref(), *location, ); - eaf.end_clause_body(clause); + builder.end_clause_body(clause); - eaf.end_case(case); + builder.end_case(case); } TypedExpr::Call { fun, arguments, .. } => { @@ -1447,9 +1480,9 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { for argument in arguments { let argument = if !argument.value.is_var() { let name = self.new_throwaway_variable(); - eaf.match_operator(); - eaf.variable_pattern(&name); - self.maybe_block_expr(eaf, &argument.value); + builder.match_operator(); + builder.variable_pattern(&name); + self.maybe_block_expr(builder, &argument.value); AssertionExpression::from_throwaway_variable(name, &argument.value) } else { AssertionExpression::from_expression(&argument.value) @@ -1457,27 +1490,33 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { call_arguments.push(argument); } - let case = eaf.start_case(); - self.call_in_assert(eaf, fun, &call_arguments); + let case = builder.start_case(); + self.call_in_assert(builder, fun, &call_arguments); // If the operator evaluates to true the assertion succeeded. // We can just return nil. - let clause = eaf.start_case_clause(); - eaf.atom_pattern("true"); - let clause = eaf.end_clause_pattern(clause); - let clause = eaf.end_clause_guards(clause); - eaf.atom("nil"); - eaf.end_clause_body(clause); + let clause = builder.start_case_clause(); + builder.atom_pattern("true"); + let clause = builder.end_clause_pattern(clause); + let clause = builder.end_clause_guards(clause); + builder.atom("nil"); + builder.end_clause_body(clause); // Otherwise we want to throw a runtime error! - let clause = eaf.start_case_clause(); - eaf.atom_pattern("false"); - let clause = eaf.end_clause_pattern(clause); - let clause = eaf.end_clause_guards(clause); - self.assert_call_error(eaf, value, &call_arguments, message.as_ref(), *location); - eaf.end_clause_body(clause); + let clause = builder.start_case_clause(); + builder.atom_pattern("false"); + let clause = builder.end_clause_pattern(clause); + let clause = builder.end_clause_guards(clause); + self.assert_call_error( + builder, + value, + &call_arguments, + message.as_ref(), + *location, + ); + builder.end_clause_body(clause); - eaf.end_case(case); + builder.end_case(case); } TypedExpr::Int { .. } @@ -1502,32 +1541,32 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { | TypedExpr::NegateBool { .. } | TypedExpr::NegateInt { .. } | TypedExpr::Invalid { .. } => { - let case = eaf.start_case(); - self.maybe_block_expr(eaf, value); + let case = builder.start_case(); + self.maybe_block_expr(builder, value); // If the expression evaluates to true the assertion succeeded. // We can just return nil. - let clause = eaf.start_case_clause(); - eaf.atom_pattern("true"); - let clause = eaf.end_clause_pattern(clause); - let clause = eaf.end_clause_guards(clause); - eaf.atom("nil"); - eaf.end_clause_body(clause); + let clause = builder.start_case_clause(); + builder.atom_pattern("true"); + let clause = builder.end_clause_pattern(clause); + let clause = builder.end_clause_guards(clause); + builder.atom("nil"); + builder.end_clause_body(clause); // Otherwise we want to throw a runtime error! - let clause = eaf.start_case_clause(); - eaf.atom_pattern("false"); - let clause = eaf.end_clause_pattern(clause); - let clause = eaf.end_clause_guards(clause); + let clause = builder.start_case_clause(); + builder.atom_pattern("false"); + let clause = builder.end_clause_pattern(clause); + let clause = builder.end_clause_guards(clause); self.assert_expression_error( - eaf, + builder, AssertionExpression::from_expression(value).evaluated_to_bool(false), message.as_ref(), *location, ); - eaf.end_clause_body(clause); + builder.end_clause_body(clause); - eaf.end_case(case); + builder.end_case(case); } } } @@ -1560,72 +1599,72 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { /// fn assert_and( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, left: &'a TypedExpr, right: &'a TypedExpr, message: Option<&'a TypedExpr>, location: SrcSpan, ) { - let case = eaf.start_case(); - self.maybe_block_expr(eaf, left); + let case = builder.start_case(); + self.maybe_block_expr(builder, left); // In case the first expression is true, we get to evaluate the second // one as well, then we will be able to tell if the assertion failed or // not! - let clause = eaf.start_case_clause(); - eaf.atom_pattern("true"); - let clause = eaf.end_clause_pattern(clause); - let clause = eaf.end_clause_guards(clause); + let clause = builder.start_case_clause(); + builder.atom_pattern("true"); + let clause = builder.end_clause_pattern(clause); + let clause = builder.end_clause_guards(clause); { // Now we have to match on the right hand side! - let case = eaf.start_case(); - self.maybe_block_expr(eaf, right); + let case = builder.start_case(); + self.maybe_block_expr(builder, right); // If it's true the assertion succeded! We can return `nil`. - let clause = eaf.start_case_clause(); - eaf.atom_pattern("true"); - let clause = eaf.end_clause_pattern(clause); - let clause = eaf.end_clause_guards(clause); - eaf.atom("nil"); - eaf.end_clause_body(clause); + let clause = builder.start_case_clause(); + builder.atom_pattern("true"); + let clause = builder.end_clause_pattern(clause); + let clause = builder.end_clause_guards(clause); + builder.atom("nil"); + builder.end_clause_body(clause); // If it's false the assertion failed! The left hand side was true // but this one evaluated to false :( - let clause = eaf.start_case_clause(); - eaf.atom_pattern("false"); - let clause = eaf.end_clause_pattern(clause); - let clause = eaf.end_clause_guards(clause); + let clause = builder.start_case_clause(); + builder.atom_pattern("false"); + let clause = builder.end_clause_pattern(clause); + let clause = builder.end_clause_guards(clause); self.assert_binary_operator_error( - eaf, + builder, BinOp::And, AssertionExpression::from_expression(left).evaluated_to_bool(true), AssertionExpression::from_expression(right).evaluated_to_bool(false), message, location, ); - eaf.end_clause_body(clause); - eaf.end_case(case); + builder.end_clause_body(clause); + builder.end_case(case); } - eaf.end_clause_body(clause); + builder.end_clause_body(clause); // In case the first expression is false, we want to fail fast. We are // short circuiting without evaluating the right hand side! This side // just build an error. - let clause = eaf.start_case_clause(); - eaf.atom_pattern("false"); - let clause = eaf.end_clause_pattern(clause); - let clause = eaf.end_clause_guards(clause); + let clause = builder.start_case_clause(); + builder.atom_pattern("false"); + let clause = builder.end_clause_pattern(clause); + let clause = builder.end_clause_guards(clause); self.assert_binary_operator_error( - eaf, + builder, BinOp::And, AssertionExpression::from_expression(left).evaluated_to_bool(false), AssertionExpression::from_expression(right).was_unevaluated(), message, location, ); - eaf.end_clause_body(clause); + builder.end_clause_body(clause); - eaf.end_case(case); + builder.end_case(case); } /// Similar to `&&`, `||` is also short-circuiting in Gleam. However, if `||` @@ -1638,161 +1677,161 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { /// need to store the values of them in variables beforehand. fn assert_or( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, left: &'a TypedExpr, right: &'a TypedExpr, message: Option<&'a TypedExpr>, location: SrcSpan, ) { - let case = eaf.start_case(); - eaf.binary_operator("orelse"); - self.maybe_block_expr(eaf, left); - self.maybe_block_expr(eaf, right); + let case = builder.start_case(); + builder.binary_operator("orelse"); + self.maybe_block_expr(builder, left); + self.maybe_block_expr(builder, right); // If the result is true, then the assertion succeeded, we can return // nil. - let clause = eaf.start_case_clause(); - eaf.atom_pattern("true"); - let clause = eaf.end_clause_pattern(clause); - let clause = eaf.end_clause_guards(clause); - eaf.atom("nil"); - eaf.end_clause_body(clause); + let clause = builder.start_case_clause(); + builder.atom_pattern("true"); + let clause = builder.end_clause_pattern(clause); + let clause = builder.end_clause_guards(clause); + builder.atom("nil"); + builder.end_clause_body(clause); // But if it fails we know that both sides of the assertion resulted in // a false value. In that case we throw an error. - let clause = eaf.start_case_clause(); - eaf.atom_pattern("false"); - let clause = eaf.end_clause_pattern(clause); - let clause = eaf.end_clause_guards(clause); + let clause = builder.start_case_clause(); + builder.atom_pattern("false"); + let clause = builder.end_clause_pattern(clause); + let clause = builder.end_clause_guards(clause); self.assert_binary_operator_error( - eaf, + builder, BinOp::Or, AssertionExpression::from_expression(left).evaluated_to_bool(false), AssertionExpression::from_expression(right).evaluated_to_bool(false), message, location, ); - eaf.end_clause_body(clause); + builder.end_clause_body(clause); - eaf.end_case(case); + builder.end_case(case); } /// This generates the code that throws a runtime error whan an `assert` /// that is checking the result of a binary operator fails. fn assert_binary_operator_error( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, operator: BinOp, left: AssertionExpression<'a>, right: AssertionExpression<'a>, message: Option<&'a TypedExpr>, location: SrcSpan, ) { - let error = self.start_runtime_error(eaf, RuntimeErrorKind::Assert, location, message); + let error = self.start_runtime_error(builder, RuntimeErrorKind::Assert, location, message); - eaf.map_field(); - eaf.atom("kind"); - eaf.atom("binary_operator"); + builder.map_field(); + builder.atom("kind"); + builder.atom("binary_operator"); - eaf.map_field(); - eaf.atom("operator"); - eaf.atom(operator.name()); + builder.map_field(); + builder.atom("operator"); + builder.atom(operator.name()); - eaf.map_field(); - eaf.atom("left"); - self.assertion_expression_map(eaf, &left); + builder.map_field(); + builder.atom("left"); + self.assertion_expression_map(builder, &left); - eaf.map_field(); - eaf.atom("right"); - self.assertion_expression_map(eaf, &right); + builder.map_field(); + builder.atom("right"); + self.assertion_expression_map(builder, &right); - eaf.map_field(); - eaf.atom("start"); - eaf.int(location.start.into()); + builder.map_field(); + builder.atom("start"); + builder.int(location.start.into()); - eaf.map_field(); - eaf.atom("end"); - eaf.int(right.location.end.into()); + builder.map_field(); + builder.atom("end"); + builder.int(right.location.end.into()); - eaf.map_field(); - eaf.atom("expression_start"); - eaf.int(left.location.start.into()); + builder.map_field(); + builder.atom("expression_start"); + builder.int(left.location.start.into()); - self.end_runtime_error(eaf, error); + self.end_runtime_error(builder, error); } /// This generates the code that throws a runtime error whan an `assert` /// that is checking the result of an arbitrary expression fails. fn assert_expression_error( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, expression: AssertionExpression<'a>, message: Option<&'a TypedExpr>, location: SrcSpan, ) { - let error = self.start_runtime_error(eaf, RuntimeErrorKind::Assert, location, message); + let error = self.start_runtime_error(builder, RuntimeErrorKind::Assert, location, message); - eaf.map_field(); - eaf.atom("kind"); - eaf.atom("expression"); + builder.map_field(); + builder.atom("kind"); + builder.atom("expression"); // If assert fails on an expression's result then we know it must have // evaluated to false! - eaf.map_field(); - eaf.atom("expression"); - self.assertion_expression_map(eaf, &expression); + builder.map_field(); + builder.atom("expression"); + self.assertion_expression_map(builder, &expression); - eaf.map_field(); - eaf.atom("start"); - eaf.int(location.start.into()); + builder.map_field(); + builder.atom("start"); + builder.int(location.start.into()); - eaf.map_field(); - eaf.atom("end"); - eaf.int(expression.location.end.into()); + builder.map_field(); + builder.atom("end"); + builder.int(expression.location.end.into()); - eaf.map_field(); - eaf.atom("expression_start"); - eaf.int(expression.location.start.into()); + builder.map_field(); + builder.atom("expression_start"); + builder.int(expression.location.start.into()); - self.end_runtime_error(eaf, error); + self.end_runtime_error(builder, error); } fn assert_call_error( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, call: &'a TypedExpr, arguments: &[AssertionExpression<'a>], message: Option<&'a TypedExpr>, location: SrcSpan, ) { - let error = self.start_runtime_error(eaf, RuntimeErrorKind::Assert, location, message); + let error = self.start_runtime_error(builder, RuntimeErrorKind::Assert, location, message); - eaf.map_field(); - eaf.atom("kind"); - eaf.atom("function_call"); + builder.map_field(); + builder.atom("kind"); + builder.atom("function_call"); - eaf.map_field(); - eaf.atom("arguments"); + builder.map_field(); + builder.atom("arguments"); for argument in arguments { - eaf.cons_list(); - self.assertion_expression_map(eaf, argument); + builder.cons_list(); + self.assertion_expression_map(builder, argument); } - eaf.empty_list(); + builder.empty_list(); - eaf.map_field(); - eaf.atom("start"); - eaf.int(location.start.into()); + builder.map_field(); + builder.atom("start"); + builder.int(location.start.into()); - eaf.map_field(); - eaf.atom("end"); - eaf.int(call.location().end.into()); + builder.map_field(); + builder.atom("end"); + builder.int(call.location().end.into()); - eaf.map_field(); - eaf.atom("expression_start"); - eaf.int(call.location().start.into()); + builder.map_field(); + builder.atom("expression_start"); + builder.int(call.location().start.into()); - self.end_runtime_error(eaf, error); + self.end_runtime_error(builder, error); } /// Given an expression being asserted on. This generates the code for an @@ -1800,7 +1839,7 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { /// its location in the source code. fn assertion_expression_map( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, expression: &AssertionExpression<'a>, ) { let AssertionExpression { @@ -1809,31 +1848,31 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { location, } = expression; - let map = eaf.start_map(); + let map = builder.start_map(); - eaf.map_field(); - eaf.atom("kind"); - eaf.atom(match kind { + builder.map_field(); + builder.atom("kind"); + builder.atom(match kind { AssertedExpressionKind::Literal => "literal", AssertedExpressionKind::Expression => "expression", AssertedExpressionKind::Unevaluated => "unevaluated", }); if runtime_value.is_some() { - eaf.map_field(); - eaf.atom("value"); - self.runtime_value(eaf, expression); + builder.map_field(); + builder.atom("value"); + self.runtime_value(builder, expression); } - eaf.map_field(); - eaf.atom("start"); - eaf.int(location.start.into()); + builder.map_field(); + builder.atom("start"); + builder.int(location.start.into()); - eaf.map_field(); - eaf.atom("end"); - eaf.int(location.end.into()); + builder.map_field(); + builder.atom("end"); + builder.int(location.end.into()); - eaf.end_map(map); + builder.end_map(map); } /// This takes a value that is in an assertion (and might have been bound @@ -1842,7 +1881,7 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { /// fn runtime_value( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, expression: &AssertionExpression<'a>, ) { match expression @@ -1850,28 +1889,30 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { .as_ref() .expect("trying to reference unevaluated assert value") { - AssertedExpressionRuntimeValue::KnownBool(true) => eaf.atom("true"), - AssertedExpressionRuntimeValue::KnownBool(false) => eaf.atom("false"), - AssertedExpressionRuntimeValue::Variable(name) => eaf.variable(name), - AssertedExpressionRuntimeValue::Expression(expr) => self.maybe_block_expr(eaf, expr), + AssertedExpressionRuntimeValue::KnownBool(true) => builder.atom("true"), + AssertedExpressionRuntimeValue::KnownBool(false) => builder.atom("false"), + AssertedExpressionRuntimeValue::Variable(name) => builder.variable(name), + AssertedExpressionRuntimeValue::Expression(expr) => { + self.maybe_block_expr(builder, expr) + } } } fn tuple_index( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, tuple: &'a TypedExpr, index: u64, ) { - let call = eaf.start_remote_call(ErlangModuleName::new("erlang"), "element"); - eaf.int((index + 1).into()); - self.maybe_block_expr(eaf, tuple); - eaf.end_call(call); + let call = builder.start_remote_call(ErlangModuleName::new("erlang"), "element"); + builder.int((index + 1).into()); + self.maybe_block_expr(builder, tuple); + builder.end_call(call); } fn var( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, name: &'a str, constructor: &'a ValueConstructor, ) { @@ -1897,19 +1938,19 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // } // ``` Type::Named { .. } | Type::Var { .. } | Type::Tuple { .. } => { - eaf.atom(&to_snake_case(record_name)) + builder.atom(&to_snake_case(record_name)) } Type::Fn { arguments, .. } => { - self.record_builder_anonymous_function(eaf, record_name, arguments.len()) + self.record_builder_anonymous_function(builder, record_name, arguments.len()) } }, ValueConstructorVariant::LocalVariable { location, .. } => { - eaf.variable(&self.local_var_name(location)) + builder.variable(&self.local_var_name(location)) } ValueConstructorVariant::ModuleConstant { literal, .. } => { - self.inlined_constant(eaf, literal) + self.inlined_constant(builder, literal) } ValueConstructorVariant::ModuleFn { @@ -1919,16 +1960,16 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { } => { let name = escape_erlang_existing_name(name); if *module == self.module_generator.module.name { - eaf.function_reference(None, name, *arity) + builder.function_reference(None, name, *arity) } else { - eaf.function_reference(Some(ErlangModuleName::new(&module)), name, *arity) + builder.function_reference(Some(ErlangModuleName::new(&module)), name, *arity) } } ValueConstructorVariant::ModuleFn { arity, module, .. } if *module == self.module_generator.module.name => { - eaf.function_reference(None, escape_erlang_existing_name(name), *arity) + builder.function_reference(None, escape_erlang_existing_name(name), *arity) } ValueConstructorVariant::ModuleFn { @@ -1936,7 +1977,7 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { module, name, .. - } => eaf.function_reference( + } => builder.function_reference( Some(ErlangModuleName::new(&module)), escape_erlang_existing_name(name), *arity, @@ -1946,43 +1987,43 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { fn call( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, fun: &'a TypedExpr, arguments: &'a [TypedCallArg], ) { match how_to_call(fun) { // If we're building a record then we want to just output a // tagged tuple, there's no function call at all! - FunctionCall::BuildRecord { name } => self.build_record(eaf, name, arguments), + FunctionCall::BuildRecord { name } => self.build_record(builder, name, arguments), // If we're calling some module function like `io.println`, `main`, // `list.map` then we can call the function using its name (and // module name if it comes from a different module). FunctionCall::Call { module, name } => { let call = if module != self.module_generator.module.name { - eaf.start_remote_call( + builder.start_remote_call( ErlangModuleName::new(&module), escape_erlang_existing_name(name), ) } else { - let call = eaf.start_call(); - eaf.atom(escape_erlang_existing_name(name)); + let call = builder.start_call(); + builder.atom(escape_erlang_existing_name(name)); call }; for argument in arguments { - self.maybe_block_expr(eaf, &argument.value); + self.maybe_block_expr(builder, &argument.value); } - eaf.end_call(call) + builder.end_call(call) } // If we're calling anything else (like an anonymous function, or // the result of another function call) we generate its code and // call that result directly. FunctionCall::DirectCall => { - let call = eaf.start_call(); - self.maybe_block_expr(eaf, fun); + let call = builder.start_call(); + self.maybe_block_expr(builder, fun); for argument in arguments { - self.maybe_block_expr(eaf, &argument.value); + self.maybe_block_expr(builder, &argument.value); } - eaf.end_call(call); + builder.end_call(call); } } } @@ -1998,7 +2039,7 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { /// fn call_in_assert( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, fun: &'a TypedExpr, arguments: &[AssertionExpression<'a>], ) { @@ -2014,31 +2055,31 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // module name if it comes from a different module). FunctionCall::Call { module, name } => { let call = if module != self.module_generator.module.name { - eaf.start_remote_call( + builder.start_remote_call( ErlangModuleName::new(&module), escape_erlang_existing_name(name), ) } else { - let call = eaf.start_call(); - eaf.atom(escape_erlang_existing_name(name)); + let call = builder.start_call(); + builder.atom(escape_erlang_existing_name(name)); call }; for argument in arguments { - self.runtime_value(eaf, argument); + self.runtime_value(builder, argument); } - eaf.end_call(call) + builder.end_call(call) } // If we're calling anything else (like an anonymous function, or // the result of another function call) we generate its code and // call that result directly. FunctionCall::DirectCall => { - let call = eaf.start_call(); - self.maybe_block_expr(eaf, fun); + let call = builder.start_call(); + self.maybe_block_expr(builder, fun); for argument in arguments { - self.runtime_value(eaf, argument); + self.runtime_value(builder, argument); } - eaf.end_call(call); + builder.end_call(call); } } } @@ -2052,48 +2093,48 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { /// record. This function will take care of turning it to snake case! fn build_record( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, record_name: &str, arguments: &'a [TypedCallArg], ) { if arguments.is_empty() { - eaf.atom(&to_snake_case(record_name)) + builder.atom(&to_snake_case(record_name)) } else { - let tuple = eaf.start_tuple(); - eaf.atom(&to_snake_case(record_name)); + let tuple = builder.start_tuple(); + builder.atom(&to_snake_case(record_name)); for argument in arguments { - self.maybe_block_expr(eaf, &argument.value); + self.maybe_block_expr(builder, &argument.value); } - eaf.end_tuple(tuple) + builder.end_tuple(tuple) } } fn case( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, subjects: &'a [TypedExpr], clauses: &'a [TypedClause], ) { - let case = eaf.start_case(); + let case = builder.start_case(); // If there's more than a single subject we will need to wrap those in a // tuple and start matching on tuple patterns. That's because Erlang // doesn't support matching on multiple subjects like Gleam. match subjects { - [subject] => self.maybe_block_expr(eaf, subject), + [subject] => self.maybe_block_expr(builder, subject), subjects => { - let tuple = eaf.start_tuple(); + let tuple = builder.start_tuple(); for subject in subjects { - self.maybe_block_expr(eaf, subject); + self.maybe_block_expr(builder, subject); } - eaf.end_tuple(tuple); + builder.end_tuple(tuple); } } for clause in clauses { let taken_names_before_clause = self.taken_names.clone(); - self.clause_branch(eaf, &clause.pattern, clause); + self.clause_branch(builder, &clause.pattern, clause); // Erlang doesn't support alternative patterns so we're gonna have // to turn those into separate branches! @@ -2123,22 +2164,22 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // for pattern in &clause.alternative_patterns { self.taken_names = taken_names_before_clause.clone(); - self.clause_branch(eaf, pattern, clause); + self.clause_branch(builder, pattern, clause); } } - eaf.end_case(case); + builder.end_case(case); } /// Given a pattern and the branch it belongs to this generates an Erlang /// case clause for that pattern. fn clause_branch( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, patterns: &'a Vec>>, clause: &'a Clause>, ) { - let clause_pattern = eaf.start_case_clause(); + let clause_pattern = builder.start_case_clause(); // We start by generating the case clause pattern. If we're matching on // multiple subjects (and so patterns has more that a single item) those @@ -2146,35 +2187,35 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // That's how we match on multiple things on the Erlang target. let mut pattern_generator = PatternGenerator::new(self); match patterns.as_slice() { - [pattern] => pattern_generator.pattern(eaf, pattern), + [pattern] => pattern_generator.pattern(builder, pattern), patterns => { - let tuple = eaf.start_tuple_pattern(); + let tuple = builder.start_tuple_pattern(); for pattern in patterns { - pattern_generator.pattern(eaf, pattern); + pattern_generator.pattern(builder, pattern); } - eaf.end_tuple_pattern(tuple); + builder.end_tuple_pattern(tuple); } }; let variables_to_add_later = pattern_generator.variables_to_add_later; - let clause_guards = eaf.end_clause_pattern(clause_pattern); + let clause_guards = builder.end_clause_pattern(clause_pattern); if let Some(guard) = clause.guard.as_ref() { - self.clause_guard(eaf, guard, &variables_to_add_later); + self.clause_guard(builder, guard, &variables_to_add_later); } // Finally we can generate the clause body. If the clause is // followed by a single block then we want it to be a statements // sequence (and not wrapped in a begin ... end block as we usually // would when generating code for a block expression). - let clause_body = eaf.end_clause_guards(clause_guards); - self.pattern_assignments(eaf, variables_to_add_later); + let clause_body = builder.end_clause_guards(clause_guards); + self.pattern_assignments(builder, variables_to_add_later); if let TypedExpr::Block { statements, .. } = &clause.then { - self.statement_sequence(eaf, statements); + self.statement_sequence(builder, statements); } else { - self.expr(eaf, &clause.then); + self.expr(builder, &clause.then); } - eaf.end_clause_body(clause_body); + builder.end_clause_body(clause_body); } /// Erlang doesn't have a special constant declaration syntax; so each Gleam @@ -2182,15 +2223,19 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { /// /// This function produces the code of a constant expression. /// - fn inlined_constant(&mut self, eaf: &mut impl Eaf, literal: &'a TypedConstant) { + fn inlined_constant( + &mut self, + builder: &mut impl ErlangBuilder, + literal: &'a TypedConstant, + ) { match literal { - Constant::Int { int_value, .. } => eaf.int(int_value.clone()), - Constant::Float { float_value, .. } => eaf.float(float_value.value()), - Constant::String { value, .. } => eaf.string(value), + Constant::Int { int_value, .. } => builder.int(int_value.clone()), + Constant::Float { float_value, .. } => builder.float(float_value.value()), + Constant::String { value, .. } => builder.string(value), Constant::Var { name, constructor, .. } => self.var( - eaf, + builder, name, constructor .as_ref() @@ -2198,46 +2243,46 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { ), Constant::Tuple { elements, .. } => { - let tuple = eaf.start_tuple(); + let tuple = builder.start_tuple(); for element in elements { - self.inlined_constant(eaf, element) + self.inlined_constant(builder, element) } - eaf.end_tuple(tuple); + builder.end_tuple(tuple); } Constant::List { elements, tail, .. } => { for element in elements { - eaf.cons_list(); - self.inlined_constant(eaf, element) + builder.cons_list(); + self.inlined_constant(builder, element) } match tail { // If there's no tail we simply add an empty list cell to // end the cons list. - None => eaf.empty_list(), + None => builder.empty_list(), Some(tail) => match tail.list_elements() { // If there's a tail and we don't statically know the // elements it's made of, we add it as a regular Erlang // tail and it will be `[1, 2 | Tail]`. - None => self.inlined_constant(eaf, tail), + None => self.inlined_constant(builder, tail), // But if we can tell it has some fixed amount of // constant elements, then those are inlined too! Some(list_elements) => { for element in list_elements { - eaf.cons_list(); - self.inlined_constant(eaf, element); + builder.cons_list(); + self.inlined_constant(builder, element); } - eaf.empty_list(); + builder.empty_list(); } }, } } Constant::BitArray { segments, .. } => { - let bit_array = eaf.start_bit_array(); + let bit_array = builder.start_bit_array(); for segment in segments { - self.bit_array_constant_segment(eaf, segment); + self.bit_array_constant_segment(builder, segment); } - eaf.end_bit_array(bit_array); + builder.end_bit_array(bit_array); } Constant::Record { @@ -2251,12 +2296,12 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // This is a regular record call, we're building a record as // usual as a tagged tuple. Some(arguments) => { - let tuple = eaf.start_tuple(); - eaf.atom(&to_snake_case(&tag)); + let tuple = builder.start_tuple(); + builder.atom(&to_snake_case(&tag)); for argument in arguments { - self.inlined_constant(eaf, &argument.value); + self.inlined_constant(builder, &argument.value); } - eaf.end_tuple(tuple); + builder.end_tuple(tuple); } // Otherwise we are either referencing a record constructor // function, or building a record that has no fields: @@ -2274,17 +2319,17 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // ``` None => match type_::collapse_links(type_.clone()).deref() { Type::Named { .. } | Type::Var { .. } | Type::Tuple { .. } => { - eaf.atom(&to_snake_case(&tag)) + builder.atom(&to_snake_case(&tag)) } Type::Fn { arguments, .. } => { - self.record_builder_anonymous_function(eaf, &tag, arguments.len()) + self.record_builder_anonymous_function(builder, &tag, arguments.len()) } }, } } Constant::StringConcatenation { left, right, .. } => { - self.constant_string_concatenate(eaf, left, right) + self.constant_string_concatenate(builder, left, right) } Constant::RecordUpdate { .. } => { @@ -2299,28 +2344,28 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { fn bit_array_constant_segment( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, segment: &'a TypedConstantBitArraySegment, ) { - eaf.bit_array_segment(); - self.inlined_constant(eaf, &segment.value); + builder.bit_array_segment(); + self.inlined_constant(builder, &segment.value); match segment.size() { Some(TypedConstant::Int { int_value, .. }) if int_value.is_negative() => { - eaf.int(BigInt::ZERO) + builder.int(BigInt::ZERO) } - Some(size) => self.inlined_constant(eaf, size), - None => eaf.atom("default"), + Some(size) => self.inlined_constant(builder, size), + None => builder.atom("default"), }; - self.bit_array_segment_specifiers(eaf, segment); + self.bit_array_segment_specifiers(builder, segment); } fn bit_array_segment_specifiers( &self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, segment: &'a BitArraySegment>, ) { let options = segment.options.iter(); - eaf.bit_array_segment_specifiers(options.filter_map(|option| match option { + builder.bit_array_segment_specifiers(options.filter_map(|option| match option { BitArrayOption::Utf8 { .. } | BitArrayOption::Utf8Codepoint { .. } => { Some(BitArraySegmentSpecifier::Utf8) } @@ -2346,7 +2391,7 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { fn constant_string_concatenate( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, left: &'a TypedConstant, right: &'a TypedConstant, ) { @@ -2354,7 +2399,7 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { items.push_back(left); items.push_back(right); - let bit_array = eaf.start_bit_array(); + let bit_array = builder.start_bit_array(); while let Some(segment) = items.pop_front() { match segment { // When concatenating constant strings we flatten out all @@ -2401,29 +2446,29 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { | Constant::Todo { .. } => (), } - eaf.bit_array_segment(); - self.inlined_constant(eaf, segment); - eaf.atom("default"); - eaf.bit_array_segment_specifiers([BitArraySegmentSpecifier::Utf8]); + builder.bit_array_segment(); + self.inlined_constant(builder, segment); + builder.atom("default"); + builder.bit_array_segment_specifiers([BitArraySegmentSpecifier::Utf8]); } - eaf.end_bit_array(bit_array); + builder.end_bit_array(bit_array); } fn string_concatenate( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, left: &'a TypedExpr, right: &'a TypedExpr, ) { - let bit_array = eaf.start_bit_array(); - self.string_concatenate_argument(eaf, left); - self.string_concatenate_argument(eaf, right); - eaf.end_bit_array(bit_array); + let bit_array = builder.start_bit_array(); + self.string_concatenate_argument(builder, left); + self.string_concatenate_argument(builder, right); + builder.end_bit_array(bit_array); } fn string_concatenate_argument( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, value: &'a TypedExpr, ) { // String concatenation is basically building a bit array with two @@ -2432,10 +2477,10 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // the `/utf8` specifier instead! // In both cases the size is alwaus automatic, so we generate the // `default` atom. - eaf.bit_array_segment(); - self.maybe_block_expr(eaf, value); - eaf.atom("default"); - eaf.bit_array_segment_specifiers(if produces_literal_string(value) { + builder.bit_array_segment(); + self.maybe_block_expr(builder, value); + builder.atom("default"); + builder.bit_array_segment_specifiers(if produces_literal_string(value) { [BitArraySegmentSpecifier::Utf8] } else { [BitArraySegmentSpecifier::Binary] @@ -2444,7 +2489,7 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { fn bin_op( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, name: &'a BinOp, left: &'a TypedExpr, right: &'a TypedExpr, @@ -2464,38 +2509,38 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // Division needs some extra case, in Gleam dividing by 0 results // in 0; while in Erlang that's an exception. - BinOp::DivFloat => return self.float_division(eaf, left, right), - BinOp::DivInt => return self.int_division(eaf, left, right, "div"), - BinOp::RemainderInt => return self.int_division(eaf, left, right, "rem"), + BinOp::DivFloat => return self.float_division(builder, left, right), + BinOp::DivInt => return self.int_division(builder, left, right, "div"), + BinOp::RemainderInt => return self.int_division(builder, left, right, "rem"), // String concatenation is not a binop at all! It's just building a // bit array. - BinOp::Concatenate => return self.string_concatenate(eaf, left, right), + BinOp::Concatenate => return self.string_concatenate(builder, left, right), }; - eaf.binary_operator(operator); - self.maybe_block_expr(eaf, left); - self.maybe_block_expr(eaf, right); + builder.binary_operator(operator); + self.maybe_block_expr(builder, left); + self.maybe_block_expr(builder, right); } fn float_division( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, left: &'a TypedExpr, right: &'a TypedExpr, ) { match how_to_divide(left, right) { - HowToDivide::ReplaceWithZero => eaf.float(0.0), + HowToDivide::ReplaceWithZero => builder.float(0.0), HowToDivide::EvaluateLeftAndReturnZero => { // We first evaluate the left hand side, and ignore its return // value, and then we return zero directly! - self.maybe_block_expr(eaf, left); - eaf.float(0.0); + self.maybe_block_expr(builder, left); + builder.float(0.0); } HowToDivide::PlainErlangDivision => { - eaf.binary_operator("/"); - self.maybe_block_expr(eaf, left); - self.maybe_block_expr(eaf, right); + builder.binary_operator("/"); + self.maybe_block_expr(builder, left); + self.maybe_block_expr(builder, right); } HowToDivide::MatchOnRight { is_left_hand_side_pure, @@ -2504,104 +2549,75 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // result in a variable to use later. let left_name = if !is_left_hand_side_pure { let left_name = self.new_throwaway_variable(); - eaf.match_operator(); - eaf.variable_pattern(&left_name); - self.maybe_block_expr(eaf, left); + builder.match_operator(); + builder.variable_pattern(&left_name); + self.maybe_block_expr(builder, left); Some(left_name) } else { None }; - let case = eaf.start_case(); - self.maybe_block_expr(eaf, right); + let case = builder.start_case(); + self.maybe_block_expr(builder, right); // +0.0 -> +0.0 - let clause = eaf.start_case_clause(); - eaf.float_pattern(0.0); - let guards = eaf.end_clause_pattern(clause); - let body = eaf.end_clause_guards(guards); - eaf.float(0.0); - eaf.end_clause_body(body); + let clause = builder.start_case_clause(); + builder.float_pattern(0.0); + let guards = builder.end_clause_pattern(clause); + let body = builder.end_clause_guards(guards); + builder.float(0.0); + builder.end_clause_body(body); // -0.0 -> -0.0 - let clause = eaf.start_case_clause(); - eaf.float_pattern(-0.0); - let guards = eaf.end_clause_pattern(clause); - let body = eaf.end_clause_guards(guards); - eaf.float(-0.0); - eaf.end_clause_body(body); + let clause = builder.start_case_clause(); + builder.float_pattern(-0.0); + let guards = builder.end_clause_pattern(clause); + let body = builder.end_clause_guards(guards); + builder.float(-0.0); + builder.end_clause_body(body); // _value -> left / _value let denominator = self.new_throwaway_variable(); - let clause = eaf.start_case_clause(); - eaf.variable_pattern(&denominator); - let guards = eaf.end_clause_pattern(clause); - let body = eaf.end_clause_guards(guards); - eaf.binary_operator("/"); + let clause = builder.start_case_clause(); + builder.variable_pattern(&denominator); + let guards = builder.end_clause_pattern(clause); + let body = builder.end_clause_guards(guards); + builder.binary_operator("/"); // If we had bound the left hand side to a variabe we just // reference it, otherwise we will generate the code for the // numerator. if let Some(left_name) = left_name { - eaf.variable(&left_name); + builder.variable(&left_name); } else { - self.maybe_block_expr(eaf, left); + self.maybe_block_expr(builder, left); } - eaf.variable(&denominator); - eaf.end_clause_body(body); - - eaf.end_case(case); - } - } - - //if right.is_non_zero_compile_time_number() { - // eaf.binary_operator("/"); - // self.maybe_block_expr(eaf, left); - // self.maybe_block_expr(eaf, right); - //} else if left.is_literal() && right.is_zero_compile_time_number() { - // eaf.float(0.0); - //} else { - // let left = { - // self.expr(eaf, left); - // nil() - // }; - // let right = { - // self.expr(eaf, right); - // nil() - // }; - // let denominator = self.new_throwaway_variable(); - // let clauses = docvec![ - // line(), - // "+0.0 -> +0.0;", - // line(), - // "-0.0 -> -0.0;", - // line(), - // denominator.clone(), - // " -> ", - // binop_documents(left, "/", denominator.to_doc()) - // ]; - // let _ = docvec!["case ", right, " of", clauses.nest(INDENT), line(), "end"]; - //} + builder.variable(&denominator); + builder.end_clause_body(body); + + builder.end_case(case); + } + } } fn int_division( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, left: &'a TypedExpr, right: &'a TypedExpr, op: &'static str, ) { match how_to_divide(left, right) { - HowToDivide::ReplaceWithZero => eaf.int(BigInt::ZERO), + HowToDivide::ReplaceWithZero => builder.int(BigInt::ZERO), HowToDivide::EvaluateLeftAndReturnZero => { // We first evaluate the left hand side, and ignore its return // value, and then we return zero directly! - self.maybe_block_expr(eaf, left); - eaf.int(BigInt::ZERO); + self.maybe_block_expr(builder, left); + builder.int(BigInt::ZERO); } HowToDivide::PlainErlangDivision => { - eaf.binary_operator(op); - self.maybe_block_expr(eaf, left); - self.maybe_block_expr(eaf, right); + builder.binary_operator(op); + self.maybe_block_expr(builder, left); + self.maybe_block_expr(builder, right); } HowToDivide::MatchOnRight { is_left_hand_side_pure, @@ -2622,44 +2638,44 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // let left_name = if !is_left_hand_side_pure { let left_name = self.new_throwaway_variable(); - eaf.match_operator(); - eaf.variable_pattern(&left_name); - self.maybe_block_expr(eaf, left); + builder.match_operator(); + builder.variable_pattern(&left_name); + self.maybe_block_expr(builder, left); Some(left_name) } else { None }; - let case = eaf.start_case(); - self.maybe_block_expr(eaf, right); + let case = builder.start_case(); + self.maybe_block_expr(builder, right); // 0 -> 0 - let clause = eaf.start_case_clause(); - eaf.int_pattern(BigInt::ZERO); - let guards = eaf.end_clause_pattern(clause); - let body = eaf.end_clause_guards(guards); - eaf.int(BigInt::ZERO); - eaf.end_clause_body(body); + let clause = builder.start_case_clause(); + builder.int_pattern(BigInt::ZERO); + let guards = builder.end_clause_pattern(clause); + let body = builder.end_clause_guards(guards); + builder.int(BigInt::ZERO); + builder.end_clause_body(body); // _value -> left div _value let denominator = self.new_throwaway_variable(); - let clause = eaf.start_case_clause(); - eaf.variable_pattern(&denominator); - let guards = eaf.end_clause_pattern(clause); - let body = eaf.end_clause_guards(guards); - eaf.binary_operator(op); + let clause = builder.start_case_clause(); + builder.variable_pattern(&denominator); + let guards = builder.end_clause_pattern(clause); + let body = builder.end_clause_guards(guards); + builder.binary_operator(op); // If we had bound the left hand side to a variabe we just // reference it, otherwise we will generate the code for the // numerator. if let Some(left_name) = left_name { - eaf.variable(&left_name); + builder.variable(&left_name); } else { - self.maybe_block_expr(eaf, left); + self.maybe_block_expr(builder, left); } - eaf.variable(&denominator); - eaf.end_clause_body(body); + builder.variable(&denominator); + builder.end_clause_body(body); - eaf.end_case(case); + builder.end_case(case); } } } @@ -2673,7 +2689,7 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { /// fn bit_array_expression_segment( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, segment: &'a TypedExprBitArraySegment, ) { // Literal strings can have the `utf8`, `utf16`, or `utf32` options just @@ -2730,15 +2746,15 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { ExpressionSegmentStringEncoding::Utf8 => { // Gleam strings are utf8 encoded binaries, so we just need // to add the binary option and we can call it a day. - eaf.bit_array_segment(); - self.maybe_block_expr(eaf, &segment.value); - eaf.atom("default"); - eaf.bit_array_segment_specifiers([BitArraySegmentSpecifier::Binary]); + builder.bit_array_segment(); + self.maybe_block_expr(builder, &segment.value); + builder.atom("default"); + builder.bit_array_segment_specifiers([BitArraySegmentSpecifier::Binary]); return; } }; - eaf.bit_array_segment(); + builder.bit_array_segment(); // For utf16 and utf32 we need an explicit conversion using erlang's // `unicode:characters_to_binary`. The segment value will be @@ -2747,29 +2763,29 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // unicode:characters_to_binary(, utf8, {utf16, big}) // ``` let call = - eaf.start_remote_call(ErlangModuleName::new("unicode"), "characters_to_binary"); + builder.start_remote_call(ErlangModuleName::new("unicode"), "characters_to_binary"); { - self.maybe_block_expr(eaf, &segment.value); - eaf.atom("utf8"); - let tuple = eaf.start_tuple(); - eaf.atom(&format!("utf{size}")); + self.maybe_block_expr(builder, &segment.value); + builder.atom("utf8"); + let tuple = builder.start_tuple(); + builder.atom(&format!("utf{size}")); match endiannes { - Endianness::Big => eaf.atom("big"), - Endianness::Little => eaf.atom("little"), + Endianness::Big => builder.atom("big"), + Endianness::Little => builder.atom("little"), } - eaf.end_tuple(tuple); + builder.end_tuple(tuple); } - eaf.end_call(call); + builder.end_call(call); - eaf.atom("default"); - eaf.bit_array_segment_specifiers([BitArraySegmentSpecifier::Binary]); + builder.atom("default"); + builder.bit_array_segment_specifiers([BitArraySegmentSpecifier::Binary]); } else { // If the bit array segment doesn't need any special handling we use the // regular printing functions to format its value and options. - eaf.bit_array_segment(); - self.maybe_block_expr(eaf, &segment.value); - self.bit_array_expression_segment_size(eaf, segment); - self.bit_array_segment_specifiers(eaf, segment); + builder.bit_array_segment(); + self.maybe_block_expr(builder, &segment.value); + self.bit_array_expression_segment_size(builder, segment); + self.bit_array_segment_specifiers(builder, segment); } } @@ -2780,11 +2796,11 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { /// size! fn bit_array_expression_segment_size( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, segment: &'a TypedExprBitArraySegment, ) { let Some(size) = segment.size() else { - eaf.atom("default"); + builder.atom("default"); return; }; @@ -2793,46 +2809,46 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // negative value must be turned to zero instead: if let TypedExpr::Int { int_value, .. } = &size { if int_value.is_negative() { - eaf.int(BigInt::ZERO) + builder.int(BigInt::ZERO) } else { - eaf.int(int_value.clone()); + builder.int(int_value.clone()); } } else { - let call = eaf.start_remote_call(ErlangModuleName::new("erlang"), "max"); - eaf.int(BigInt::ZERO); - self.maybe_block_expr(eaf, size); - eaf.end_call(call); + let call = builder.start_remote_call(ErlangModuleName::new("erlang"), "max"); + builder.int(BigInt::ZERO); + self.maybe_block_expr(builder, size); + builder.end_call(call); } } fn clause_guard( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, guard: &'a TypedClauseGuard, assignments: &HashMap, ) { match guard { ClauseGuard::Invalid { .. } => unreachable!("invalid guard made it to code generation"), - ClauseGuard::ModuleSelect { literal, .. } => self.inlined_constant(eaf, literal), - ClauseGuard::Constant(constant) => self.inlined_constant(eaf, constant), + ClauseGuard::ModuleSelect { literal, .. } => self.inlined_constant(builder, literal), + ClauseGuard::Constant(constant) => self.inlined_constant(builder, constant), - ClauseGuard::Block { value, .. } => self.clause_guard(eaf, value, assignments), + ClauseGuard::Block { value, .. } => self.clause_guard(builder, value, assignments), ClauseGuard::TupleIndex { tuple, index, .. } => { - self.clause_guard_tuple_index(eaf, tuple, *index) + self.clause_guard_tuple_index(builder, tuple, *index) } ClauseGuard::FieldAccess { container, index, .. } => self.clause_guard_tuple_index( - eaf, + builder, container, index.expect("Unable to find index") + 1, ), ClauseGuard::Not { expression, .. } => { - eaf.unary_operator("not"); - self.clause_guard(eaf, expression, assignments); + builder.unary_operator("not"); + self.clause_guard(builder, expression, assignments); } ClauseGuard::BinaryOperator { @@ -2857,13 +2873,18 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { BinOp::DivInt => "div", BinOp::RemainderInt => "rem", BinOp::Concatenate => { - return self.clause_guard_string_concatenate(eaf, left, right, assignments); + return self.clause_guard_string_concatenate( + builder, + left, + right, + assignments, + ); } }; - eaf.binary_operator(operator); - self.clause_guard(eaf, left, assignments); - self.clause_guard(eaf, right, assignments); + builder.binary_operator(operator); + self.clause_guard(builder, left, assignments); + self.clause_guard(builder, right, assignments); } // Only local variables are supported and the typer ensures that all @@ -2878,11 +2899,11 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // generated code the variable is only defined later, so just // referencing its name would result in an error. match assignments.get(name) { - Some(AliasedLiteral::String { value, .. }) => eaf.string(value), - Some(AliasedLiteral::Int { value, .. }) => eaf.int(value.clone()), - Some(AliasedLiteral::Float { value, .. }) => eaf.float(value.value()), + Some(AliasedLiteral::String { value, .. }) => builder.string(value), + Some(AliasedLiteral::Int { value, .. }) => builder.int(value.clone()), + Some(AliasedLiteral::Float { value, .. }) => builder.float(value.value()), None => { - eaf.variable(&self.local_var_name(definition_location)); + builder.variable(&self.local_var_name(definition_location)); } } } @@ -2891,32 +2912,32 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { fn clause_guard_tuple_index( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, tuple: &'a TypedClauseGuard, index: u64, ) { - let call = eaf.start_remote_call(ErlangModuleName::new("erlang"), "element"); - eaf.int((index + 1).into()); - self.clause_guard(eaf, tuple, &HashMap::new()); - eaf.end_call(call); + let call = builder.start_remote_call(ErlangModuleName::new("erlang"), "element"); + builder.int((index + 1).into()); + self.clause_guard(builder, tuple, &HashMap::new()); + builder.end_call(call); } fn clause_guard_string_concatenate( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, left: &'a TypedClauseGuard, right: &'a TypedClauseGuard, assignments: &HashMap, ) { - let bit_array = eaf.start_bit_array(); - self.clause_guard_string_concatenate_argument(eaf, left, assignments); - self.clause_guard_string_concatenate_argument(eaf, right, assignments); - eaf.end_bit_array(bit_array); + let bit_array = builder.start_bit_array(); + self.clause_guard_string_concatenate_argument(builder, left, assignments); + self.clause_guard_string_concatenate_argument(builder, right, assignments); + builder.end_bit_array(bit_array); } fn clause_guard_string_concatenate_argument( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, guard: &'a TypedClauseGuard, assignments: &HashMap, ) { @@ -2926,10 +2947,10 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { // the `/utf8` specifier instead! // In both cases the size is alwaus automatic, so we generate the // `default` atom. - eaf.bit_array_segment(); - self.clause_guard(eaf, guard, assignments); - eaf.atom("default"); - eaf.bit_array_segment_specifiers(if guard_produces_literal_string(guard) { + builder.bit_array_segment(); + self.clause_guard(builder, guard, assignments); + builder.atom("default"); + builder.bit_array_segment_specifiers(if guard_produces_literal_string(guard) { [BitArraySegmentSpecifier::Utf8] } else { [BitArraySegmentSpecifier::Binary] @@ -2963,27 +2984,27 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { /// fn record_builder_anonymous_function( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, record_name: &str, arguments: usize, ) { let arguments = (0..arguments) .map(|_| self.new_throwaway_variable()) .collect_vec(); - let function = eaf.start_anonymous_function(&arguments); + let function = builder.start_anonymous_function(&arguments); if arguments.is_empty() { - eaf.atom(&to_snake_case(record_name)) + builder.atom(&to_snake_case(record_name)) } else { - let tuple = eaf.start_tuple(); - eaf.atom(&to_snake_case(record_name)); + let tuple = builder.start_tuple(); + builder.atom(&to_snake_case(record_name)); for argument in arguments { - eaf.variable(&argument); + builder.variable(&argument); } - eaf.end_tuple(tuple) + builder.end_tuple(tuple) } - eaf.end_function(function); + builder.end_function(function); } /// After generating a pattern we might have to generate additional variable @@ -2991,7 +3012,7 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { /// This adds those variable to the current body. fn pattern_assignments( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, variables_to_add_later: HashMap, ) { let variables_to_add_later = variables_to_add_later @@ -2999,19 +3020,19 @@ impl<'a, 'generator> FunctionGenerator<'a, 'generator> { .sorted_by(|(one, _), (other, _)| one.cmp(other)); for (gleam_name, value) in variables_to_add_later { - eaf.match_operator(); + builder.match_operator(); match value { AliasedLiteral::String { location, value } => { - eaf.variable_pattern(&self.new_erlang_variable(&gleam_name, location)); - eaf.string(&value); + builder.variable_pattern(&self.new_erlang_variable(&gleam_name, location)); + builder.string(&value); } AliasedLiteral::Float { location, value } => { - eaf.variable_pattern(&self.new_erlang_variable(&gleam_name, location)); - eaf.float(value.value()); + builder.variable_pattern(&self.new_erlang_variable(&gleam_name, location)); + builder.float(value.value()); } AliasedLiteral::Int { location, value } => { - eaf.variable_pattern(&self.new_erlang_variable(&gleam_name, location)); - eaf.int(value.clone()); + builder.variable_pattern(&self.new_erlang_variable(&gleam_name, location)); + builder.int(value.clone()); } } } @@ -3152,28 +3173,6 @@ fn how_to_call<'a>(function: &'a TypedExpr) -> FunctionCall<'a> { } }, - //TypedExpr::Fn { kind, body, .. } if kind.is_capture() => { - // if let Statement::Expression(TypedExpr::Call { - // fun, - // arguments: inner_arguments, - // .. - // }) = body.first() - // { - // let mut merged_arguments = Vec::with_capacity(inner_arguments.len()); - // for arg in inner_arguments { - // if let TypedExpr::Var { name, .. } = &arg.value - // && name == CAPTURE_VARIABLE - // { - // merged_arguments.push(arguments.swap_remove(0)) - // } else { - // merged_arguments.push(self.maybe_block_expr(eaf, &arg.value)) - // } - // } - // self.docs_arguments_call(eaf, fun, merged_arguments) - // } else { - // panic!("Erl printing: Capture was not a call") - // } - //} TypedExpr::Fn { .. } | TypedExpr::Call { .. } | TypedExpr::Todo { .. } @@ -3264,19 +3263,19 @@ fn how_to_divide(left: &TypedExpr, right: &TypedExpr) -> HowToDivide { } pub fn record_definition(record_name: &str, fields: &[(&str, Arc)]) -> String { - let mut eaf = PrettyEaf::new(None); + let mut builder = ErlangSourceBuilder::new(None); - let record = eaf.start_record_attribute(&to_snake_case(record_name)); + let record = builder.start_record_attribute(&to_snake_case(record_name)); let type_printer = TypeGenerator::new("").var_as_any(); for (field_name, field_type) in fields { - eaf.record_field(); - eaf.atom(field_name); - type_printer.type_(&mut eaf, field_type); + builder.record_field(); + builder.atom(field_name); + type_printer.type_(&mut builder, field_type); } - eaf.end_record_attribute(record); - eaf.into_output() + builder.end_record_attribute(record); + builder.into_output() } pub fn module<'a>( @@ -3285,10 +3284,10 @@ pub fn module<'a>( root: &'a Utf8Path, ) -> String { let mut generator = Generator::new(module, line_numbers, root); - let mut eaf = PrettyEaf::new(Some(ErlangModuleName::new(&module.name))); - generator.module_document(&mut eaf); + let mut builder = ErlangSourceBuilder::new(Some(ErlangModuleName::new(&module.name))); + generator.module_document(&mut builder); - let mut output = eaf.into_output(); + let mut output = builder.into_output(); if generator.echo_used { output.push_str(std::include_str!("../templates/echo.erl")); } @@ -3882,49 +3881,49 @@ impl<'a> TypeGenerator<'a> { self } - pub fn type_(&self, eaf: &mut impl Eaf, type_: &Type) { + pub fn type_(&self, builder: &mut impl ErlangBuilder, type_: &Type) { match type_ { - Type::Var { type_ } => self.type_variable(eaf, &type_.borrow()), + Type::Var { type_ } => self.type_variable(builder, &type_.borrow()), Type::Named { name, module, arguments, .. - } if is_prelude_module(module) => self.prelude_type(eaf, name, arguments), + } if is_prelude_module(module) => self.prelude_type(builder, name, arguments), Type::Named { name, module, arguments, .. - } => self.named_type(eaf, module.into(), name, arguments), + } => self.named_type(builder, module.into(), name, arguments), Type::Fn { arguments, return_ } => { - let function_type = eaf.start_function_type(); + let function_type = builder.start_function_type(); for argument in arguments { - self.type_(eaf, argument); + self.type_(builder, argument); } - let function_type = eaf.end_function_type_arguments(function_type); - self.type_(eaf, return_); - eaf.end_function_type(function_type); + let function_type = builder.end_function_type_arguments(function_type); + self.type_(builder, return_); + builder.end_function_type(function_type); } Type::Tuple { elements } => { - let tuple = eaf.start_tuple_type(); + let tuple = builder.start_tuple_type(); for element in elements { - self.type_(eaf, element) + self.type_(builder, element) } - eaf.end_tuple_type(tuple); + builder.end_tuple_type(tuple); } } } - fn type_variable(&self, eaf: &mut impl Eaf, type_: &TypeVar) { + fn type_variable(&self, builder: &mut impl ErlangBuilder, type_: &TypeVar) { match type_ { - TypeVar::Link { type_ } => self.type_(eaf, type_), + TypeVar::Link { type_ } => self.type_(builder, type_), TypeVar::Generic { id, .. } | TypeVar::Unbound { id, .. } => { if self.var_as_any || self.type_variable_is_used_exactly_once(*id) { - let any = eaf.start_named_type("any"); - eaf.end_named_type(any); + let any = builder.start_named_type("any"); + builder.end_named_type(any); } else { - eaf.type_variable(&id_to_type_var_str(*id)) + builder.type_variable(&id_to_type_var_str(*id)) } } } @@ -3943,58 +3942,58 @@ impl<'a> TypeGenerator<'a> { fn prelude_type( &self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, name: &str, arguments: &[Arc], ) { match name { - "Nil" => eaf.literal_atom_type("nil"), + "Nil" => builder.literal_atom_type("nil"), "Int" | "UtfCodepoint" => { - let integer = eaf.start_named_type("integer"); - eaf.end_named_type(integer); + let integer = builder.start_named_type("integer"); + builder.end_named_type(integer); } "String" => { - let string = eaf.start_named_type("binary"); - eaf.end_named_type(string); + let string = builder.start_named_type("binary"); + builder.end_named_type(string); } "Bool" => { - let boolean = eaf.start_named_type("boolean"); - eaf.end_named_type(boolean); + let boolean = builder.start_named_type("boolean"); + builder.end_named_type(boolean); } "Float" => { - let float = eaf.start_named_type("float"); - eaf.end_named_type(float); + let float = builder.start_named_type("float"); + builder.end_named_type(float); } "BitArray" => { - let bitstring = eaf.start_named_type("bitstring"); - eaf.end_named_type(bitstring); + let bitstring = builder.start_named_type("bitstring"); + builder.end_named_type(bitstring); } "List" => { - let list = eaf.start_named_type("list"); + let list = builder.start_named_type("list"); let list_item = arguments .first() .expect("prelude type list with no argument"); - self.type_(eaf, list_item); - eaf.end_named_type(list); + self.type_(builder, list_item); + builder.end_named_type(list); } "Result" => { let [ok_type, error_type] = arguments else { panic!("result type with no ok and err types") }; - let result = eaf.start_union_type(); + let result = builder.start_union_type(); - let ok = eaf.start_tuple_type(); - eaf.literal_atom_type("ok"); - self.type_(eaf, ok_type); - eaf.end_tuple_type(ok); + let ok = builder.start_tuple_type(); + builder.literal_atom_type("ok"); + self.type_(builder, ok_type); + builder.end_tuple_type(ok); - let error = eaf.start_tuple_type(); - eaf.literal_atom_type("error"); - self.type_(eaf, error_type); - eaf.end_tuple_type(error); + let error = builder.start_tuple_type(); + builder.literal_atom_type("error"); + self.type_(builder, error_type); + builder.end_tuple_type(error); - eaf.end_union_type(result); + builder.end_union_type(result); } // Getting here should mean we either forgot a built-in type or there is a @@ -4005,23 +4004,23 @@ impl<'a> TypeGenerator<'a> { fn named_type( &self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, module: EcoString, name: &str, arguments: &[Arc], ) { let name = erl_safe_type_name(to_snake_case(name)); let type_ = if self.current_module == module { - eaf.start_named_type(&name) + builder.start_named_type(&name) } else { - eaf.start_remote_named_type(ErlangModuleName::new(&module), &name) + builder.start_remote_named_type(ErlangModuleName::new(&module), &name) }; for argument in arguments { - self.type_(eaf, argument) + self.type_(builder, argument) } - eaf.end_named_type(type_); + builder.end_named_type(type_); } } diff --git a/compiler-core/src/erlang/pattern.rs b/compiler-core/src/erlang/pattern.rs index aee9051e6..07aab11fe 100644 --- a/compiler-core/src/erlang/pattern.rs +++ b/compiler-core/src/erlang/pattern.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2021 The Gleam contributors -use erlang_abstract_format::BitArraySegmentSpecifier; +use erlang_generation::BitArraySegmentSpecifier; use crate::{analyse::Inferred, parse::LiteralFloatValue}; @@ -129,16 +129,16 @@ impl<'a, 'generator, 'module> PatternGenerator<'a, 'generator, 'module> { pub(super) fn pattern( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, pattern: &'a TypedPattern, ) { match pattern { - Pattern::Discard { .. } => eaf.discard_pattern(), - Pattern::Float { float_value, .. } => eaf.float_pattern(float_value.value()), - Pattern::Int { int_value, .. } => eaf.int_pattern(int_value.clone()), - Pattern::String { value, .. } => eaf.string_pattern(value), + Pattern::Discard { .. } => builder.discard_pattern(), + Pattern::Float { float_value, .. } => builder.float_pattern(float_value.value()), + Pattern::Int { int_value, .. } => builder.int_pattern(int_value.clone()), + Pattern::String { value, .. } => builder.string_pattern(value), Pattern::Variable { name, location, .. } => { - eaf.variable_pattern(&self.generator.new_erlang_variable(name, *location)) + builder.variable_pattern(&self.generator.new_erlang_variable(name, *location)) } Pattern::Assign { @@ -146,28 +146,28 @@ impl<'a, 'generator, 'module> PatternGenerator<'a, 'generator, 'module> { pattern, location, } => { - eaf.match_pattern(); - self.pattern(eaf, pattern); - eaf.variable_pattern(&self.generator.new_erlang_variable(name, *location)); + builder.match_pattern(); + self.pattern(builder, pattern); + builder.variable_pattern(&self.generator.new_erlang_variable(name, *location)); } Pattern::Tuple { elements, .. } => { - let tuple = eaf.start_tuple_pattern(); + let tuple = builder.start_tuple_pattern(); for element in elements { - self.pattern(eaf, element); + self.pattern(builder, element); } - eaf.end_tuple_pattern(tuple); + builder.end_tuple_pattern(tuple); } Pattern::List { elements, tail, .. } => { for element in elements { - eaf.cons_list_pattern(); - self.pattern(eaf, element); + builder.cons_list_pattern(); + self.pattern(builder, element); } if let Some(tail) = tail { - self.pattern(eaf, &tail.pattern); + self.pattern(builder, &tail.pattern); } else { - eaf.empty_list_pattern(); + builder.empty_list_pattern(); } } @@ -181,14 +181,14 @@ impl<'a, 'generator, 'module> PatternGenerator<'a, 'generator, 'module> { }; if arguments.is_empty() { - eaf.atom_pattern(&to_snake_case(name)); + builder.atom_pattern(&to_snake_case(name)); } else { - let tuple = eaf.start_tuple_pattern(); - eaf.atom_pattern(&to_snake_case(name)); + let tuple = builder.start_tuple_pattern(); + builder.atom_pattern(&to_snake_case(name)); for argument in arguments { - self.pattern(eaf, &argument.value); + self.pattern(builder, &argument.value); } - eaf.end_tuple_pattern(tuple); + builder.end_tuple_pattern(tuple); } } @@ -212,40 +212,41 @@ impl<'a, 'generator, 'module> PatternGenerator<'a, 'generator, 'module> { ); } - let bit_array = eaf.start_bit_array_pattern(); + let bit_array = builder.start_bit_array_pattern(); // We first generate a segment matching on the literal prefix. - eaf.bit_array_segment(); - eaf.string_pattern(left_side_string); - eaf.atom("deafult"); - eaf.bit_array_segment_specifiers([BitArraySegmentSpecifier::Utf8]); + builder.bit_array_segment(); + builder.string_pattern(left_side_string); + builder.atom("deafult"); + builder.bit_array_segment_specifiers([BitArraySegmentSpecifier::Utf8]); // We then add a segment matching on the rest of the string. - eaf.bit_array_segment(); + builder.bit_array_segment(); match right_side_assignment { - AssignName::Variable(name) => eaf.variable_pattern( + AssignName::Variable(name) => builder.variable_pattern( &self.generator.new_erlang_variable(name, *right_location), ), - AssignName::Discard(_) => eaf.discard_pattern(), + AssignName::Discard(_) => builder.discard_pattern(), } - eaf.atom("default"); - eaf.bit_array_segment_specifiers([BitArraySegmentSpecifier::Binary]); + builder.atom("default"); + builder.bit_array_segment_specifiers([BitArraySegmentSpecifier::Binary]); - eaf.end_bit_array_pattern(bit_array); + builder.end_bit_array_pattern(bit_array); } Pattern::BitArray { segments, .. } => { - let bit_array = eaf.start_bit_array_pattern(); + let bit_array = builder.start_bit_array_pattern(); for segment in segments { - eaf.bit_array_segment(); - self.bit_array_pattern_segment_value(eaf, segment); - self.bit_array_pattern_segment_size(eaf, segment); - self.generator.bit_array_segment_specifiers(eaf, segment); + builder.bit_array_segment(); + self.bit_array_pattern_segment_value(builder, segment); + self.bit_array_pattern_segment_size(builder, segment); + self.generator + .bit_array_segment_specifiers(builder, segment); } - eaf.end_bit_array_pattern(bit_array); + builder.end_bit_array_pattern(bit_array); } - Pattern::BitArraySize(size) => self.bit_array_size(eaf, size), + Pattern::BitArraySize(size) => self.bit_array_size(builder, size), Pattern::Invalid { .. } => { panic!("invalid patterns should not reach code generation") @@ -253,24 +254,28 @@ impl<'a, 'generator, 'module> PatternGenerator<'a, 'generator, 'module> { } } - fn bit_array_size(&mut self, eaf: &mut impl Eaf, size: &'a TypedBitArraySize) { + fn bit_array_size( + &mut self, + builder: &mut impl ErlangBuilder, + size: &'a TypedBitArraySize, + ) { match size { - BitArraySize::Int { int_value, .. } => eaf.int(int_value.clone()), - BitArraySize::Block { inner, .. } => self.bit_array_size(eaf, inner), + BitArraySize::Int { int_value, .. } => builder.int(int_value.clone()), + BitArraySize::Block { inner, .. } => self.bit_array_size(builder, inner), BitArraySize::Variable { constructor, name, .. } => match self.variables_to_add_later.get(name) { - Some(AliasedLiteral::Int { value, .. }) => eaf.int(value.clone()), + Some(AliasedLiteral::Int { value, .. }) => builder.int(value.clone()), Some(_) => panic!("segment size that is not int made it through type checking"), None => { let constructor = constructor.as_ref().expect("variable with no constructor"); match &constructor.variant { ValueConstructorVariant::ModuleConstant { literal, .. } => { - self.generator.inlined_constant(eaf, literal) + self.generator.inlined_constant(builder, literal) } ValueConstructorVariant::LocalVariable { location, .. } => { - eaf.variable(&self.generator.local_var_name(location)) + builder.variable(&self.generator.local_var_name(location)) } ValueConstructorVariant::ModuleFn { .. } | ValueConstructorVariant::Record { .. } => panic!("invalid segment"), @@ -289,22 +294,22 @@ impl<'a, 'generator, 'module> PatternGenerator<'a, 'generator, 'module> { IntOperator::Subtract => "-", IntOperator::Multiply => "*", IntOperator::Divide => { - return self.bit_array_size_divide(eaf, left, right, "div"); + return self.bit_array_size_divide(builder, left, right, "div"); } IntOperator::Remainder => { - return self.bit_array_size_divide(eaf, left, right, "rem"); + return self.bit_array_size_divide(builder, left, right, "rem"); } }; - eaf.binary_operator(operator); - self.bit_array_size(eaf, left); - self.bit_array_size(eaf, right); + builder.binary_operator(operator); + self.bit_array_size(builder, left); + self.bit_array_size(builder, right); } } } fn bit_array_pattern_segment_value( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, segment: &'a TypedPatternBitArraySegment, ) { let Pattern::Assign { @@ -315,7 +320,7 @@ impl<'a, 'generator, 'module> PatternGenerator<'a, 'generator, 'module> { else { // If the pattern is not an assign, it needs no extra care, we can // just produce the code for such pattern! - self.pattern(eaf, &segment.value); + self.pattern(builder, &segment.value); return; }; @@ -349,7 +354,7 @@ impl<'a, 'generator, 'module> PatternGenerator<'a, 'generator, 'module> { // pattern, that makes things even simpler, we can just produce the // code for a variable pattern with the wanted name and call it a day Pattern::Discard { .. } => { - eaf.variable_pattern(&self.generator.new_erlang_variable(name, *location)); + builder.variable_pattern(&self.generator.new_erlang_variable(name, *location)); return; } @@ -369,56 +374,56 @@ impl<'a, 'generator, 'module> PatternGenerator<'a, 'generator, 'module> { let _ = self .variables_to_add_later .insert(name.clone(), aliased_value); - self.pattern(eaf, pattern); + self.pattern(builder, pattern); } fn bit_array_pattern_segment_size( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, segment: &'a TypedPatternBitArraySegment, ) { let Some(size) = segment.size() else { - eaf.atom("default"); + builder.atom("default"); return; }; let TypedPattern::BitArraySize(size) = size else { panic!("invalid size in pattern size segment") }; - self.bit_array_size(eaf, size); + self.bit_array_size(builder, size); } fn bit_array_size_divide( &mut self, - eaf: &mut impl Eaf, + builder: &mut impl ErlangBuilder, left: &'a TypedBitArraySize, right: &'a TypedBitArraySize, operator: &'static str, ) { if right.non_zero_compile_time_number() { - eaf.binary_operator(operator); - self.bit_array_size(eaf, left); - self.bit_array_size(eaf, right); + builder.binary_operator(operator); + self.bit_array_size(builder, left); + self.bit_array_size(builder, right); } else { - let case = eaf.start_case(); - self.bit_array_size(eaf, right); + let case = builder.start_case(); + self.bit_array_size(builder, right); - let clause = eaf.start_case_clause(); - eaf.int_pattern(BigInt::ZERO); - let clause = eaf.end_clause_pattern(clause); - let clause = eaf.end_clause_guards(clause); - eaf.int(BigInt::ZERO); - eaf.end_clause_body(clause); + let clause = builder.start_case_clause(); + builder.int_pattern(BigInt::ZERO); + let clause = builder.end_clause_pattern(clause); + let clause = builder.end_clause_guards(clause); + builder.int(BigInt::ZERO); + builder.end_clause_body(clause); - let clause = eaf.start_case_clause(); + let clause = builder.start_case_clause(); let denominator = self.generator.new_throwaway_variable(); - eaf.variable_pattern(&denominator); - let clause = eaf.end_clause_pattern(clause); - let clause = eaf.end_clause_guards(clause); - eaf.binary_operator(operator); - self.bit_array_size(eaf, left); - eaf.variable(&denominator); - eaf.end_clause_body(clause); - eaf.end_case(case); + builder.variable_pattern(&denominator); + let clause = builder.end_clause_pattern(clause); + let clause = builder.end_clause_guards(clause); + builder.binary_operator(operator); + self.bit_array_size(builder, left); + builder.variable(&denominator); + builder.end_clause_body(clause); + builder.end_case(case); } } } diff --git a/erlang-abstract-format/Cargo.toml b/erlang-generation/Cargo.toml similarity index 93% rename from erlang-abstract-format/Cargo.toml rename to erlang-generation/Cargo.toml index 97867bbf7..8d833c327 100644 --- a/erlang-abstract-format/Cargo.toml +++ b/erlang-generation/Cargo.toml @@ -2,7 +2,7 @@ # SPDX-FileCopyrightText: 2026 The Gleam contributors [package] -name = "erlang-abstract-format" +name = "erlang-generation" authors = ["Louis Pilfold "] version = "1.0.0" edition = "2024" diff --git a/erlang-abstract-format/src/lib.rs b/erlang-generation/src/lib.rs similarity index 80% rename from erlang-abstract-format/src/lib.rs rename to erlang-generation/src/lib.rs index 64625c441..7a0031e45 100644 --- a/erlang-abstract-format/src/lib.rs +++ b/erlang-generation/src/lib.rs @@ -39,8 +39,8 @@ impl ErlangModuleName { #[must_use] /// Represents an open function that has yet to be closed. -/// A function definition is started with `Eaf::start_function` and _must_ be -/// closed using `Eaf::end_function`. +/// A function definition is started with `ErlangBuilder::start_function` and +/// _must_ be closed using `ErlangBuilder::end_function`. pub struct Function { clauses: erlang_term_format::List, statements: erlang_term_format::List, @@ -187,7 +187,8 @@ pub enum BitArraySegmentSpecifier { Unit(u8), } -/// Defines the operations to describe the content of an Erlang module. +/// A trait defining operations to describe the content of an Erlang module. +/// /// This might look strange in places, for example why is there a `start_tuple` /// and `end_tuple` function, but lists are built using `cons_list` and not a /// `start_list` and `end_list` function? @@ -200,8 +201,8 @@ pub enum BitArraySegmentSpecifier { /// it's gonna be handy: /// https://www.erlang.org/doc/apps/erts/absform.html /// -pub trait Eaf { - /// Creates a new `Eaf` data structure to generate Erlang code. +pub trait ErlangBuilder { + /// Creates a new `ErlangBuilder` data structure to generate Erlang code. /// If a module name is provided this will also automatically take care of /// generating the appropriate `-module` annotation at the very beginning. /// @@ -210,7 +211,8 @@ pub trait Eaf { /// fn new(module_name: Option) -> Self; - /// Consumes the given `Eaf` turning it into some other representation. + /// Consumes the given `ErlangBuilder` turning it into some other + /// representation. /// For example that might be a binary representation, or a textual pretty /// printed one. /// @@ -221,7 +223,7 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// eaf.export_attribute(vec![("wibble", 1), ("wobble", 2)]); + /// builder.export_attribute(vec![("wibble", 1), ("wobble", 2)]); /// ``` /// /// Corresponds to: @@ -240,7 +242,7 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// eaf.export_attribute(vec![("wibble", 1), ("wobble", 2)]); + /// builder.export_attribute(vec![("wibble", 1), ("wobble", 2)]); /// ``` /// /// Corresponds to: @@ -262,9 +264,9 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let doc = eaf.start_doc_attribute(); - /// eaf.atom("false"); - /// eaf.close_doc_attribute(doc); + /// let doc = builder.start_doc_attribute(); + /// builder.atom("false"); + /// builder.close_doc_attribute(doc); /// ``` /// /// Corresponds to: @@ -283,9 +285,9 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let doc = eaf.start_moduledoc_attribute(); - /// eaf.atom("false"); - /// eaf.close_doc_attribute(doc); + /// let doc = builder.start_moduledoc_attribute(); + /// builder.atom("false"); + /// builder.close_doc_attribute(doc); /// ``` /// /// Corresponds to: @@ -308,7 +310,7 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// eaf.compile_attribute(vec!["no_warn", "inline"]); + /// builder.compile_attribute(vec!["no_warn", "inline"]); /// ``` /// /// Corresponds to: @@ -323,7 +325,7 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// eaf.file_attribute("wibble.gleam", 2.into()); + /// builder.file_attribute("wibble.gleam", 2.into()); /// ``` /// /// Correspods to: @@ -341,11 +343,11 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let record = eaf.start_record_attribute("wobble"); - /// eaf.record_field(); - /// eaf.atom("wibble"); - /// eaf.literal_atom_type("ok"); - /// eaf.close_record_attribute(record); + /// let record = builder.start_record_attribute("wobble"); + /// builder.record_field(); + /// builder.atom("wibble"); + /// builder.literal_atom_type("ok"); + /// builder.close_record_attribute(record); /// ``` /// /// Corresponds to: @@ -380,12 +382,12 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let spec = eaf.start_function_spec("wibble", 1) - /// let function_type = eaf.start_function_type(); - /// eaf.int_type(); - /// let function_type eaf.end_function_type_arguments(function_type); - /// eaf.variable_type("A"); - /// eaf.end_function_type(function_type); + /// let spec = builder.start_function_spec("wibble", 1) + /// let function_type = builder.start_function_type(); + /// builder.int_type(); + /// let function_type builder.end_function_type_arguments(function_type); + /// builder.variable_type("A"); + /// builder.end_function_type(function_type); /// ``` /// /// Corresponds to: @@ -408,16 +410,16 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let spec = eaf.start_type_spec(false, "wibble", ["A"]); + /// let spec = builder.start_type_spec(false, "wibble", ["A"]); /// - /// let union = eaf.start_union_type(); - /// eaf.literal_atom_type("nil"); + /// let union = builder.start_union_type(); + /// builder.literal_atom_type("nil"); /// - /// let list = eaf.start_named_type("list"); - /// eaf.type_variable("A") - /// eaf.close_named_type(); + /// let list = builder.start_named_type("list"); + /// builder.type_variable("A") + /// builder.close_named_type(); /// - /// eaf.end_uniont_type(union); + /// builder.end_uniont_type(union); /// ``` /// /// Corresponds to: @@ -442,12 +444,12 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let function_type = eaf.start_function_type(); - /// eaf.int_type(); - /// eaf.variable_type("A"); - /// let function_type eaf.end_function_type_arguments(function_type); - /// eaf.variable_type("A"); - /// eaf.end_function_type(function_type); + /// let function_type = builder.start_function_type(); + /// builder.int_type(); + /// builder.variable_type("A"); + /// let function_type builder.end_function_type_arguments(function_type); + /// builder.variable_type("A"); + /// builder.end_function_type(function_type); /// ``` /// /// Corresponds to: @@ -481,8 +483,8 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let integer = eaf.start_named_type("integer"); - /// eaf.end_named_type(integer); + /// let integer = builder.start_named_type("integer"); + /// builder.end_named_type(integer); /// ``` /// /// Corresponds to: @@ -500,8 +502,8 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let type_ = eaf.start_remote_named_type("wibble", "wobble"); - /// eaf.end_named_type(type_); + /// let type_ = builder.start_remote_named_type("wibble", "wobble"); + /// builder.end_named_type(type_); /// ``` /// /// Corresponds to: @@ -523,10 +525,10 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let tuple = eaf.start_tuple_type(); - /// eaf.literal_atom_type("nil"); - /// eaf.literal_atom_type("ok"); - /// eaf.end_tuple_type(tuple); + /// let tuple = builder.start_tuple_type(); + /// builder.literal_atom_type("nil"); + /// builder.literal_atom_type("ok"); + /// builder.end_tuple_type(tuple); /// ``` /// /// Corresponds to the following Erlang type: @@ -549,10 +551,10 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let ok_or_error = eaf.start_union_type(); - /// eaf.literal_atom_type("ok"); - /// eaf.literal_atom_type("error"); - /// eaf.end_union_type(ok_or_error); + /// let ok_or_error = builder.start_union_type(); + /// builder.literal_atom_type("ok"); + /// builder.literal_atom_type("error"); + /// builder.end_union_type(ok_or_error); /// ``` /// /// Corresponds to: @@ -574,11 +576,11 @@ pub trait Eaf { /// could do it like this: /// /// ```ignore - /// let function = eaf.start_function_type(); - /// eaf.type_variable("A"); - /// let function = eaf.end_function_type_arguments(); - /// eaf.type_variable("A"); - /// eaf.end_function(function); + /// let function = builder.start_function_type(); + /// builder.type_variable("A"); + /// let function = builder.end_function_type_arguments(); + /// builder.type_variable("A"); + /// builder.end_function(function); /// ``` /// /// And it corresponds to: @@ -595,10 +597,10 @@ pub trait Eaf { /// be defined like this: /// /// ```ignore - /// let function = eaf.start_function_type(); - /// let function = eaf.end_function_type_arguments(); - /// eaf.literal_atom_type("nil"); - /// eaf.end_function(function); + /// let function = builder.start_function_type(); + /// let function = builder.end_function_type_arguments(); + /// builder.literal_atom_type("nil"); + /// builder.end_function(function); /// ``` /// /// And it corresponds to: @@ -617,9 +619,9 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let function = eaf.start_function("first_name", 0, vec![]); - /// eaf.string("Giacomo"); - /// eaf.end_function(function); + /// let function = builder.start_function("first_name", 0, vec![]); + /// builder.string("Giacomo"); + /// builder.end_function(function); /// ``` /// /// Corresponds to: @@ -642,9 +644,9 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let function = eaf.start_anonymous_function([]); - /// eaf.string("Erlang rocks"); - /// eaf.end_anonymous_function(function); + /// let function = builder.start_anonymous_function([]); + /// builder.string("Erlang rocks"); + /// builder.end_anonymous_function(function); /// ``` /// /// Corresponds to: @@ -670,10 +672,10 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let block = eaf.start_block(); - /// eaf.string("Giacomo"); - /// eaf.int(1); - /// eaf.end_block(block); + /// let block = builder.start_block(); + /// builder.string("Giacomo"); + /// builder.int(1); + /// builder.end_block(block); /// ``` /// /// Corresponds to: @@ -699,9 +701,9 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let call = eaf.start_remote_call("io", "format"); - /// eaf.string("Giacomo"); - /// eaf.end_call(call); + /// let call = builder.start_remote_call("io", "format"); + /// builder.string("Giacomo"); + /// builder.end_call(call); /// ``` /// /// Corresponds to: @@ -719,11 +721,11 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let call = eaf.start_call(); - /// eaf.atom("wibble") - /// eaf.string("Hello"); - /// eaf.string("Giacomo"); - /// eaf.end_call(call); + /// let call = builder.start_call(); + /// builder.atom("wibble") + /// builder.string("Hello"); + /// builder.string("Giacomo"); + /// builder.end_call(call); /// ``` /// /// Corresponds to: @@ -745,10 +747,10 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let tuple = eaf.start_tuple(); - /// eaf.string("Hello"); - /// eaf.int(1); - /// eaf.end_tuple(tuple); + /// let tuple = builder.start_tuple(); + /// builder.string("Hello"); + /// builder.int(1); + /// builder.end_tuple(tuple); /// ``` /// /// Corresponds to: @@ -771,15 +773,15 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let map = eaf.start_map(); + /// let map = builder.start_map(); /// - /// eaf.map_field(); - /// eaf.atom("gleam_error") - /// eaf.atom("todo"); + /// builder.map_field(); + /// builder.atom("gleam_error") + /// builder.atom("todo"); /// - /// eaf.map_field(); - /// eaf.atom("line"); - /// eaf.int(6.into()); + /// builder.map_field(); + /// builder.atom("line"); + /// builder.int(6.into()); /// ``` /// /// Corresponds to: @@ -810,19 +812,19 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let bit_array = eaf.start_bit_array(); + /// let bit_array = builder.start_bit_array(); /// - /// eaf.bit_array_segment(); - /// eaf.int(1); - /// eaf.atom("default"); - /// eaf.atom("default"); + /// builder.bit_array_segment(); + /// builder.int(1); + /// builder.atom("default"); + /// builder.atom("default"); /// - /// eaf.bit_array_segment(); - /// eaf.string("hello"); - /// eaf.atom("deafult"); - /// eaf.atom("default"); + /// builder.bit_array_segment(); + /// builder.string("hello"); + /// builder.atom("deafult"); + /// builder.atom("default"); /// - /// eaf.end_bit_array(bit_array); + /// builder.end_bit_array(bit_array); /// ``` /// /// Corresponds to: @@ -879,11 +881,11 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// eaf.cons_list(); - /// eaf.variable("Hello"); - /// eaf.cons_list(); - /// eaf.string("Giacomo"); - /// eaf.empty_list(); + /// builder.cons_list(); + /// builder.variable("Hello"); + /// builder.cons_list(); + /// builder.string("Giacomo"); + /// builder.empty_list(); /// ``` /// /// Corresponds to: @@ -911,17 +913,17 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let case = eaf.start_case(); - /// eaf.variable("wibble"); + /// let case = builder.start_case(); + /// builder.variable("wibble"); /// - /// let clause = eaf.start_case_clause(); - /// eaf.discard_pattern(); - /// let clause = eaf.end_clause_pattern(); - /// let clause = eaf.end_clause_guards(); - /// eaf.int(1.into()); - /// eaf.end_clause_body(); + /// let clause = builder.start_case_clause(); + /// builder.discard_pattern(); + /// let clause = builder.end_clause_pattern(); + /// let clause = builder.end_clause_guards(); + /// builder.int(1.into()); + /// builder.end_clause_body(); /// - /// eaf.end_case(case); + /// builder.end_case(case); /// ``` /// /// Corresponds to: @@ -978,8 +980,8 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// eaf.unary_operator("-"); - /// eaf.variable("X"); + /// builder.unary_operator("-"); + /// builder.variable("X"); /// ``` /// /// Corresponds to: @@ -995,9 +997,9 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// eaf.binary_operator("+"); - /// eaf.variable("X"); - /// eaf.int(1); + /// builder.binary_operator("+"); + /// builder.variable("X"); + /// builder.int(1); /// ``` /// /// Corresponds to: @@ -1012,8 +1014,8 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// eaf.function_reference(None, "wibble", 1); - /// eaf.function_reference(Some("io"), "format", 2); + /// builder.function_reference(None, "wibble", 1); + /// builder.function_reference(Some("io"), "format", 2); /// ``` /// /// Correspond to: @@ -1033,9 +1035,9 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// eaf.match_operator(); - /// eaf.variable_pattern("X"); - /// eaf.int(1); + /// builder.match_operator(); + /// builder.variable_pattern("X"); + /// builder.int(1); /// ``` /// /// Corresponds to: @@ -1054,9 +1056,9 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// eaf.match_pattern(); - /// eaf.int_pattern(1); - /// eaf.variable_pattern("X"); + /// builder.match_pattern(); + /// builder.int_pattern(1); + /// builder.variable_pattern("X"); /// ``` /// /// Corresponds to: @@ -1144,10 +1146,10 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let tuple = eaf.start_tuple_pattern(); - /// eaf.int_pattern(1); - /// eaf.discard_pattern(); - /// eaf.end_tuple(tuple); + /// let tuple = builder.start_tuple_pattern(); + /// builder.int_pattern(1); + /// builder.discard_pattern(); + /// builder.end_tuple(tuple); /// ``` /// /// Corresponds to the following pattern: @@ -1168,19 +1170,19 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// let bit_array = eaf.start_bit_array_pattern(); + /// let bit_array = builder.start_bit_array_pattern(); /// - /// eaf.bit_array_pattern_segment(); - /// eaf.int_pattern(1); - /// eaf.atom("default"); - /// eaf.atom("default"); + /// builder.bit_array_pattern_segment(); + /// builder.int_pattern(1); + /// builder.atom("default"); + /// builder.atom("default"); /// - /// eaf.bit_array_pattern_segment(); - /// eaf.discard_pattern(); - /// eaf.atom("deafult"); - /// eaf.atom("default"); + /// builder.bit_array_pattern_segment(); + /// builder.discard_pattern(); + /// builder.atom("deafult"); + /// builder.atom("default"); /// - /// eaf.end_bit_array_pattern(bit_array); + /// builder.end_bit_array_pattern(bit_array); /// ``` /// /// Corresponds to the following pattern: @@ -1203,11 +1205,11 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// eaf.cons_list_pattern(); - /// eaf.discard_pattern(); - /// eaf.cons_list_pattern(); - /// eaf.string("Louis"); - /// eaf.empty_list_pattern(); + /// builder.cons_list_pattern(); + /// builder.discard_pattern(); + /// builder.cons_list_pattern(); + /// builder.string("Louis"); + /// builder.empty_list_pattern(); /// ``` /// /// Corresponds to the following pattern: @@ -1233,7 +1235,7 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// eaf.string("ksiÄ…skÄ™"); + /// builder.string("ksiÄ…skÄ™"); /// ``` /// /// Corresponds to: @@ -1252,7 +1254,7 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// eaf.int(BigInt::from(2)) + /// builder.int(BigInt::from(2)) /// ``` /// /// Corresponds to: @@ -1268,7 +1270,7 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// eaf.float(1.2) + /// builder.float(1.2) /// ``` /// /// Corresponds to: @@ -1284,7 +1286,7 @@ pub trait Eaf { /// For example: /// /// ```ignore - /// eaf.atom("wibble") + /// builder.atom("wibble") /// ``` /// /// Corresponds to: @@ -1296,23 +1298,22 @@ pub trait Eaf { fn atom(&mut self, name: &str); } -/// A structure that implements the EAF trait but rather than producing the -/// Erlang abstract format binary, it will produce a nice and readable Erlang -/// source string that can be used for testing. +/// A structure that implements the `ErlangBuilder` trait and produces a nice +/// and readable Erlang source string. #[derive(Debug)] -pub struct PrettyEaf { +pub struct ErlangSourceBuilder { code: String, /// This keeps track of what we're generating - position: Vec, + position: Vec, /// The current indentation to use when generating stuff like case /// expressions, block statements, etc. indentation: usize, } /// This is used to keep track of the current position when generating pretty -/// printed code from an `Eaf`. +/// printed code from an `ErlangSourceBuilder`. #[derive(Debug)] -pub enum PrettyEafPosition { +enum ErlangSourceBuilderPosition { /// We're generating a top level documentation attribute like `-doc(false)`, /// or `-moduledoc(~"wibble wobble")`. DocAttribute, @@ -1406,10 +1407,7 @@ pub enum PrettyEafPosition { /// We're generating code for a unary operator. We're waiting for the /// expression to apply the operator to. - UnaryOperator { - /// This is true if the operator is `-`. - is_number_negation: bool, - }, + UnaryOperator, /// We're generating a tuple. Tuple { @@ -1511,7 +1509,7 @@ pub enum PrettyEafPosition { } #[derive(Debug, Eq, PartialEq)] -pub enum ListKind { +enum ListKind { /// We're generating a list pattern. Pattern, /// We're generating a list expression. @@ -1519,7 +1517,7 @@ pub enum ListKind { } #[derive(Debug, Eq, PartialEq, Copy, Clone)] -pub enum BitArrayKind { +enum BitArrayKind { /// We're generating a bit array pattern. Pattern, /// We're generating a bit array expression. @@ -1531,7 +1529,7 @@ pub enum BitArrayKind { /// after two expressions are generated. So we need to keep track of what we're /// expecting to be generated next. #[derive(Debug)] -pub enum MapFieldExpectedItem { +enum MapFieldExpectedItem { Key, Value, } @@ -1541,7 +1539,7 @@ pub enum MapFieldExpectedItem { /// It is implicitly over after those two things are generated. /// So we need to keep track of which we're expecting to be generated next. #[derive(Debug)] -pub enum ExpectedRecordFieldItem { +enum ExpectedRecordFieldItem { Name, Type, } @@ -1551,7 +1549,7 @@ pub enum ExpectedRecordFieldItem { /// finally we will be generating the statements making up the clause's body. /// #[derive(Debug)] -pub enum ExpectedCaseClauseItem { +enum ExpectedCaseClauseItem { Pattern, Guards { /// This is true if no guard has been generated yet. @@ -1568,7 +1566,7 @@ pub enum ExpectedCaseClauseItem { /// expression. /// #[derive(Debug)] -pub enum ExpectedCaseItem { +enum ExpectedCaseItem { /// We're waiting for the expression to be matched on to be generated. Subject, /// We've generated the expression to be matched on, and now are waiting for @@ -1587,7 +1585,7 @@ pub enum ExpectedCaseItem { /// pretty print the output. /// #[derive(Debug)] -pub enum ExpectedBinaryOperatorSide { +enum ExpectedBinaryOperatorSide { Left, Right, BinaryOperatorIsOver, @@ -1598,7 +1596,7 @@ pub enum ExpectedBinaryOperatorSide { /// This keeps track of which one we're expecting to be generated next. /// #[derive(Debug)] -pub enum BitArraySegmentExpectedItem { +enum BitArraySegmentExpectedItem { Value { /// This is telling us if the value of the segment has to be a pattern /// or an expression. @@ -1613,7 +1611,7 @@ pub enum BitArraySegmentExpectedItem { /// current module, or any expression), and its arguments. /// #[derive(Debug)] -pub enum ExpectedCallItem { +enum ExpectedCallItem { /// We're waiting for the function to be called to be generated FunctionToBeCalled, /// The function to be called was generated, now we're waiting for its @@ -1625,7 +1623,7 @@ pub enum ExpectedCallItem { /// arguments of the function, and the return type. /// #[derive(Debug)] -pub enum ExpectedFunctionTypeItem { +enum ExpectedFunctionTypeItem { Arguments { first: bool }, ReturnType, } @@ -1635,7 +1633,7 @@ pub enum ExpectedFunctionTypeItem { /// see. /// #[derive(Debug)] -pub enum TypeSpecExpectedItem { +enum TypeSpecExpectedItem { TypeDefinition, TypeSpecIsOver, } @@ -1643,7 +1641,7 @@ pub enum TypeSpecExpectedItem { /// A match operator is made of two sides: `X = 1`. A pattern and an expression. /// #[derive(Debug)] -pub enum ExpectedMatchSide { +enum ExpectedMatchSide { /// We're waiting for the pattern on the left hand side of an assignment to /// be generated. Pattern, @@ -1656,7 +1654,7 @@ pub enum ExpectedMatchSide { /// A pattern and a variable pattern for the name. /// #[derive(Debug)] -pub enum ExpectedMatchPatternSide { +enum ExpectedMatchPatternSide { /// We're waiting for the pattern on the left hand side of the match pattern /// to be generated. Left, @@ -1671,7 +1669,7 @@ pub enum ExpectedMatchPatternSide { /// the list is actually over. /// #[derive(Debug)] -pub enum ExpectedListItem { +enum ExpectedListItem { First, Rest, ListIsOver, @@ -1715,16 +1713,16 @@ static UNICODE_ESCAPE_SEQUENCE_PATTERN: OnceLock = OnceLock::new(); /// /// ```ignore /// // X = 1 -/// eaf.match_operator() -/// eaf.variable_pattern("X") -/// eaf.int(1) +/// builder.match_operator() +/// builder.variable_pattern("X") +/// builder.int(1) /// ``` /// /// Notice how here we don't have a `start_match_operator` and /// `end_match_operator`. As you'll see in the implementation these will /// require a bit of extra book-keeping in the `new_x` functions. /// -impl Eaf for PrettyEaf { +impl ErlangBuilder for ErlangSourceBuilder { fn new(module: Option) -> Self { Self { code: if let Some(module) = module { @@ -1802,18 +1800,20 @@ impl Eaf for PrettyEaf { fn start_doc_attribute(&mut self) -> DocAttribute { self.new_top_level_form(); self.code.push_str("-doc("); - self.position.push(PrettyEafPosition::DocAttribute); + self.position + .push(ErlangSourceBuilderPosition::DocAttribute); DocAttribute { - items: PrettyEaf::dummy_list(), + items: ErlangSourceBuilder::dummy_list(), } } fn start_moduledoc_attribute(&mut self) -> DocAttribute { self.new_top_level_form(); self.code.push_str("-moduledoc("); - self.position.push(PrettyEafPosition::DocAttribute); + self.position + .push(ErlangSourceBuilderPosition::DocAttribute); DocAttribute { - items: PrettyEaf::dummy_list(), + items: ErlangSourceBuilder::dummy_list(), } } @@ -1856,10 +1856,10 @@ impl Eaf for PrettyEaf { self.code.push_str(", {"); self.indentation += INDENT; self.position - .push(PrettyEafPosition::RecordAttribute { first: true }); + .push(ErlangSourceBuilderPosition::RecordAttribute { first: true }); RecordAttribute { - fields: PrettyEaf::dummy_list(), + fields: ErlangSourceBuilder::dummy_list(), } } @@ -1870,18 +1870,20 @@ impl Eaf for PrettyEaf { fn record_field(&mut self) { self.new_record_field(); - self.position.push(PrettyEafPosition::RecordField { - expected: ExpectedRecordFieldItem::Name, - }); + self.position + .push(ErlangSourceBuilderPosition::RecordField { + expected: ExpectedRecordFieldItem::Name, + }); } fn start_function_spec(&mut self, name: &str, _arity: usize) -> FunctionSpec { self.new_top_level_form(); self.code.push_str("\n-spec "); self.code.push_str("e_atom_name(name)); - self.position.push(PrettyEafPosition::FunctionSpec); + self.position + .push(ErlangSourceBuilderPosition::FunctionSpec); FunctionSpec { - representations: PrettyEaf::dummy_list(), + representations: ErlangSourceBuilder::dummy_list(), } } @@ -1913,7 +1915,7 @@ impl Eaf for PrettyEaf { self.code.push_str(type_variable.as_ref()) } self.code.push_str(") :: "); - self.position.push(PrettyEafPosition::TypeSpec { + self.position.push(ErlangSourceBuilderPosition::TypeSpec { expected: TypeSpecExpectedItem::TypeDefinition, }); } @@ -1921,22 +1923,24 @@ impl Eaf for PrettyEaf { fn start_function_type(&mut self) -> FunctionTypeArguments { self.new_type(); - let needs_wrapping = if let Some(PrettyEafPosition::FunctionSpec) = self.position.last() { - self.code.push('('); - false - } else { - self.code.push_str("fun(("); - true - }; + let needs_wrapping = + if let Some(ErlangSourceBuilderPosition::FunctionSpec) = self.position.last() { + self.code.push('('); + false + } else { + self.code.push_str("fun(("); + true + }; - self.position.push(PrettyEafPosition::FunctionType { - expected: ExpectedFunctionTypeItem::Arguments { first: true }, - needs_wrapping, - }); + self.position + .push(ErlangSourceBuilderPosition::FunctionType { + expected: ExpectedFunctionTypeItem::Arguments { first: true }, + needs_wrapping, + }); FunctionTypeArguments { - types: PrettyEaf::dummy_list(), - arguments: PrettyEaf::dummy_list(), + types: ErlangSourceBuilder::dummy_list(), + arguments: ErlangSourceBuilder::dummy_list(), } } @@ -1959,26 +1963,26 @@ impl Eaf for PrettyEaf { fn start_named_type(&mut self, name: &str) -> NamedType { self.new_type(); self.position - .push(PrettyEafPosition::NamedType { first: true }); + .push(ErlangSourceBuilderPosition::NamedType { first: true }); self.code.push_str("e_atom_name(name)); self.code.push('('); NamedType { - types: PrettyEaf::dummy_list(), + types: ErlangSourceBuilder::dummy_list(), } } fn start_remote_named_type(&mut self, module: ErlangModuleName, name: &str) -> NamedType { self.new_type(); self.position - .push(PrettyEafPosition::NamedType { first: true }); + .push(ErlangSourceBuilderPosition::NamedType { first: true }); self.code.push_str("e_atom_name(&module.0)); self.code.push(':'); self.code.push_str("e_atom_name(name)); self.code.push('('); NamedType { - types: PrettyEaf::dummy_list(), + types: ErlangSourceBuilder::dummy_list(), } } @@ -1990,11 +1994,11 @@ impl Eaf for PrettyEaf { fn start_tuple_type(&mut self) -> TupleType { self.new_type(); self.position - .push(PrettyEafPosition::TupleType { first: true }); + .push(ErlangSourceBuilderPosition::TupleType { first: true }); self.code.push('{'); TupleType { - items: PrettyEaf::dummy_list(), + items: ErlangSourceBuilder::dummy_list(), } } @@ -2006,10 +2010,10 @@ impl Eaf for PrettyEaf { fn start_union_type(&mut self) -> UnionType { self.new_type(); self.position - .push(PrettyEafPosition::UnionType { first: true }); + .push(ErlangSourceBuilderPosition::UnionType { first: true }); UnionType { - alternatives: PrettyEaf::dummy_list(), + alternatives: ErlangSourceBuilder::dummy_list(), } } @@ -2051,11 +2055,11 @@ impl Eaf for PrettyEaf { self.code.push_str(") ->"); self.indentation += INDENT; self.position - .push(PrettyEafPosition::FunctionStatement { first: true }); + .push(ErlangSourceBuilderPosition::FunctionStatement { first: true }); Function { - clauses: PrettyEaf::dummy_list(), - statements: PrettyEaf::dummy_list(), + clauses: ErlangSourceBuilder::dummy_list(), + statements: ErlangSourceBuilder::dummy_list(), } } @@ -2079,11 +2083,11 @@ impl Eaf for PrettyEaf { self.code.push_str(") ->"); self.indentation += INDENT; self.position - .push(PrettyEafPosition::AnonymousFunctionStatement { first: true }); + .push(ErlangSourceBuilderPosition::AnonymousFunctionStatement { first: true }); Function { - clauses: PrettyEaf::dummy_list(), - statements: PrettyEaf::dummy_list(), + clauses: ErlangSourceBuilder::dummy_list(), + statements: ErlangSourceBuilder::dummy_list(), } } @@ -2097,10 +2101,11 @@ impl Eaf for PrettyEaf { self.new_expression(); self.code.push_str("begin"); self.indentation += INDENT; - self.position.push(PrettyEafPosition::Block { first: true }); + self.position + .push(ErlangSourceBuilderPosition::Block { first: true }); Block { - statements: PrettyEaf::dummy_list(), + statements: ErlangSourceBuilder::dummy_list(), } } @@ -2116,7 +2121,7 @@ impl Eaf for PrettyEaf { // it is going to need to be wrapped in parentheses to be valid in // OTP 28: it is not ok to write `wibble()()`, but we have to write // `(wibble())()`. - if let Some(PrettyEafPosition::FunctionCall { + if let Some(ErlangSourceBuilderPosition::FunctionCall { expected: ExpectedCallItem::FunctionToBeCalled, called_item_needs_wrapping, }) = self.position.last_mut() @@ -2128,12 +2133,13 @@ impl Eaf for PrettyEaf { self.code.push_str("e_atom_name(&module.0)); self.code.push(':'); self.code.push_str("e_atom_name(function)); - self.position.push(PrettyEafPosition::FunctionCall { - expected: ExpectedCallItem::Arguments { first: true }, - called_item_needs_wrapping: false, - }); + self.position + .push(ErlangSourceBuilderPosition::FunctionCall { + expected: ExpectedCallItem::Arguments { first: true }, + called_item_needs_wrapping: false, + }); Call { - arguments: PrettyEaf::dummy_list(), + arguments: ErlangSourceBuilder::dummy_list(), } } @@ -2144,7 +2150,7 @@ impl Eaf for PrettyEaf { // it is going to need to be wrapped in parentheses to be valid in // OTP 28: it is not ok to write `wibble()()`, but we have to write // `(wibble())()`. - if let Some(PrettyEafPosition::FunctionCall { + if let Some(ErlangSourceBuilderPosition::FunctionCall { expected: ExpectedCallItem::FunctionToBeCalled, called_item_needs_wrapping, }) = self.position.last_mut() @@ -2153,12 +2159,13 @@ impl Eaf for PrettyEaf { }; self.new_expression(); - self.position.push(PrettyEafPosition::FunctionCall { - expected: ExpectedCallItem::FunctionToBeCalled, - called_item_needs_wrapping: false, - }); + self.position + .push(ErlangSourceBuilderPosition::FunctionCall { + expected: ExpectedCallItem::FunctionToBeCalled, + called_item_needs_wrapping: false, + }); Call { - arguments: PrettyEaf::dummy_list(), + arguments: ErlangSourceBuilder::dummy_list(), } } @@ -2170,10 +2177,11 @@ impl Eaf for PrettyEaf { fn start_tuple(&mut self) -> Tuple { self.new_expression(); self.code.push('{'); - self.position.push(PrettyEafPosition::Tuple { first: true }); + self.position + .push(ErlangSourceBuilderPosition::Tuple { first: true }); Tuple { - items: PrettyEaf::dummy_list(), + items: ErlangSourceBuilder::dummy_list(), } } @@ -2186,9 +2194,10 @@ impl Eaf for PrettyEaf { self.new_expression(); self.code.push_str("#{"); self.indentation += INDENT; - self.position.push(PrettyEafPosition::Map { first: true }); + self.position + .push(ErlangSourceBuilderPosition::Map { first: true }); Map { - items: PrettyEaf::dummy_list(), + items: ErlangSourceBuilder::dummy_list(), } } @@ -2199,7 +2208,7 @@ impl Eaf for PrettyEaf { fn map_field(&mut self) { self.new_map_field(); - self.position.push(PrettyEafPosition::MapField { + self.position.push(ErlangSourceBuilderPosition::MapField { expected: MapFieldExpectedItem::Key, }); } @@ -2208,13 +2217,13 @@ impl Eaf for PrettyEaf { self.do_not_wrap_if_segment_value_or_size(); self.new_expression(); self.code.push_str("<<"); - self.position.push(PrettyEafPosition::BitArray { + self.position.push(ErlangSourceBuilderPosition::BitArray { kind: BitArrayKind::Expression, first: true, }); BitArray { - segments: PrettyEaf::dummy_list(), + segments: ErlangSourceBuilder::dummy_list(), } } @@ -2225,15 +2234,16 @@ impl Eaf for PrettyEaf { fn bit_array_segment(&mut self) { let kind = self.new_bit_array_segment(); - self.position.push(PrettyEafPosition::BitArraySegment { - expected: BitArraySegmentExpectedItem::Value { kind }, - // We assume all values are going to have to be wrapped, better - // be safe than sorry! - // We will turn this off only for certain expressions we know - // are safe to not wrap, like bare integers and strings. - segment_value_needs_wrapping: true, - segment_size_needs_wrapping: true, - }) + self.position + .push(ErlangSourceBuilderPosition::BitArraySegment { + expected: BitArraySegmentExpectedItem::Value { kind }, + // We assume all values are going to have to be wrapped, better + // be safe than sorry! + // We will turn this off only for certain expressions we know + // are safe to not wrap, like bare integers and strings. + segment_value_needs_wrapping: true, + segment_size_needs_wrapping: true, + }) } fn bit_array_segment_specifiers( @@ -2241,7 +2251,7 @@ impl Eaf for PrettyEaf { specifiers: impl IntoIterator, ) { self.pop_leftover_items(); - let Some(PrettyEafPosition::BitArraySegment { + let Some(ErlangSourceBuilderPosition::BitArraySegment { expected: BitArraySegmentExpectedItem::Specifiers, segment_value_needs_wrapping, segment_size_needs_wrapping, @@ -2308,12 +2318,12 @@ impl Eaf for PrettyEaf { fn start_case(&mut self) -> Case { self.new_expression(); self.code.push_str("case "); - self.position.push(PrettyEafPosition::Case { + self.position.push(ErlangSourceBuilderPosition::Case { expected: ExpectedCaseItem::Subject, }); Case { - branches: PrettyEaf::dummy_list(), + branches: ErlangSourceBuilder::dummy_list(), } } @@ -2324,19 +2334,19 @@ impl Eaf for PrettyEaf { fn start_case_clause(&mut self) -> ClausePattern { self.new_case_clause(); - self.position.push(PrettyEafPosition::CaseClause { + self.position.push(ErlangSourceBuilderPosition::CaseClause { expected: ExpectedCaseClauseItem::Pattern, }); ClausePattern { - pattern: PrettyEaf::dummy_list(), - guards: PrettyEaf::dummy_list(), - body: PrettyEaf::dummy_list(), + pattern: ErlangSourceBuilder::dummy_list(), + guards: ErlangSourceBuilder::dummy_list(), + body: ErlangSourceBuilder::dummy_list(), } } fn end_clause_pattern(&mut self, clause_pattern: ClausePattern) -> ClauseGuards { self.close_currently_open_item(); - self.position.push(PrettyEafPosition::CaseClause { + self.position.push(ErlangSourceBuilderPosition::CaseClause { expected: ExpectedCaseClauseItem::Guards { first: true }, }); clause_pattern.pattern.consume(); @@ -2349,7 +2359,7 @@ impl Eaf for PrettyEaf { fn end_clause_guards(&mut self, clause_guards: ClauseGuards) -> ClauseBody { self.close_currently_open_item(); self.indentation += INDENT; - self.position.push(PrettyEafPosition::CaseClause { + self.position.push(ErlangSourceBuilderPosition::CaseClause { expected: ExpectedCaseClauseItem::Body { first: true }, }); @@ -2374,9 +2384,8 @@ impl Eaf for PrettyEaf { self.new_expression(); self.code.push_str(operator); self.code.push(' '); - self.position.push(PrettyEafPosition::UnaryOperator { - is_number_negation: operator == "-", - }) + self.position + .push(ErlangSourceBuilderPosition::UnaryOperator) } fn binary_operator(&mut self, operator: &'static str) { @@ -2387,18 +2396,19 @@ impl Eaf for PrettyEaf { // side), then we want to wrap it in parentheses to avoid precedence // confusion! let needs_wrapping = match self.position.last() { - Some(PrettyEafPosition::BinaryOperator { .. }) => { + Some(ErlangSourceBuilderPosition::BinaryOperator { .. }) => { self.code.push('('); true } Some(_) | None => false, }; - self.position.push(PrettyEafPosition::BinaryOperator { - expected: ExpectedBinaryOperatorSide::Left, - needs_wrapping, - operator, - }) + self.position + .push(ErlangSourceBuilderPosition::BinaryOperator { + expected: ExpectedBinaryOperatorSide::Left, + needs_wrapping, + operator, + }) } fn function_reference(&mut self, module: Option, name: &str, arity: usize) { @@ -2415,16 +2425,18 @@ impl Eaf for PrettyEaf { fn match_operator(&mut self) { self.new_expression(); - self.position.push(PrettyEafPosition::MatchOperator { - expected: ExpectedMatchSide::Pattern, - }); + self.position + .push(ErlangSourceBuilderPosition::MatchOperator { + expected: ExpectedMatchSide::Pattern, + }); } fn match_pattern(&mut self) { self.new_pattern(); - self.position.push(PrettyEafPosition::MatchPattern { - expected: ExpectedMatchPatternSide::Left, - }) + self.position + .push(ErlangSourceBuilderPosition::MatchPattern { + expected: ExpectedMatchPatternSide::Left, + }) } fn variable_pattern(&mut self, name: &str) { @@ -2467,9 +2479,9 @@ impl Eaf for PrettyEaf { self.new_pattern(); self.code.push('{'); self.position - .push(PrettyEafPosition::TuplePattern { first: true }); + .push(ErlangSourceBuilderPosition::TuplePattern { first: true }); TuplePattern { - items: PrettyEaf::dummy_list(), + items: ErlangSourceBuilder::dummy_list(), } } @@ -2481,13 +2493,13 @@ impl Eaf for PrettyEaf { fn start_bit_array_pattern(&mut self) -> BitArrayPattern { self.new_pattern(); self.code.push_str("<<"); - self.position.push(PrettyEafPosition::BitArray { + self.position.push(ErlangSourceBuilderPosition::BitArray { kind: BitArrayKind::Pattern, first: true, }); BitArrayPattern { - segments: PrettyEaf::dummy_list(), + segments: ErlangSourceBuilder::dummy_list(), } } @@ -2529,7 +2541,7 @@ impl Eaf for PrettyEaf { // That's how we can tell in the Erlang Abstract Format that the size // should be the default value, but it's not actually spelled out in // textual Erlang code. - if let Some(PrettyEafPosition::BitArraySegment { + if let Some(ErlangSourceBuilderPosition::BitArraySegment { expected: expected @ BitArraySegmentExpectedItem::Size, segment_value_needs_wrapping, segment_size_needs_wrapping, @@ -2568,7 +2580,7 @@ fn format_float(number: f64) -> String { const INDENT: usize = 4; -impl PrettyEaf { +impl ErlangSourceBuilder { fn dummy_list() -> erlang_term_format::List { erlang_term_format::List::new(0) } @@ -2605,17 +2617,17 @@ impl PrettyEaf { }; match position { - PrettyEafPosition::DocAttribute => (), + ErlangSourceBuilderPosition::DocAttribute => (), - PrettyEafPosition::RecordField { + ErlangSourceBuilderPosition::RecordField { expected: expected @ ExpectedRecordFieldItem::Name, } => *expected = ExpectedRecordFieldItem::Type, - PrettyEafPosition::Case { + ErlangSourceBuilderPosition::Case { expected: expected @ ExpectedCaseItem::Subject, } => *expected = ExpectedCaseItem::Branches { first: true }, - PrettyEafPosition::FunctionCall { + ErlangSourceBuilderPosition::FunctionCall { expected: expected @ ExpectedCallItem::FunctionToBeCalled, called_item_needs_wrapping, } => { @@ -2625,7 +2637,7 @@ impl PrettyEaf { *expected = ExpectedCallItem::Arguments { first: true } } - PrettyEafPosition::FunctionCall { + ErlangSourceBuilderPosition::FunctionCall { expected: ExpectedCallItem::Arguments { first }, called_item_needs_wrapping, } => { @@ -2640,7 +2652,7 @@ impl PrettyEaf { } *first = false; } - PrettyEafPosition::Tuple { first } => { + ErlangSourceBuilderPosition::Tuple { first } => { if !*first { self.code.push_str(", "); } @@ -2649,12 +2661,12 @@ impl PrettyEaf { // We're expecting the list's head. We don't have to add // anything! - PrettyEafPosition::List { + ErlangSourceBuilderPosition::List { expected: expected @ ExpectedListItem::First, kind: ListKind::Expression, } => *expected = ExpectedListItem::Rest, - PrettyEafPosition::List { + ErlangSourceBuilderPosition::List { expected: expected @ ExpectedListItem::Rest, kind: ListKind::Expression, } => { @@ -2662,12 +2674,12 @@ impl PrettyEaf { self.code.push_str(" | ") } - PrettyEafPosition::BinaryOperator { + ErlangSourceBuilderPosition::BinaryOperator { expected: expected @ ExpectedBinaryOperatorSide::Left, .. } => *expected = ExpectedBinaryOperatorSide::Right, - PrettyEafPosition::BinaryOperator { + ErlangSourceBuilderPosition::BinaryOperator { expected: expected @ ExpectedBinaryOperatorSide::Right, operator, .. @@ -2678,10 +2690,10 @@ impl PrettyEaf { self.code.push(' '); } - PrettyEafPosition::FunctionStatement { first } - | PrettyEafPosition::AnonymousFunctionStatement { first } - | PrettyEafPosition::Block { first } - | PrettyEafPosition::CaseClause { + ErlangSourceBuilderPosition::FunctionStatement { first } + | ErlangSourceBuilderPosition::AnonymousFunctionStatement { first } + | ErlangSourceBuilderPosition::Block { first } + | ErlangSourceBuilderPosition::CaseClause { expected: ExpectedCaseClauseItem::Body { first }, } => { if !*first { @@ -2692,7 +2704,7 @@ impl PrettyEaf { self.push_indentation(); } - PrettyEafPosition::BitArraySegment { + ErlangSourceBuilderPosition::BitArraySegment { expected: expected @ BitArraySegmentExpectedItem::Value { kind: BitArrayKind::Expression, @@ -2706,7 +2718,7 @@ impl PrettyEaf { *expected = BitArraySegmentExpectedItem::Size } - PrettyEafPosition::BitArraySegment { + ErlangSourceBuilderPosition::BitArraySegment { expected: expected @ BitArraySegmentExpectedItem::Size, segment_value_needs_wrapping, segment_size_needs_wrapping, @@ -2725,7 +2737,7 @@ impl PrettyEaf { } } - PrettyEafPosition::CaseClause { + ErlangSourceBuilderPosition::CaseClause { expected: ExpectedCaseClauseItem::Guards { first: first @ true, @@ -2735,7 +2747,7 @@ impl PrettyEaf { self.code.push_str(" when "); } - PrettyEafPosition::MapField { expected } => match expected { + ErlangSourceBuilderPosition::MapField { expected } => match expected { MapFieldExpectedItem::Key => *expected = MapFieldExpectedItem::Value, // We've generated a key and now the value is being generated. // So we need to add the `=>` separating key and value and we @@ -2749,7 +2761,7 @@ impl PrettyEaf { // We were expecting an expression and someone is about to generate // it, we can pop this off the stack and need to add the ` = ` // separating the previous pattern from this new expression. - PrettyEafPosition::MatchOperator { + ErlangSourceBuilderPosition::MatchOperator { expected: ExpectedMatchSide::Expression, } => { self.code.push_str(" = "); @@ -2757,57 +2769,57 @@ impl PrettyEaf { } // We were expecting an expression and someone generated it, we can // now pop this off the stack. - PrettyEafPosition::UnaryOperator { .. } => { + ErlangSourceBuilderPosition::UnaryOperator { .. } => { self.position.pop(); } // Expressions are not allowed in any of these positions. - PrettyEafPosition::Case { + ErlangSourceBuilderPosition::Case { expected: ExpectedCaseItem::Branches { .. }, } - | PrettyEafPosition::List { + | ErlangSourceBuilderPosition::List { expected: ExpectedListItem::ListIsOver, kind: ListKind::Expression, } - | PrettyEafPosition::BitArray { .. } - | PrettyEafPosition::MatchOperator { + | ErlangSourceBuilderPosition::BitArray { .. } + | ErlangSourceBuilderPosition::MatchOperator { expected: ExpectedMatchSide::Pattern, } - | PrettyEafPosition::CaseClause { + | ErlangSourceBuilderPosition::CaseClause { expected: ExpectedCaseClauseItem::Pattern, } - | PrettyEafPosition::TuplePattern { .. } - | PrettyEafPosition::MatchPattern { .. } - | PrettyEafPosition::FunctionSpec - | PrettyEafPosition::TypeSpec { .. } - | PrettyEafPosition::NamedType { .. } - | PrettyEafPosition::FunctionType { .. } - | PrettyEafPosition::UnionType { .. } - | PrettyEafPosition::RecordField { + | ErlangSourceBuilderPosition::TuplePattern { .. } + | ErlangSourceBuilderPosition::MatchPattern { .. } + | ErlangSourceBuilderPosition::FunctionSpec + | ErlangSourceBuilderPosition::TypeSpec { .. } + | ErlangSourceBuilderPosition::NamedType { .. } + | ErlangSourceBuilderPosition::FunctionType { .. } + | ErlangSourceBuilderPosition::UnionType { .. } + | ErlangSourceBuilderPosition::RecordField { expected: ExpectedRecordFieldItem::Type, } - | PrettyEafPosition::TupleType { .. } - | PrettyEafPosition::Map { .. } - | PrettyEafPosition::RecordAttribute { .. } - | PrettyEafPosition::CaseClause { + | ErlangSourceBuilderPosition::TupleType { .. } + | ErlangSourceBuilderPosition::Map { .. } + | ErlangSourceBuilderPosition::RecordAttribute { .. } + | ErlangSourceBuilderPosition::CaseClause { expected: ExpectedCaseClauseItem::Guards { first: false }, } - | PrettyEafPosition::BitArraySegment { + | ErlangSourceBuilderPosition::BitArraySegment { expected: BitArraySegmentExpectedItem::Specifiers, .. } - | PrettyEafPosition::BitArraySegment { + | ErlangSourceBuilderPosition::BitArraySegment { expected: BitArraySegmentExpectedItem::Value { kind: BitArrayKind::Pattern, }, .. } - | PrettyEafPosition::BinaryOperator { + | ErlangSourceBuilderPosition::BinaryOperator { expected: ExpectedBinaryOperatorSide::BinaryOperatorIsOver, .. } - | PrettyEafPosition::List { + | ErlangSourceBuilderPosition::List { kind: ListKind::Pattern, .. } => invalid_code_for_position!(self, "expression"), @@ -2829,74 +2841,74 @@ impl PrettyEaf { }; match position { - PrettyEafPosition::FunctionSpec => {} - PrettyEafPosition::FunctionType { + ErlangSourceBuilderPosition::FunctionSpec => {} + ErlangSourceBuilderPosition::FunctionType { expected: ExpectedFunctionTypeItem::ReturnType, needs_wrapping: _, } => {} - PrettyEafPosition::TypeSpec { + ErlangSourceBuilderPosition::TypeSpec { expected: expected @ TypeSpecExpectedItem::TypeDefinition, } => { *expected = TypeSpecExpectedItem::TypeSpecIsOver; } - PrettyEafPosition::FunctionType { + ErlangSourceBuilderPosition::FunctionType { expected: ExpectedFunctionTypeItem::Arguments { first }, needs_wrapping: _, } - | PrettyEafPosition::TupleType { first } - | PrettyEafPosition::NamedType { first } => { + | ErlangSourceBuilderPosition::TupleType { first } + | ErlangSourceBuilderPosition::NamedType { first } => { if !*first { self.code.push_str(", ") } *first = false } - PrettyEafPosition::UnionType { first } => { + ErlangSourceBuilderPosition::UnionType { first } => { if !*first { self.code.push_str(" | ") } *first = false } - PrettyEafPosition::RecordField { + ErlangSourceBuilderPosition::RecordField { expected: ExpectedRecordFieldItem::Type, } => { self.code.push_str(" :: "); self.position.pop(); } - PrettyEafPosition::FunctionCall { .. } - | PrettyEafPosition::Block { .. } - | PrettyEafPosition::Tuple { .. } - | PrettyEafPosition::BitArray { .. } - | PrettyEafPosition::BitArraySegment { .. } - | PrettyEafPosition::List { .. } - | PrettyEafPosition::FunctionStatement { .. } - | PrettyEafPosition::AnonymousFunctionStatement { .. } - | PrettyEafPosition::DocAttribute - | PrettyEafPosition::UnaryOperator { .. } - | PrettyEafPosition::Case { .. } - | PrettyEafPosition::BinaryOperator { .. } - | PrettyEafPosition::CaseClause { .. } - | PrettyEafPosition::Map { .. } - | PrettyEafPosition::MapField { .. } - | PrettyEafPosition::RecordField { + ErlangSourceBuilderPosition::FunctionCall { .. } + | ErlangSourceBuilderPosition::Block { .. } + | ErlangSourceBuilderPosition::Tuple { .. } + | ErlangSourceBuilderPosition::BitArray { .. } + | ErlangSourceBuilderPosition::BitArraySegment { .. } + | ErlangSourceBuilderPosition::List { .. } + | ErlangSourceBuilderPosition::FunctionStatement { .. } + | ErlangSourceBuilderPosition::AnonymousFunctionStatement { .. } + | ErlangSourceBuilderPosition::DocAttribute + | ErlangSourceBuilderPosition::UnaryOperator { .. } + | ErlangSourceBuilderPosition::Case { .. } + | ErlangSourceBuilderPosition::BinaryOperator { .. } + | ErlangSourceBuilderPosition::CaseClause { .. } + | ErlangSourceBuilderPosition::Map { .. } + | ErlangSourceBuilderPosition::MapField { .. } + | ErlangSourceBuilderPosition::RecordField { expected: ExpectedRecordFieldItem::Name, } - | PrettyEafPosition::MatchOperator { + | ErlangSourceBuilderPosition::MatchOperator { expected: ExpectedMatchSide::Expression, } - | PrettyEafPosition::RecordAttribute { .. } - | PrettyEafPosition::TypeSpec { + | ErlangSourceBuilderPosition::RecordAttribute { .. } + | ErlangSourceBuilderPosition::TypeSpec { expected: TypeSpecExpectedItem::TypeSpecIsOver, } - | PrettyEafPosition::MatchOperator { + | ErlangSourceBuilderPosition::MatchOperator { expected: ExpectedMatchSide::Pattern, } - | PrettyEafPosition::MatchPattern { .. } - | PrettyEafPosition::TuplePattern { .. } => { + | ErlangSourceBuilderPosition::MatchPattern { .. } + | ErlangSourceBuilderPosition::TuplePattern { .. } => { invalid_code_for_position!(self, "type") } } @@ -2919,12 +2931,12 @@ impl PrettyEaf { match position { // We're expecting the list's head. We don't have to add // anything! - PrettyEafPosition::List { + ErlangSourceBuilderPosition::List { kind: ListKind::Pattern, expected: expected @ ExpectedListItem::First, } => *expected = ExpectedListItem::Rest, - PrettyEafPosition::List { + ErlangSourceBuilderPosition::List { kind: ListKind::Pattern, expected: expected @ ExpectedListItem::Rest, } => { @@ -2932,7 +2944,7 @@ impl PrettyEaf { self.code.push_str(" | ") } - PrettyEafPosition::BitArraySegment { + ErlangSourceBuilderPosition::BitArraySegment { segment_value_needs_wrapping, segment_size_needs_wrapping: _, expected: @@ -2948,7 +2960,7 @@ impl PrettyEaf { // We were waiting for the pattern to be generated, now we're done // and can start generating an expression for the right-hand side. - PrettyEafPosition::MatchOperator { + ErlangSourceBuilderPosition::MatchOperator { expected: expected @ ExpectedMatchSide::Pattern, } => { *expected = ExpectedMatchSide::Expression; @@ -2958,17 +2970,17 @@ impl PrettyEaf { // We don't change this ourselves since the pattern has to be closed // explicitly calling `end_clause_pattern`. // We don't have to do anything here! - PrettyEafPosition::CaseClause { + ErlangSourceBuilderPosition::CaseClause { expected: ExpectedCaseClauseItem::Pattern, } => (), - PrettyEafPosition::TuplePattern { first } => { + ErlangSourceBuilderPosition::TuplePattern { first } => { if *first { *first = false; } else { self.code.push_str(", ") } } - PrettyEafPosition::MatchPattern { expected } => match expected { + ErlangSourceBuilderPosition::MatchPattern { expected } => match expected { ExpectedMatchPatternSide::Left => *expected = ExpectedMatchPatternSide::Right, // The right hand side is about to be generated so we have to // push the ` = ` to separate it from the left hand side, and we @@ -2980,16 +2992,16 @@ impl PrettyEaf { } }, - PrettyEafPosition::FunctionCall { .. } - | PrettyEafPosition::Block { .. } - | PrettyEafPosition::FunctionStatement { .. } - | PrettyEafPosition::AnonymousFunctionStatement { .. } - | PrettyEafPosition::List { + ErlangSourceBuilderPosition::FunctionCall { .. } + | ErlangSourceBuilderPosition::Block { .. } + | ErlangSourceBuilderPosition::FunctionStatement { .. } + | ErlangSourceBuilderPosition::AnonymousFunctionStatement { .. } + | ErlangSourceBuilderPosition::List { kind: ListKind::Expression, .. } - | PrettyEafPosition::BitArray { .. } - | PrettyEafPosition::BitArraySegment { + | ErlangSourceBuilderPosition::BitArray { .. } + | ErlangSourceBuilderPosition::BitArraySegment { expected: BitArraySegmentExpectedItem::Size | BitArraySegmentExpectedItem::Specifiers @@ -2998,32 +3010,32 @@ impl PrettyEaf { }, .. } - | PrettyEafPosition::UnaryOperator { .. } - | PrettyEafPosition::BinaryOperator { .. } - | PrettyEafPosition::Case { .. } - | PrettyEafPosition::Map { .. } - | PrettyEafPosition::MapField { .. } - | PrettyEafPosition::MatchOperator { + | ErlangSourceBuilderPosition::UnaryOperator { .. } + | ErlangSourceBuilderPosition::BinaryOperator { .. } + | ErlangSourceBuilderPosition::Case { .. } + | ErlangSourceBuilderPosition::Map { .. } + | ErlangSourceBuilderPosition::MapField { .. } + | ErlangSourceBuilderPosition::MatchOperator { expected: ExpectedMatchSide::Expression, } - | PrettyEafPosition::Tuple { .. } - | PrettyEafPosition::FunctionType { .. } - | PrettyEafPosition::FunctionSpec - | PrettyEafPosition::TypeSpec { .. } - | PrettyEafPosition::NamedType { .. } - | PrettyEafPosition::UnionType { .. } - | PrettyEafPosition::TupleType { .. } - | PrettyEafPosition::RecordField { .. } - | PrettyEafPosition::DocAttribute - | PrettyEafPosition::RecordAttribute { .. } - | PrettyEafPosition::List { + | ErlangSourceBuilderPosition::Tuple { .. } + | ErlangSourceBuilderPosition::FunctionType { .. } + | ErlangSourceBuilderPosition::FunctionSpec + | ErlangSourceBuilderPosition::TypeSpec { .. } + | ErlangSourceBuilderPosition::NamedType { .. } + | ErlangSourceBuilderPosition::UnionType { .. } + | ErlangSourceBuilderPosition::TupleType { .. } + | ErlangSourceBuilderPosition::RecordField { .. } + | ErlangSourceBuilderPosition::DocAttribute + | ErlangSourceBuilderPosition::RecordAttribute { .. } + | ErlangSourceBuilderPosition::List { kind: ListKind::Pattern, expected: ExpectedListItem::ListIsOver, } - | PrettyEafPosition::CaseClause { + | ErlangSourceBuilderPosition::CaseClause { expected: ExpectedCaseClauseItem::Guards { .. }, } - | PrettyEafPosition::CaseClause { + | ErlangSourceBuilderPosition::CaseClause { expected: ExpectedCaseClauseItem::Body { .. }, } => { invalid_code_for_position!(self, "pattern"); @@ -3041,14 +3053,14 @@ impl PrettyEaf { // When we're done generating statements for a function we need to // add one final `.` to the last statement. Then we also want to // add an empty line to make our code breath a bit better. - PrettyEafPosition::FunctionStatement { .. } => { + ErlangSourceBuilderPosition::FunctionStatement { .. } => { self.indentation -= INDENT; self.code.push_str(".\n") } // When we're done generating statements for an anonymous function // we need to add the closing `end` after the last statement on a // new line. - PrettyEafPosition::AnonymousFunctionStatement { .. } => { + ErlangSourceBuilderPosition::AnonymousFunctionStatement { .. } => { self.indentation -= INDENT; self.code.push('\n'); self.push_indentation(); @@ -3056,7 +3068,7 @@ impl PrettyEaf { } // When we're done generating statements for a block we need to add // the closing `end`, and reduce the nesting level. - PrettyEafPosition::Block { .. } => { + ErlangSourceBuilderPosition::Block { .. } => { self.indentation -= INDENT; self.code.push('\n'); self.push_indentation(); @@ -3065,10 +3077,10 @@ impl PrettyEaf { // When we're done generating code for a function spec we want to // add a `.` and go to a new line so we can start generating the // function itself. - PrettyEafPosition::FunctionSpec => self.code.push_str(".\n"), + ErlangSourceBuilderPosition::FunctionSpec => self.code.push_str(".\n"), // When we're done generating the arguments of a function we need // to add the closed parentheses for the function call! - PrettyEafPosition::FunctionCall { + ErlangSourceBuilderPosition::FunctionCall { expected: ExpectedCallItem::Arguments { first }, called_item_needs_wrapping, } => { @@ -3089,29 +3101,30 @@ impl PrettyEaf { // When we're done generating the items of a tuple we need // to add the closed curly brace to actually close the tuple. - PrettyEafPosition::TupleType { .. } - | PrettyEafPosition::Tuple { .. } - | PrettyEafPosition::TuplePattern { .. } => self.code.push('}'), + ErlangSourceBuilderPosition::TupleType { .. } + | ErlangSourceBuilderPosition::Tuple { .. } + | ErlangSourceBuilderPosition::TuplePattern { .. } => self.code.push('}'), // When we're done generating a bit array we can add its closing // element. - PrettyEafPosition::BitArray { .. } => self.code.push_str(">>"), + ErlangSourceBuilderPosition::BitArray { .. } => self.code.push_str(">>"), // When the function type arguments are over we add what we need for // the return type. - PrettyEafPosition::FunctionType { + ErlangSourceBuilderPosition::FunctionType { expected: ExpectedFunctionTypeItem::Arguments { .. }, needs_wrapping, } => { // After popping the argument, we now need to wait for the // return type! - self.position.push(PrettyEafPosition::FunctionType { - expected: ExpectedFunctionTypeItem::ReturnType, - needs_wrapping, - }); + self.position + .push(ErlangSourceBuilderPosition::FunctionType { + expected: ExpectedFunctionTypeItem::ReturnType, + needs_wrapping, + }); self.code.push_str(") -> ") } // When a named type is over we need to add the closing parentheses. - PrettyEafPosition::NamedType { .. } => self.code.push(')'), + ErlangSourceBuilderPosition::NamedType { .. } => self.code.push(')'), // If we close a function type we need to check what the current // state is. If we were generating this for a type spec we're done. // But if we were generating this as a type inside another we need to @@ -3128,7 +3141,7 @@ impl PrettyEaf { // % ^ We're adding this bit here! // wobble() -> fun wibble/0. // ``` - PrettyEafPosition::FunctionType { + ErlangSourceBuilderPosition::FunctionType { expected: ExpectedFunctionTypeItem::ReturnType, needs_wrapping, } => { @@ -3137,12 +3150,12 @@ impl PrettyEaf { } } // There's nothing left to do when a union type ends. - PrettyEafPosition::UnionType { .. } => (), + ErlangSourceBuilderPosition::UnionType { .. } => (), // When a doc attribute is closed we need to add the closed // parentheses and a newline. - PrettyEafPosition::DocAttribute => self.code.push_str(").\n"), + ErlangSourceBuilderPosition::DocAttribute => self.code.push_str(").\n"), // When a case expression is over, we need to add the closing `end`. - PrettyEafPosition::Case { + ErlangSourceBuilderPosition::Case { expected: ExpectedCaseItem::Branches { .. }, } => { self.indentation -= INDENT; @@ -3151,7 +3164,7 @@ impl PrettyEaf { self.code.push_str("end"); } - PrettyEafPosition::CaseClause { expected } => match expected { + ErlangSourceBuilderPosition::CaseClause { expected } => match expected { ExpectedCaseClauseItem::Pattern => (), // When the guards of a case clause are over we need to add the // arrow before the body is generated. @@ -3162,32 +3175,32 @@ impl PrettyEaf { }, // We're done with a map, we can add the closed parentheses and // reduce nesting. - PrettyEafPosition::Map { .. } => { + ErlangSourceBuilderPosition::Map { .. } => { self.indentation -= INDENT; self.code.push('\n'); self.push_indentation(); self.code.push('}'); } - PrettyEafPosition::RecordAttribute { .. } => { + ErlangSourceBuilderPosition::RecordAttribute { .. } => { self.indentation -= INDENT; self.code.push('\n'); self.push_indentation(); self.code.push_str("})."); } - PrettyEafPosition::MapField { .. } - | PrettyEafPosition::RecordField { .. } - | PrettyEafPosition::MatchPattern { .. } - | PrettyEafPosition::UnaryOperator { .. } - | PrettyEafPosition::List { .. } - | PrettyEafPosition::BinaryOperator { .. } - | PrettyEafPosition::MatchOperator { .. } - | PrettyEafPosition::TypeSpec { .. } - | PrettyEafPosition::BitArraySegment { .. } - | PrettyEafPosition::Case { + ErlangSourceBuilderPosition::MapField { .. } + | ErlangSourceBuilderPosition::RecordField { .. } + | ErlangSourceBuilderPosition::MatchPattern { .. } + | ErlangSourceBuilderPosition::UnaryOperator { .. } + | ErlangSourceBuilderPosition::List { .. } + | ErlangSourceBuilderPosition::BinaryOperator { .. } + | ErlangSourceBuilderPosition::MatchOperator { .. } + | ErlangSourceBuilderPosition::TypeSpec { .. } + | ErlangSourceBuilderPosition::BitArraySegment { .. } + | ErlangSourceBuilderPosition::Case { expected: ExpectedCaseItem::Subject, } - | PrettyEafPosition::FunctionCall { + | ErlangSourceBuilderPosition::FunctionCall { // If we try and close a function for which no called item was // generated, then that's an error! expected: ExpectedCallItem::FunctionToBeCalled, @@ -3231,34 +3244,34 @@ impl PrettyEaf { .expect("escaping string in the top level scope"); match position { - PrettyEafPosition::FunctionSpec - | PrettyEafPosition::TypeSpec { .. } - | PrettyEafPosition::FunctionType { .. } - | PrettyEafPosition::NamedType { .. } - | PrettyEafPosition::UnionType { .. } - | PrettyEafPosition::RecordAttribute { .. } - | PrettyEafPosition::TupleType { .. } => { + ErlangSourceBuilderPosition::FunctionSpec + | ErlangSourceBuilderPosition::TypeSpec { .. } + | ErlangSourceBuilderPosition::FunctionType { .. } + | ErlangSourceBuilderPosition::NamedType { .. } + | ErlangSourceBuilderPosition::UnionType { .. } + | ErlangSourceBuilderPosition::RecordAttribute { .. } + | ErlangSourceBuilderPosition::TupleType { .. } => { invalid_code_for_position!(self, "escaping string") } - PrettyEafPosition::FunctionCall { .. } - | PrettyEafPosition::FunctionStatement { .. } - | PrettyEafPosition::AnonymousFunctionStatement { .. } - | PrettyEafPosition::List { .. } - | PrettyEafPosition::UnaryOperator { .. } - | PrettyEafPosition::Tuple { .. } - | PrettyEafPosition::TuplePattern { .. } - | PrettyEafPosition::BitArray { .. } - | PrettyEafPosition::BitArraySegment { .. } - | PrettyEafPosition::Block { .. } - | PrettyEafPosition::BinaryOperator { .. } - | PrettyEafPosition::Case { .. } - | PrettyEafPosition::CaseClause { .. } - | PrettyEafPosition::Map { .. } - | PrettyEafPosition::MapField { .. } - | PrettyEafPosition::MatchPattern { .. } - | PrettyEafPosition::RecordField { .. } - | PrettyEafPosition::MatchOperator { .. } => { + ErlangSourceBuilderPosition::FunctionCall { .. } + | ErlangSourceBuilderPosition::FunctionStatement { .. } + | ErlangSourceBuilderPosition::AnonymousFunctionStatement { .. } + | ErlangSourceBuilderPosition::List { .. } + | ErlangSourceBuilderPosition::UnaryOperator { .. } + | ErlangSourceBuilderPosition::Tuple { .. } + | ErlangSourceBuilderPosition::TuplePattern { .. } + | ErlangSourceBuilderPosition::BitArray { .. } + | ErlangSourceBuilderPosition::BitArraySegment { .. } + | ErlangSourceBuilderPosition::Block { .. } + | ErlangSourceBuilderPosition::BinaryOperator { .. } + | ErlangSourceBuilderPosition::Case { .. } + | ErlangSourceBuilderPosition::CaseClause { .. } + | ErlangSourceBuilderPosition::Map { .. } + | ErlangSourceBuilderPosition::MapField { .. } + | ErlangSourceBuilderPosition::MatchPattern { .. } + | ErlangSourceBuilderPosition::RecordField { .. } + | ErlangSourceBuilderPosition::MatchOperator { .. } => { // When pretty printing we want the resulting code to be regular // executable Erlang code. // If we're tasked with escaping the content of a literal string @@ -3283,7 +3296,7 @@ impl PrettyEaf { .into() } - PrettyEafPosition::DocAttribute => { + ErlangSourceBuilderPosition::DocAttribute => { // Escaping strings generated inside doc attributes is a little // different: since their content doesn't come from a Gleam // literal string but freeform text, their content might contain @@ -3296,7 +3309,8 @@ impl PrettyEaf { #[must_use] fn new_bit_array_segment(&mut self) -> BitArrayKind { self.pop_leftover_items(); - let Some(PrettyEafPosition::BitArray { first, kind }) = self.position.last_mut() else { + let Some(ErlangSourceBuilderPosition::BitArray { first, kind }) = self.position.last_mut() + else { invalid_code_for_position!(self, "bit array segment") }; @@ -3311,7 +3325,7 @@ impl PrettyEaf { fn new_case_clause(&mut self) { self.pop_leftover_items(); - let Some(PrettyEafPosition::Case { + let Some(ErlangSourceBuilderPosition::Case { expected: ExpectedCaseItem::Branches { first }, }) = self.position.last_mut() else { @@ -3330,7 +3344,7 @@ impl PrettyEaf { fn new_map_field(&mut self) { self.pop_leftover_items(); - let Some(PrettyEafPosition::Map { first }) = self.position.last_mut() else { + let Some(ErlangSourceBuilderPosition::Map { first }) = self.position.last_mut() else { invalid_code_for_position!(self, "map field"); }; @@ -3363,12 +3377,12 @@ impl PrettyEaf { // If we're about to generate a bit array segment value, or a size, // then we can skip the wrapping, otherwise this is not needed at all! match self.position.last_mut() { - Some(PrettyEafPosition::BitArraySegment { + Some(ErlangSourceBuilderPosition::BitArraySegment { segment_value_needs_wrapping, expected: BitArraySegmentExpectedItem::Value { .. }, .. }) => *segment_value_needs_wrapping = false, - Some(PrettyEafPosition::BitArraySegment { + Some(ErlangSourceBuilderPosition::BitArraySegment { segment_size_needs_wrapping, expected: BitArraySegmentExpectedItem::Size, .. @@ -3385,7 +3399,7 @@ impl PrettyEaf { // output slightly different code: rather than a bit array we want to // output a regular string with no modifiers which are going to be added // later as the segment is created - if let Some(PrettyEafPosition::BitArraySegment { + if let Some(ErlangSourceBuilderPosition::BitArraySegment { // the call to `new_expression` at the beginning is going to advance // the state to expect the `::Size`, that means the code we are // outputting now was expected to be the the `::Value` of the bit @@ -3414,7 +3428,7 @@ impl PrettyEaf { // If we were expecting the rest of a list and we generate a new // cons cell we can keep adding commas to separate items: we want // to show `[1, 2, 3]` rather than `[1 | [2 | [3 | []]]]` - Some(PrettyEafPosition::List { + Some(ErlangSourceBuilderPosition::List { kind, expected: expected @ ExpectedListItem::Rest, }) if *kind == list_kind => { @@ -3429,7 +3443,7 @@ impl PrettyEaf { ListKind::Expression => self.new_expression(), } self.code.push('['); - self.position.push(PrettyEafPosition::List { + self.position.push(ErlangSourceBuilderPosition::List { kind: list_kind, expected: ExpectedListItem::First, }); @@ -3443,7 +3457,7 @@ impl PrettyEaf { // If we were building a cons list and were expecting the end of the // list then we have to special case this: we don't want to render // it as: `[1, 2 | []]`, but as `[1, 2]`. - Some(PrettyEafPosition::List { + Some(ErlangSourceBuilderPosition::List { kind, expected: ExpectedListItem::Rest, }) if *kind == list_kind => { @@ -3475,7 +3489,7 @@ impl PrettyEaf { }; match position { - PrettyEafPosition::TypeSpec { + ErlangSourceBuilderPosition::TypeSpec { expected: TypeSpecExpectedItem::TypeSpecIsOver, } => { self.code.push_str(".\n"); @@ -3488,7 +3502,7 @@ impl PrettyEaf { // are built as a list of cons cells, so we can't really // tell when a list is over until we get to the next // expression. - PrettyEafPosition::List { + ErlangSourceBuilderPosition::List { expected: ExpectedListItem::ListIsOver, .. } => { @@ -3505,7 +3519,7 @@ impl PrettyEaf { // the current item and notice there's a closed operator left). // Also, just like lists, we might still need to add some // parentheses _after_ the operator is over. - PrettyEafPosition::BinaryOperator { + ErlangSourceBuilderPosition::BinaryOperator { expected: ExpectedBinaryOperatorSide::BinaryOperatorIsOver, needs_wrapping, .. @@ -3523,72 +3537,73 @@ impl PrettyEaf { // All of these items are not leftovers. They are either still open, // require manual closing, or things that don't need closing at all! - PrettyEafPosition::NamedType { .. } - | PrettyEafPosition::UnionType { .. } - | PrettyEafPosition::TupleType { .. } - | PrettyEafPosition::FunctionStatement { .. } - | PrettyEafPosition::AnonymousFunctionStatement { .. } - | PrettyEafPosition::DocAttribute - | PrettyEafPosition::FunctionSpec - | PrettyEafPosition::Tuple { .. } - | PrettyEafPosition::TuplePattern { .. } - | PrettyEafPosition::BitArray { .. } - | PrettyEafPosition::Map { .. } - | PrettyEafPosition::Block { .. } - | PrettyEafPosition::UnaryOperator { .. } - | PrettyEafPosition::FunctionType { + ErlangSourceBuilderPosition::NamedType { .. } + | ErlangSourceBuilderPosition::UnionType { .. } + | ErlangSourceBuilderPosition::TupleType { .. } + | ErlangSourceBuilderPosition::FunctionStatement { .. } + | ErlangSourceBuilderPosition::AnonymousFunctionStatement { .. } + | ErlangSourceBuilderPosition::DocAttribute + | ErlangSourceBuilderPosition::FunctionSpec + | ErlangSourceBuilderPosition::Tuple { .. } + | ErlangSourceBuilderPosition::TuplePattern { .. } + | ErlangSourceBuilderPosition::BitArray { .. } + | ErlangSourceBuilderPosition::Map { .. } + | ErlangSourceBuilderPosition::Block { .. } + | ErlangSourceBuilderPosition::UnaryOperator { .. } + | ErlangSourceBuilderPosition::FunctionType { expected: ExpectedFunctionTypeItem::Arguments { .. } | ExpectedFunctionTypeItem::ReturnType, .. } - | PrettyEafPosition::TypeSpec { + | ErlangSourceBuilderPosition::TypeSpec { expected: TypeSpecExpectedItem::TypeDefinition, } - | PrettyEafPosition::MapField { + | ErlangSourceBuilderPosition::MapField { expected: MapFieldExpectedItem::Key | MapFieldExpectedItem::Value, } - | PrettyEafPosition::List { + | ErlangSourceBuilderPosition::List { expected: ExpectedListItem::First | ExpectedListItem::Rest, .. } - | PrettyEafPosition::BitArraySegment { + | ErlangSourceBuilderPosition::BitArraySegment { expected: BitArraySegmentExpectedItem::Size | BitArraySegmentExpectedItem::Specifiers | BitArraySegmentExpectedItem::Value { .. }, .. } - | PrettyEafPosition::FunctionCall { + | ErlangSourceBuilderPosition::FunctionCall { expected: ExpectedCallItem::Arguments { .. } | ExpectedCallItem::FunctionToBeCalled, .. } - | PrettyEafPosition::MatchPattern { + | ErlangSourceBuilderPosition::MatchPattern { expected: ExpectedMatchPatternSide::Left | ExpectedMatchPatternSide::Right, } - | PrettyEafPosition::Case { + | ErlangSourceBuilderPosition::Case { expected: ExpectedCaseItem::Subject | ExpectedCaseItem::Branches { .. }, } - | PrettyEafPosition::CaseClause { + | ErlangSourceBuilderPosition::CaseClause { expected: ExpectedCaseClauseItem::Pattern | ExpectedCaseClauseItem::Guards { .. } | ExpectedCaseClauseItem::Body { .. }, } - | PrettyEafPosition::BinaryOperator { + | ErlangSourceBuilderPosition::BinaryOperator { expected: ExpectedBinaryOperatorSide::Left | ExpectedBinaryOperatorSide::Right, .. } - | PrettyEafPosition::RecordAttribute { .. } - | PrettyEafPosition::MatchOperator { + | ErlangSourceBuilderPosition::RecordAttribute { .. } + | ErlangSourceBuilderPosition::MatchOperator { expected: ExpectedMatchSide::Expression | ExpectedMatchSide::Pattern, } - | PrettyEafPosition::RecordField { .. } => (), + | ErlangSourceBuilderPosition::RecordField { .. } => (), } } fn new_record_field(&mut self) { self.pop_leftover_items(); - let Some(PrettyEafPosition::RecordAttribute { first }) = self.position.last_mut() else { + let Some(ErlangSourceBuilderPosition::RecordAttribute { first }) = self.position.last_mut() + else { panic!("tried generating record field outside of record attribute"); };