Skip to content

Commit bb69dd9

Browse files
committed
Unaligned bit arrays on the JavaScript target
1 parent e9f1dd6 commit bb69dd9

File tree

69 files changed

+2559
-570
lines changed

Some content is hidden

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

69 files changed

+2559
-570
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@
7676
- Better error message for existed type constructor being used as value constructor.
7777
([Jiangda Wang](https://github.com/Frank-III))
7878

79+
- On the JavaScript target, bit array expressions and patterns no longer need to
80+
be byte aligned, and the `bits` segment type is now supported in patterns.
81+
([Richard Viney](https://github.com/richard-viney))
82+
7983
### Build tool
8084

8185
- Improved the error message you get when trying to add a package that doesn't

compiler-core/src/javascript/expression.rs

+38-22
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 UNREACHABLE".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))?,
@@ -1460,7 +1469,8 @@ fn bit_array<'a>(
14601469
if segment.type_ == crate::type_::int() {
14611470
match (details.size_value, segment.value.as_ref()) {
14621471
(Some(size_value), Constant::Int { int_value, .. })
1463-
if size_value <= SAFE_INT_SEGMENT_MAX_SIZE.into() =>
1472+
if size_value <= SAFE_INT_SEGMENT_MAX_SIZE.into()
1473+
&& (&size_value % BigInt::from(8) == BigInt::ZERO) =>
14641474
{
14651475
let bytes = bit_array_segment_int_value_to_bytes(
14661476
int_value.clone(),
@@ -1514,9 +1524,24 @@ fn bit_array<'a>(
15141524
Ok(docvec!["codepointBits(", value, ")"])
15151525
}
15161526

1517-
// Bit strings
1527+
// Bit arrays
15181528
[Opt::Bits { .. }] => Ok(docvec![value, ".buffer"]),
15191529

1530+
// Bit arrays with explicit size. The explicit size slices the bit array to the
1531+
// specified size. A runtime exception is thrown if the size exceeds the number
1532+
// of bits in the bit array.
1533+
[Opt::Bits { .. }, Opt::Size { value: size, .. }]
1534+
| [Opt::Size { value: size, .. }, Opt::Bits { .. }] => match &**size {
1535+
Constant::Int { value: size, .. } => {
1536+
Ok(docvec![value, ".slice(0, ", size, ")"])
1537+
}
1538+
1539+
_ => Err(Error::Unsupported {
1540+
feature: "This bit array segment option".into(),
1541+
location: segment.location,
1542+
}),
1543+
},
1544+
15201545
// Anything else
15211546
_ => Err(Error::Unsupported {
15221547
feature: "This bit array segment option".into(),
@@ -1578,15 +1603,6 @@ fn sized_bit_array_segment_details<'a>(
15781603
_ => None,
15791604
};
15801605

1581-
if let Some(size_value) = size_value.as_ref() {
1582-
if *size_value > BigInt::ZERO && size_value % 8 != BigInt::ZERO {
1583-
return Err(Error::Unsupported {
1584-
feature: "Non byte aligned array".into(),
1585-
location: segment.location,
1586-
});
1587-
}
1588-
}
1589-
15901606
(size_value, constant_expr_fun(tracker, size)?)
15911607
}
15921608
_ => {

0 commit comments

Comments
 (0)