Skip to content

Commit f42c180

Browse files
giacomocavalierilpil
authored andcommitted
use a printer struct for pattern printing on erlang
1 parent c78860c commit f42c180

File tree

2 files changed

+332
-349
lines changed

2 files changed

+332
-349
lines changed

compiler-core/src/erlang.rs

Lines changed: 56 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ mod pattern;
77
mod tests;
88

99
use crate::build::{Target, module_erlang_name};
10+
use crate::erlang::pattern::PatternPrinter;
1011
use crate::strings::{convert_string_escape_chars, to_snake_case};
1112
use crate::type_::is_prelude_module;
1213
use crate::{
@@ -959,18 +960,18 @@ fn expr_segment<'a>(
959960
)
960961
}
961962

962-
fn bit_array_segment<'a, Value: 'a, CreateDoc, SizeToDoc, UnitToDoc>(
963+
fn bit_array_segment<'a, Value: 'a, CreateDoc, SizeToDoc, UnitToDoc, State>(
963964
mut create_document: CreateDoc,
964965
options: &'a [BitArrayOption<Value>],
965966
mut size_to_doc: SizeToDoc,
966967
mut unit_to_doc: UnitToDoc,
967968
value_is_a_string_literal: bool,
968969
value_is_a_discard: bool,
969-
env: &mut Env<'a>,
970+
state: &mut State,
970971
) -> Document<'a>
971972
where
972-
CreateDoc: FnMut(&mut Env<'a>) -> Document<'a>,
973-
SizeToDoc: FnMut(&'a Value, &mut Env<'a>) -> Option<Document<'a>>,
973+
CreateDoc: FnMut(&mut State) -> Document<'a>,
974+
SizeToDoc: FnMut(&'a Value, &mut State) -> Option<Document<'a>>,
974975
UnitToDoc: FnMut(&'a u8) -> Option<Document<'a>>,
975976
{
976977
let mut size: Option<Document<'a>> = None;
@@ -1007,12 +1008,12 @@ where
10071008
Opt::Big { .. } => others.push("big".to_doc()),
10081009
Opt::Little { .. } => others.push("little".to_doc()),
10091010
Opt::Native { .. } => others.push("native".to_doc()),
1010-
Opt::Size { value, .. } => size = size_to_doc(value, env),
1011+
Opt::Size { value, .. } => size = size_to_doc(value, state),
10111012
Opt::Unit { value, .. } => unit = unit_to_doc(value),
10121013
}
10131014
}
10141015

1015-
let mut document = create_document(env);
1016+
let mut document = create_document(state);
10161017

10171018
document = document.append(size);
10181019
let others_is_empty = others.is_empty();
@@ -1180,23 +1181,23 @@ fn binop_documents<'a>(left: Document<'a>, op: &'static str, right: Document<'a>
11801181
fn let_assert<'a>(
11811182
value: &'a TypedExpr,
11821183
pattern: &'a TypedPattern,
1183-
env: &mut Env<'a>,
1184+
environment: &mut Env<'a>,
11841185
message: Option<&'a TypedExpr>,
11851186
position: Position,
11861187
location: SrcSpan,
11871188
) -> Document<'a> {
11881189
// If the pattern will never fail, like a tuple or a simple variable, we
11891190
// simply treat it as if it were a `let` assignment.
11901191
if pattern.always_matches() {
1191-
return let_(value, pattern, env);
1192+
return let_(value, pattern, environment);
11921193
}
11931194

11941195
let message = match message {
1195-
Some(message) => expr(message, env),
1196+
Some(message) => expr(message, environment),
11961197
None => string("Pattern match failed, no pattern matched the value."),
11971198
};
11981199

1199-
let subject = maybe_block_expr(value, env);
1200+
let subject = maybe_block_expr(value, environment);
12001201

12011202
// The code we generated for a `let assert` assignment looks something like
12021203
// this. For this Gleam code:
@@ -1248,26 +1249,31 @@ fn let_assert<'a>(
12481249
};
12491250

12501251
let (subject_assignment, subject) = if is_tail && !value.is_var() {
1251-
let variable = env.next_local_var_name(ASSERT_SUBJECT_VARIABLE);
1252+
let variable = environment.next_local_var_name(ASSERT_SUBJECT_VARIABLE);
12521253
let assignment = docvec![variable.clone(), " = ", subject, ",", line()];
12531254
(assignment, variable)
12541255
} else {
12551256
(nil(), subject)
12561257
};
12571258

1258-
let mut guards = vec![];
1259-
let mut vars = vec![];
1260-
let pattern_document = pattern::to_doc(pattern, &mut vars, env, &mut guards);
1261-
let clause_guard = optional_clause_guard(None, guards, env);
1259+
let mut pattern_printer = PatternPrinter::new(environment);
1260+
let pattern_document = pattern_printer.print(pattern);
1261+
let PatternPrinter {
1262+
environment,
1263+
variables,
1264+
guards,
1265+
} = pattern_printer;
1266+
1267+
let clause_guard = optional_clause_guard(None, guards, environment);
12621268

1263-
let value_document = match vars.as_slice() {
1269+
let value_document = match variables.as_slice() {
12641270
_ if is_tail => subject.clone(),
12651271
[] => "nil".to_doc(),
1266-
[variable] => env.local_var_name(variable),
1272+
[variable] => environment.local_var_name(variable),
12671273
variables => {
12681274
let variables = variables
12691275
.iter()
1270-
.map(|variable| env.local_var_name(variable));
1276+
.map(|variable| environment.local_var_name(variable));
12711277
docvec![
12721278
break_("{", "{"),
12731279
join(variables, break_(",", ", ")).nest(INDENT),
@@ -1277,14 +1283,14 @@ fn let_assert<'a>(
12771283
}
12781284
};
12791285

1280-
let assignment = match vars.as_slice() {
1286+
let assignment = match variables.as_slice() {
12811287
_ if is_tail => nil(),
12821288
[] => nil(),
1283-
[variable] => env.next_local_var_name(variable).append(" = "),
1289+
[variable] => environment.next_local_var_name(variable).append(" = "),
12841290
variables => {
12851291
let variables = variables
12861292
.iter()
1287-
.map(|variable| env.next_local_var_name(variable));
1293+
.map(|variable| environment.next_local_var_name(variable));
12881294
docvec![
12891295
break_("{", "{"),
12901296
join(variables, break_(",", ", ")).nest(INDENT),
@@ -1301,7 +1307,7 @@ fn let_assert<'a>(
13011307
value_document,
13021308
";",
13031309
line(),
1304-
env.next_local_var_name(ASSERT_FAIL_VARIABLE),
1310+
environment.next_local_var_name(ASSERT_FAIL_VARIABLE),
13051311
" ->",
13061312
docvec![
13071313
line(),
@@ -1310,13 +1316,13 @@ fn let_assert<'a>(
13101316
&message,
13111317
location,
13121318
vec![
1313-
("value", env.local_var_name(ASSERT_FAIL_VARIABLE)),
1319+
("value", environment.local_var_name(ASSERT_FAIL_VARIABLE)),
13141320
("start", location.start.to_doc()),
13151321
("'end'", value.location().end.to_doc()),
13161322
("pattern_start", pattern.location().start.to_doc()),
13171323
("pattern_end", pattern.location().end.to_doc()),
13181324
],
1319-
env,
1325+
environment,
13201326
)
13211327
.nest(INDENT)
13221328
]
@@ -1334,11 +1340,14 @@ fn let_assert<'a>(
13341340
]
13351341
}
13361342

1337-
fn let_<'a>(value: &'a TypedExpr, pat: &'a TypedPattern, env: &mut Env<'a>) -> Document<'a> {
1338-
let body = maybe_block_expr(value, env).group();
1339-
let mut guards = vec![];
1340-
1341-
pattern::to_doc(pat, &mut vec![], env, &mut guards)
1343+
fn let_<'a>(
1344+
value: &'a TypedExpr,
1345+
pattern: &'a TypedPattern,
1346+
environment: &mut Env<'a>,
1347+
) -> Document<'a> {
1348+
let body = maybe_block_expr(value, environment).group();
1349+
PatternPrinter::new(environment)
1350+
.print(pattern)
13421351
.append(" = ")
13431352
.append(body)
13441353
}
@@ -1530,7 +1539,7 @@ fn record_constructor_function(tag: &EcoString, arity: usize) -> Document<'_> {
15301539
.append("} end")
15311540
}
15321541

