Skip to content

Commit c23f5a4

Browse files
committed
Unaligned bit arrays on the JavaScript target
1 parent ffd4f34 commit c23f5a4

File tree

68 files changed

+2843
-583
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+2843
-583
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
shell starting from OTP27.
1313
([Giacomo Cavalieri](https://github.com/giacomocavalieri))
1414

15+
- On the JavaScript target, bit array expressions and patterns no longer need to
16+
be byte aligned, and the `bits` segment type is now supported in patterns.
17+
([Richard Viney](https://github.com/richard-viney))
18+
1519
### Build tool
1620

1721
- `gleam new` now has refined project name validation - rather than failing on

compiler-core/src/javascript/expression.rs

+39-23
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,8 @@ impl<'module> Generator<'module> {
240240
if segment.type_ == crate::type_::int() {
241241
match (details.size_value, segment.value.as_ref()) {
242242
(Some(size_value), TypedExpr::Int { int_value, .. })
243-
if size_value <= SAFE_INT_SEGMENT_MAX_SIZE.into() =>
243+
if size_value <= SAFE_INT_SEGMENT_MAX_SIZE.into()
244+
&& (&size_value % BigInt::from(8) == BigInt::ZERO) =>
244245
{
245246
let bytes = bit_array_segment_int_value_to_bytes(
246247
int_value.clone(),
@@ -295,7 +296,24 @@ impl<'module> Generator<'module> {
295296
}
296297

297298
// Bit arrays
298-
[Opt::Bytes { .. } | Opt::Bits { .. }] => Ok(docvec![value, ".buffer"]),
299+
[Opt::Bits { .. }] => Ok(value),
300+
301+
// Bit arrays with explicit size. The explicit size slices the bit array to the
302+
// specified size. A runtime exception is thrown if the size exceeds the number
303+
// of bits in the bit array.
304+
[Opt::Bits { .. }, Opt::Size { value: size, .. }]
305+
| [Opt::Size { value: size, .. }, Opt::Bits { .. }] => match &**size {
306+
TypedExpr::Int { value: size, .. } => {
307+
Ok(docvec![value, ".slice(0, ", size, ")"])
308+
}
309+
310+
TypedExpr::Var { name, .. } => Ok(docvec![value, ".slice(0, ", name, ")"]),
311+
312+
_ => Err(Error::Unsupported {
313+
feature: "This bit array segment option".into(),
314+
location: segment.location,
315+
}),
316+
},
299317

300318
// Anything else
301319
_ => Err(Error::Unsupported {
@@ -348,15 +366,6 @@ impl<'module> Generator<'module> {
348366
_ => None,
349367
};
350368

351-
if let Some(size_value) = size_value.as_ref() {
352-
if *size_value > BigInt::ZERO && size_value % 8 != BigInt::ZERO {
353-
return Err(Error::Unsupported {
354-
feature: "Non byte aligned array".into(),
355-
location: segment.location,
356-
});
357-
}
358-
}
359-
360369
(
361370
size_value,
362371
self.not_in_tail_position(|gen| gen.wrap_expression(size))?,
@@ -1467,7 +1476,8 @@ fn bit_array<'a>(
14671476
if segment.type_ == crate::type_::int() {
14681477
match (details.size_value, segment.value.as_ref()) {
14691478
(Some(size_value), Constant::Int { int_value, .. })
1470-
if size_value <= SAFE_INT_SEGMENT_MAX_SIZE.into() =>
1479+
if size_value <= SAFE_INT_SEGMENT_MAX_SIZE.into()
1480+
&& (&size_value % BigInt::from(8) == BigInt::ZERO) =>
14711481
{
14721482
let bytes = bit_array_segment_int_value_to_bytes(
14731483
int_value.clone(),
@@ -1521,8 +1531,23 @@ fn bit_array<'a>(
15211531
Ok(docvec!["codepointBits(", value, ")"])
15221532
}
15231533

1524-
// Bit strings
1525-
[Opt::Bits { .. }] => Ok(docvec![value, ".buffer"]),
1534+
// Bit arrays
1535+
[Opt::Bits { .. }] => Ok(value),
1536+
1537+
// Bit arrays with explicit size. The explicit size slices the bit array to the
1538+
// specified size. A runtime exception is thrown if the size exceeds the number
1539+
// of bits in the bit array.
1540+
[Opt::Bits { .. }, Opt::Size { value: size, .. }]
1541+
| [Opt::Size { value: size, .. }, Opt::Bits { .. }] => match &**size {
1542+
Constant::Int { value: size, .. } => {
1543+
Ok(docvec![value, ".slice(0, ", size, ")"])
1544+
}
1545+
1546+
_ => Err(Error::Unsupported {
1547+
feature: "This bit array segment option".into(),
1548+
location: segment.location,
1549+
}),
1550+
},
15261551

15271552
// Anything else
15281553
_ => Err(Error::Unsupported {
@@ -1585,15 +1610,6 @@ fn sized_bit_array_segment_details<'a>(
15851610
_ => None,
15861611
};
15871612

1588-
if let Some(size_value) = size_value.as_ref() {
1589-
if *size_value > BigInt::ZERO && size_value % 8 != BigInt::ZERO {
1590-
return Err(Error::Unsupported {
1591-
feature: "Non byte aligned array".into(),
1592-
location: segment.location,
1593-
});
1594-
}
1595-
}
1596-
15971613
(size_value, constant_expr_fun(tracker, size)?)
15981614
}
15991615
_ => {

0 commit comments

Comments
 (0)