Implement bit-fields.

This commit is contained in:
Stephen Chung
2021-06-02 14:29:18 +08:00
parent 25e99af07e
commit 71684f5e2a
11 changed files with 497 additions and 97 deletions

View File

@@ -1,5 +1,5 @@
use crate::dynamic::Variant;
use crate::{def_package, EvalAltResult, INT};
use crate::{def_package, EvalAltResult, Position, INT};
use std::ops::Range;
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
@@ -29,9 +29,9 @@ where
Default::default(),
Box::new(EvalAltResult::ErrorArithmetic(
"step value cannot be zero".to_string(),
crate::Position::NONE,
Position::NONE,
)),
crate::Position::NONE,
Position::NONE,
)
.into();
}
@@ -126,6 +126,68 @@ where
}
}
// Register range function with step
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
struct BitRange(INT, INT, usize);
const BITS: usize = std::mem::size_of::<INT>() * 8;
impl BitRange {
pub fn new(value: INT, from: INT, len: INT) -> Result<Self, Box<EvalAltResult>> {
let from = if from >= 0 {
let offset = from as usize;
#[cfg(not(feature = "unchecked"))]
if offset >= BITS {
return EvalAltResult::ErrorBitFieldBounds(BITS, from, Position::NONE).into();
}
offset
} else {
#[cfg(not(feature = "unchecked"))]
if let Some(abs_from) = from.checked_abs() {
if (abs_from as usize) > BITS {
return EvalAltResult::ErrorBitFieldBounds(BITS, from, Position::NONE).into();
}
BITS - (abs_from as usize)
} else {
return EvalAltResult::ErrorBitFieldBounds(BITS, from, Position::NONE).into();
}
#[cfg(feature = "unchecked")]
{
BITS - (from.abs() as usize)
}
};
let len = if len < 0 {
0
} else if from + (len as usize) > BITS {
BITS - from
} else {
len as usize
};
Ok(Self(value, 1 << from, len))
}
}
impl Iterator for BitRange {
type Item = bool;
fn next(&mut self) -> Option<Self::Item> {
let Self(value, mask, len) = *self;
if len == 0 {
None
} else {
let r = (value & mask) != 0;
self.1 <<= 1;
self.2 -= 1;
Some(r)
}
}
}
macro_rules! reg_range {
($lib:ident | $x:expr => $( $y:ty ),*) => {
$(
@@ -193,8 +255,8 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
#[cfg(not(feature = "unchecked"))]
if step == 0.0 {
return EvalAltResult::ErrorInFunctionCall("range".to_string(), "".to_string(),
Box::new(EvalAltResult::ErrorArithmetic("step value cannot be zero".to_string(), crate::Position::NONE)),
crate::Position::NONE,
Box::new(EvalAltResult::ErrorArithmetic("step value cannot be zero".to_string(), Position::NONE)),
Position::NONE,
).into();
}
@@ -255,8 +317,8 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
#[cfg(not(feature = "unchecked"))]
if step.is_zero() {
return EvalAltResult::ErrorInFunctionCall("range".to_string(), "".to_string(),
Box::new(EvalAltResult::ErrorArithmetic("step value cannot be zero".to_string(), crate::Position::NONE)),
crate::Position::NONE,
Box::new(EvalAltResult::ErrorArithmetic("step value cannot be zero".to_string(), Position::NONE)),
Position::NONE,
).into();
}
@@ -304,4 +366,18 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
#[cfg(feature = "metadata")]
lib.update_fn_metadata(_hash, &["from: Decimal", "to: Decimal", "step: Decimal", "Iterator<Item=Decimal>"]);
}
lib.set_iterator::<BitRange>();
let _hash = lib.set_native_fn("bits", |value, from, len| BitRange::new(value, from, len));
#[cfg(feature = "metadata")]
lib.update_fn_metadata(_hash, &["value: INT", "from: Decimal", "len: Decimal", "Iterator<Item=bool>"]);
let _hash = lib.set_native_fn("bits", |value, from| BitRange::new(value, from, INT::MAX));
#[cfg(feature = "metadata")]
lib.update_fn_metadata(_hash, &["value: INT", "from: Decimal", "Iterator<Item=bool>"]);
let _hash = lib.set_native_fn("bits", |value| BitRange::new(value, 0, INT::MAX));
#[cfg(feature = "metadata")]
lib.update_fn_metadata(_hash, &["value: INT", "Iterator<Item=bool>"]);
});