diff --git a/src/transform/common.rs b/src/transform/common.rs index 71a325d..9f79e1a 100644 --- a/src/transform/common.rs +++ b/src/transform/common.rs @@ -239,7 +239,15 @@ pub(crate) fn replace_block_ids(ir: &mut IR, from: &HashSet, to: String) } } -pub(crate) fn calc_array(mut offsets: Vec) -> (u32, Array) { +#[derive(Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq, Default)] +pub enum ArrayMode { + #[default] + Standard, + Cursed, + Holey, +} + +pub(crate) fn calc_array(mut offsets: Vec, mode: ArrayMode) -> anyhow::Result<(u32, Array)> { offsets.sort_unstable(); // Guess stride. @@ -261,19 +269,30 @@ pub(crate) fn calc_array(mut offsets: Vec) -> (u32, Array) { .all(|(n, &i)| i == start_offset + (n as u32) * stride) { // Array is regular, - ( + return Ok(( start_offset, Array::Regular(RegularArray { len: offsets.len() as _, stride, }), - ) - } else { - // Array is irregular, - for o in &mut offsets { - *o -= start_offset + )); + } + + // Array is irregular, If we wanted a regular array, fail. + match mode { + ArrayMode::Standard => { + bail!("arrayize: items are not evenly spaced. Set `mode: Cursed` to allow index->offset relation to be non-linear, or `mode: Holey` to keep it linear but fill the holes with indexes that won't be valid.") + } + ArrayMode::Cursed => { + for o in &mut offsets { + *o -= start_offset + } + Ok((start_offset, Array::Cursed(CursedArray { offsets }))) + } + ArrayMode::Holey => { + let len = (offsets.last().unwrap() - offsets.first().unwrap()) / stride + 1; + Ok((start_offset, Array::Regular(RegularArray { len, stride }))) } - (start_offset, Array::Cursed(CursedArray { offsets })) } } diff --git a/src/transform/make_field_array.rs b/src/transform/make_field_array.rs index 31dd54c..aea4173 100644 --- a/src/transform/make_field_array.rs +++ b/src/transform/make_field_array.rs @@ -11,7 +11,7 @@ pub struct MakeFieldArray { pub from: String, pub to: String, #[serde(default)] - pub allow_cursed: bool, + pub mode: ArrayMode, } impl MakeFieldArray { @@ -55,13 +55,10 @@ impl MakeFieldArray { info!(" {}", i.name); } - let (offset, array) = - calc_array(items.iter().map(|x| x.bit_offset.min_offset()).collect()); - if let Array::Cursed(_) = &array { - if !self.allow_cursed { - bail!("arrayize: items {} are not evenly spaced. Set `allow_cursed: true` to allow this.", to) - } - } + let (offset, array) = calc_array( + items.iter().map(|x| x.bit_offset.min_offset()).collect(), + self.mode, + )?; let mut item = items[0].clone(); diff --git a/src/transform/make_register_array.rs b/src/transform/make_register_array.rs index b8163a3..fd67cf3 100644 --- a/src/transform/make_register_array.rs +++ b/src/transform/make_register_array.rs @@ -1,4 +1,3 @@ -use anyhow::bail; use log::*; use serde::{Deserialize, Serialize}; @@ -11,7 +10,7 @@ pub struct MakeRegisterArray { pub from: String, pub to: String, #[serde(default)] - pub allow_cursed: bool, + pub mode: ArrayMode, } impl MakeRegisterArray { @@ -39,12 +38,8 @@ impl MakeRegisterArray { info!(" {}", i.name); } - let (offset, array) = calc_array(items.iter().map(|x| x.byte_offset).collect()); - if let Array::Cursed(_) = &array { - if !self.allow_cursed { - bail!("arrayize: items {} are not evenly spaced. Set `allow_cursed: true` to allow this.", to); - } - } + let (offset, array) = + calc_array(items.iter().map(|x| x.byte_offset).collect(), self.mode)?; let mut item = items[0].clone();