Skip to main content

ironwork_rt/
storage.rs

1//! The storage vocabulary a program's data shares: how an item is held, where it sits, and the
2//! values that move between items.
3
4use crate::vocab::{Figurative, SignClause};
5use numeric::precision::{Fixed, Places};
6use zarch::hfp::{Hfp, Precision};
7use zarch::wide::U256;
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub enum Kind {
11    Group,
12    Alnum { justified: bool },
13    National,
14    Zoned { digits: u32, scale: u32, signed: bool, sign: Option<SignClause> },
15    Packed { digits: u32, scale: u32, signed: bool },
16    Binary { digits: u32, scale: u32, signed: bool, native: bool },
17    Float(Precision),
18    /// `edit` indexes the layout's list of edited PICTUREs.
19    NumericEdited { edit: u32, digits: u32, scale: u32, blank_when_zero: bool },
20    AlnumEdited { edit: u32 },
21    /// USAGE POINTER: an address, four bytes.
22    Pointer,
23    /// An index name or USAGE INDEX item, holding an occurrence number in four bytes.
24    Index,
25    /// USAGE OBJECT REFERENCE: four bytes naming an object, as under LP(32).
26    ObjectReference,
27    /// USAGE FUNCTION-POINTER or PROCEDURE-POINTER, four bytes.
28    ProgramPointer,
29}
30
31impl Kind {
32    pub fn is_numeric(self) -> bool {
33        matches!(self, Kind::Zoned { .. } | Kind::Packed { .. } | Kind::Binary { .. } | Kind::Float(_) | Kind::Index)
34    }
35
36    /// Digits and decimal places of a fixed-point numeric item.
37    pub fn digits_scale(self) -> Option<(u32, u32)> {
38        match self {
39            Kind::Zoned { digits, scale, .. }
40            | Kind::Packed { digits, scale, .. }
41            | Kind::Binary { digits, scale, .. }
42            | Kind::NumericEdited { digits, scale, .. } => Some((digits, scale)),
43            Kind::Index => Some((9, 0)),
44            _ => None,
45        }
46    }
47}
48
49#[derive(Clone, Copy, Debug)]
50pub struct Loc {
51    pub offset: usize,
52    pub len: usize,
53    pub kind: Kind,
54    pub item: usize,
55}
56
57#[derive(Clone, Debug)]
58pub enum Val {
59    Bytes(Vec<u8>),
60    National(Vec<u8>),
61    Num(Fixed),
62    Float(Hfp),
63    Fig(Figurative),
64    All(Vec<u8>),
65    /// A pointer value: `ADDRESS_BASE` (in the interpreter's run unit) plus an offset into run-unit memory, or 0 for NULL.
66    Address(u32),
67}
68
69/// A numeric literal's value; None unless it holds 1 to 31 digits.
70pub fn literal_fixed(text: &str) -> Option<Fixed> {
71    let (negative, body) = match text.as_bytes().first() {
72        Some(b'-') => (true, &text[1..]),
73        Some(b'+') => (false, &text[1..]),
74        _ => (false, text),
75    };
76    let (int, frac) = body.split_once('.').unwrap_or((body, ""));
77    let digits = format!("{int}{frac}");
78    if digits.is_empty() || digits.len() > 31 {
79        return None;
80    }
81    let magnitude = U256::from_u128(digits.parse().ok()?);
82    Some(Fixed { negative: negative && !magnitude.is_zero(), magnitude, places: Places::new(int.len().max(1) as u32, frac.len() as u32) })
83}