Skip to content

Commit

Permalink
Unaligned bit arrays on the JavaScript target
Browse files Browse the repository at this point in the history
  • Loading branch information
richard-viney committed Dec 4, 2024
1 parent cd2c872 commit 2496b81
Show file tree
Hide file tree
Showing 69 changed files with 2,559 additions and 570 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@
O(1) operation instead of O(N), significantly improving performance.
([Richard Viney](https://github.com/richard-viney))

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

### Build tool

- Improved the error message you get when trying to add a package that doesn't
Expand Down
60 changes: 38 additions & 22 deletions compiler-core/src/javascript/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,8 @@ impl<'module> Generator<'module> {
if segment.type_ == crate::type_::int() {
match (details.size_value, segment.value.as_ref()) {
(Some(size_value), TypedExpr::Int { int_value, .. })
if size_value <= SAFE_INT_SEGMENT_MAX_SIZE.into() =>
if size_value <= SAFE_INT_SEGMENT_MAX_SIZE.into()
&& (&size_value % BigInt::from(8) == BigInt::ZERO) =>
{
let bytes = bit_array_segment_int_value_to_bytes(
int_value.clone(),
Expand Down Expand Up @@ -295,7 +296,24 @@ impl<'module> Generator<'module> {
}

// Bit arrays
[Opt::Bytes { .. } | Opt::Bits { .. }] => Ok(docvec![value, ".buffer"]),
[Opt::Bits { .. }] => Ok(value),

// Bit arrays with explicit size. The explicit size slices the bit array to the
// specified size. A runtime exception is thrown if the size exceeds the number
// of bits in the bit array.
[Opt::Bits { .. }, Opt::Size { value: size, .. }]
| [Opt::Size { value: size, .. }, Opt::Bits { .. }] => match &**size {
TypedExpr::Int { value: size, .. } => {
Ok(docvec![value, ".slice(0, ", size, ")"])
}

TypedExpr::Var { name, .. } => Ok(docvec![value, ".slice(0, ", name, ")"]),

_ => Err(Error::Unsupported {
feature: "This bit array segment option UNREACHABLE".into(),
location: segment.location,
}),
},

// Anything else
_ => Err(Error::Unsupported {
Expand Down Expand Up @@ -348,15 +366,6 @@ impl<'module> Generator<'module> {
_ => None,
};

if let Some(size_value) = size_value.as_ref() {
if *size_value > BigInt::ZERO && size_value % 8 != BigInt::ZERO {
return Err(Error::Unsupported {
feature: "Non byte aligned array".into(),
location: segment.location,
});
}
}

(
size_value,
self.not_in_tail_position(|gen| gen.wrap_expression(size))?,
Expand Down Expand Up @@ -1460,7 +1469,8 @@ fn bit_array<'a>(
if segment.type_ == crate::type_::int() {
match (details.size_value, segment.value.as_ref()) {
(Some(size_value), Constant::Int { int_value, .. })
if size_value <= SAFE_INT_SEGMENT_MAX_SIZE.into() =>
if size_value <= SAFE_INT_SEGMENT_MAX_SIZE.into()
&& (&size_value % BigInt::from(8) == BigInt::ZERO) =>
{
let bytes = bit_array_segment_int_value_to_bytes(
int_value.clone(),
Expand Down Expand Up @@ -1514,9 +1524,24 @@ fn bit_array<'a>(
Ok(docvec!["codepointBits(", value, ")"])
}

// Bit strings
// Bit arrays
[Opt::Bits { .. }] => Ok(docvec![value, ".buffer"]),

// Bit arrays with explicit size. The explicit size slices the bit array to the
// specified size. A runtime exception is thrown if the size exceeds the number
// of bits in the bit array.
[Opt::Bits { .. }, Opt::Size { value: size, .. }]
| [Opt::Size { value: size, .. }, Opt::Bits { .. }] => match &**size {
Constant::Int { value: size, .. } => {
Ok(docvec![value, ".slice(0, ", size, ")"])
}

_ => Err(Error::Unsupported {
feature: "This bit array segment option".into(),
location: segment.location,
}),
},

// Anything else
_ => Err(Error::Unsupported {
feature: "This bit array segment option".into(),
Expand Down Expand Up @@ -1578,15 +1603,6 @@ fn sized_bit_array_segment_details<'a>(
_ => None,
};

if let Some(size_value) = size_value.as_ref() {
if *size_value > BigInt::ZERO && size_value % 8 != BigInt::ZERO {
return Err(Error::Unsupported {
feature: "Non byte aligned array".into(),
location: segment.location,
});
}
}

(size_value, constant_expr_fun(tracker, size)?)
}
_ => {
Expand Down
Loading

0 comments on commit 2496b81

Please sign in to comment.