Skip to content

Commit 4280f7f

Browse files
GearsDatapackslpil
authored andcommitted
Use regular pattern matching instead of guards
1 parent d0f0a75 commit 4280f7f

15 files changed

+51
-68
lines changed

compiler-core/src/ast.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2122,6 +2122,11 @@ impl<A> Pattern<A> {
21222122
_ => false,
21232123
}
21242124
}
2125+
2126+
#[must_use]
2127+
pub fn is_string(&self) -> bool {
2128+
matches!(self, Self::String { .. })
2129+
}
21252130
}
21262131

21272132
impl TypedPattern {

compiler-core/src/erlang/pattern.rs

Lines changed: 33 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ use std::cell::RefCell;
22

33
use ecow::eco_format;
44

5-
use crate::{
6-
analyse::Inferred,
7-
strings::{length_utf16, length_utf32},
8-
};
5+
use crate::analyse::Inferred;
96

107
use super::*;
118

@@ -193,7 +190,21 @@ fn pattern_segment<'a>(
193190
) -> Document<'a> {
194191
let value = segment.value.as_ref();
195192

196-
let pattern_is_a_string_literal = matches!(value, Pattern::String { .. });
193+
let pattern_is_a_string_literal = match value {
194+
Pattern::String { .. } => true,
195+
Pattern::Assign { pattern, .. } => pattern.is_string(),
196+
Pattern::Int { .. }
197+
| Pattern::Float { .. }
198+
| Pattern::Variable { .. }
199+
| Pattern::VarUsage { .. }
200+
| Pattern::Discard { .. }
201+
| Pattern::List { .. }
202+
| Pattern::Constructor { .. }
203+
| Pattern::Tuple { .. }
204+
| Pattern::BitArray { .. }
205+
| Pattern::StringPrefix { .. }
206+
| Pattern::Invalid { .. } => false,
207+
};
197208
let pattern_is_a_discard = matches!(value, Pattern::Discard { .. });
198209

199210
let vars = RefCell::new(vars);
@@ -233,57 +244,24 @@ fn pattern_segment<'a>(
233244
variable_name
234245
}
235246

236-
// Here we do the same as for floats and ints, but we must calculate the size of
237-
// the string first, so we can correctly match the bit array segment then compare
238-
// it afterwards.
247+
// If we are assigning to a string which is UTF-16 or UTF-32, we cannot simply use
248+
// variable patterns and guards like we do with other segments. Gleam strings are
249+
// UTF-8 so we must anyway bind the correct value to the variable. We generate code
250+
// that looks like this:
251+
//
252+
// ```erlang
253+
// case X of
254+
// <<"Hello"/utf16>> ->
255+
// Message = <<"Hello"/utf8>>,
256+
// <clause body>
257+
// end.
258+
// ```
239259
Pattern::String { value, .. } => {
240-
let escaped = convert_string_escape_chars(value);
241-
let (utf_option, string_length) = if segment.has_utf16_option() {
242-
assignments.borrow_mut().push(PatternAssignment {
243-
variable: name,
244-
value: string(value),
245-
});
246-
247-
let option = if segment.has_native_option() {
248-
"utf16-native"
249-
} else if segment.endianness().is_big() {
250-
"utf16"
251-
} else {
252-
"utf16-little"
253-
};
254-
255-
// Each UTF-16 codepoint is 2 bytes
256-
(option, length_utf16(&escaped) * 2)
257-
} else if segment.has_utf32_option() {
258-
assignments.borrow_mut().push(PatternAssignment {
259-
variable: name,
260-
value: string(value),
261-
});
262-
263-
let option = if segment.has_native_option() {
264-
"utf32-native"
265-
} else if segment.endianness().is_big() {
266-
"utf32"
267-
} else {
268-
"utf32-little"
269-
};
270-
271-
// Each UTF-32 codepoint is 4 bytes
272-
(option, length_utf32(&escaped) * 4)
273-
} else {
274-
("utf8", escaped.len())
275-
};
276-
277-
guards.borrow_mut().push(docvec![
278-
variable_name.clone(),
279-
" =:= ",
280-
"<<\"",
281-
string_inner(value),
282-
"\"/",
283-
utf_option,
284-
">>",
285-
]);
286-
docvec![variable_name, ":", string_length]
260+
assignments.borrow_mut().push(PatternAssignment {
261+
variable: name,
262+
value: string(value),
263+
});
264+
value.to_doc().surround("\"", "\"")
287265
}
288266