1533-
fn clause<'a>(clause: &'a TypedClause, env: &mut Env<'a>) -> Document<'a> {
1542+
fn clause<'a>(clause: &'a TypedClause, environment: &mut Env<'a>) -> Document<'a> {
15341543
let Clause {
15351544
guard,
15361545
pattern: pat,
@@ -1544,29 +1553,36 @@ fn clause<'a>(clause: &'a TypedClause, env: &mut Env<'a>) -> Document<'a> {
15441553
// rewriting because each pattern would define different (rewritten)
15451554
// variables names.
15461555
let mut then_doc = None;
1547-
let initial_erlang_vars = env.erl_function_scope_vars.clone();
1556+
let initial_erlang_vars = environment.erl_function_scope_vars.clone();
15481557
let mut end_erlang_vars = im::HashMap::new();
15491558

15501559
let doc = join(
15511560
std::iter::once(pat)
15521561
.chain(alternative_patterns)
15531562
.map(|patterns| {
1554-
let mut additional_guards = vec![];
1555-
env.erl_function_scope_vars = initial_erlang_vars.clone();
1563+
environment.erl_function_scope_vars = initial_erlang_vars.clone();
1564+
let mut pattern_printer = PatternPrinter::new(environment);
15561565

15571566
let patterns_doc = if patterns.len() == 1 {
1558-
let p = patterns.first().expect("Single pattern clause printing");
1559-
pattern::to_doc(p, &mut vec![], env, &mut additional_guards)
1567+
let pattern = patterns.first().expect("Single pattern clause printing");
1568+
pattern_printer.print(pattern)
15601569
} else {
15611570
tuple(patterns.iter().map(|pattern| {
1562-
pattern::to_doc(pattern, &mut vec![], env, &mut additional_guards)
1571+
pattern_printer.reset_variables();
1572+
pattern_printer.print(pattern)
15631573
}))
15641574
};
15651575

1566-
let guard = optional_clause_guard(guard.as_ref(), additional_guards, env);
1576+
let PatternPrinter {
1577+
environment,
1578+
guards,
1579+
variables: _,
1580+
} = pattern_printer;
1581+
1582+
let guard = optional_clause_guard(guard.as_ref(), guards, environment);
15671583
if then_doc.is_none() {
1568-
then_doc = Some(clause_consequence(then, env));
1569-
end_erlang_vars = env.erl_function_scope_vars.clone();
1584+
then_doc = Some(clause_consequence(then, environment));
1585+
end_erlang_vars = environment.erl_function_scope_vars.clone();
15701586
}
15711587

15721588
patterns_doc.append(
@@ -1578,7 +1594,7 @@ fn clause<'a>(clause: &'a TypedClause, env: &mut Env<'a>) -> Document<'a> {
15781594
";".to_doc().append(lines(2)),
15791595
);
15801596

1581-
env.erl_function_scope_vars = end_erlang_vars;
1597+
environment.erl_function_scope_vars = end_erlang_vars;
15821598
doc
15831599
}
15841600

0 commit comments

Comments
 (0)