289267
// Doing a pattern such as `<<_ as a>>` is the same as just `<<a>>`, so we treat it

compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__bit_array_assignment_utf16.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub fn main() {
2222
-spec main() -> binary().
2323
main() ->
2424
case <<"Hello"/utf16>> of
25-
<<M:10/binary>> when M =:= <<"Hello"/utf16>> ->
25+
<<"Hello"/utf16>> ->
2626
M@1 = <<"Hello"/utf8>>,
2727
M@1;
2828

compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__bit_array_assignment_utf16_little_endian.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub fn main() {
2222
-spec main() -> binary().
2323
main() ->
2424
case <<"Hello"/utf16-little>> of
25-
<<M:10/binary-little>> when M =:= <<"Hello"/utf16-little>> ->
25+
<<"Hello"/utf16-little>> ->
2626
M@1 = <<"Hello"/utf8>>,
2727
M@1;
2828

compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__bit_array_assignment_utf16_native_endian.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub fn main() {
2222
-spec main() -> binary().
2323
main() ->
2424
case <<"Hello"/utf16-native>> of
25-
<<M:10/binary-native>> when M =:= <<"Hello"/utf16-native>> ->
25+
<<"Hello"/utf16-native>> ->
2626
M@1 = <<"Hello"/utf8>>,
2727
M@1;
2828

compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__bit_array_assignment_utf32.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub fn main() {
2222
-spec main() -> binary().
2323
main() ->
2424
case <<"Hello"/utf32>> of
25-
<<M:20/binary>> when M =:= <<"Hello"/utf32>> ->
25+
<<"Hello"/utf32>> ->
2626
M@1 = <<"Hello"/utf8>>,
2727
M@1;
2828

compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__bit_array_assignment_utf32_little_endian.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub fn main() {
2222
-spec main() -> binary().
2323
main() ->
2424
case <<"Hello"/utf32-little>> of
25-
<<M:20/binary-little>> when M =:= <<"Hello"/utf32-little>> ->
25+
<<"Hello"/utf32-little>> ->
2626
M@1 = <<"Hello"/utf8>>,
2727
M@1;
2828

compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__case__bit_array_assignment_utf32_native_endian.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub fn main() {
2222
-spec main() -> binary().
2323
main() ->
2424
case <<"Hello"/utf32-native>> of
25-
<<M:20/binary-native>> when M =:= <<"Hello"/utf32-native>> ->
25+
<<"Hello"/utf32-native>> ->
2626
M@1 = <<"Hello"/utf8>>,
2727
M@1;
2828

compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_string.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub fn main() {
2020
-spec main() -> binary().
2121
main() ->
2222
Message@1 = case <<"Hello, world!"/utf8>> of
23-
<<Message:13/binary>> when Message =:= <<"Hello, world!"/utf8>> -> Message;
23+
<<"Hello, world!"/utf8>> -> <<"Hello, world!"/utf8>>;
2424
_assert_fail ->
2525
erlang:error(#{gleam_error => let_assert,
2626
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,

compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__let_assert__bit_array_assignment_utf16.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub fn main() {
2020
-spec main() -> binary().
2121
main() ->
2222
M@1 = case <<"Hello"/utf16>> of
23-
<<M:10/binary>> when M =:= <<"Hello"/utf16>> -> <<"Hello"/utf8>>;
23+
<<"Hello"/utf16>> -> <<"Hello"/utf8>>;
2424
_assert_fail ->
2525
erlang:error(#{gleam_error => let_assert,
2626
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,

0 commit comments

Comments
 (0)