Skip to main content

ironwork_rt/lir/
text.rs

1//! INSPECT, STRING and UNSTRING (lir.md ยง9.1): the operands and receivers `crate::strings` works over,
2//! in the order the walker evaluates them.
3
4use super::{MovePlan, Operand, PlaceId, StepPlan, StorePlan};
5use crate::vocab::InspectMode;
6use crate::{codec_enum, codec_struct};
7
8/// An operand as STRING, UNSTRING, INSPECT and CALL BY CONTENT take it: bytes, not a value.
9#[derive(Clone, Debug, PartialEq, Eq)]
10pub enum Chars<P = PlaceId, O = Operand> {
11    /// A literal or figurative constant, its bytes made at lowering.
12    Literal(Vec<u8>),
13    /// A data item's storage.
14    Place(P),
15    /// FUNCTION, LENGTH OF or ADDRESS OF, converted as the statement converts a value.
16    Value(O),
17}
18
19/// What INSPECT examines: a data item, or for TALLYING alone a function's value, which
20/// `rt::text::tally` evaluates once before the phrases' operands.
21#[derive(Clone, Debug, PartialEq, Eq)]
22pub enum Inspected<P = PlaceId, O = Operand> {
23    Item(P),
24    Value(O),
25}
26
27#[derive(Clone, Debug, PartialEq, Eq)]
28pub struct InspectPlan<P = PlaceId, O = Operand> {
29    pub target: Inspected<P, O>,
30    pub tallying: Vec<InspectPhrase<P, O>>,
31    pub replacing: Vec<InspectPhrase<P, O>>,
32    pub converting: Option<Converting<P, O>>,
33}
34
35/// `pattern` is None for CHARACTERS; `by` is REPLACING's, and `counter` TALLYING's with its add.
36#[derive(Clone, Debug, PartialEq, Eq)]
37pub struct InspectPhrase<P = PlaceId, O = Operand> {
38    pub mode: InspectMode,
39    pub pattern: Option<Chars<P, O>>,
40    pub by: Option<Replacement<P, O>>,
41    pub counter: Option<(P, StepPlan)>,
42    /// BEFORE and AFTER INITIAL as written; the last of each applies.
43    pub bounds: Vec<Bound<P, O>>,
44}
45
46#[derive(Clone, Debug, PartialEq, Eq)]
47pub enum Replacement<P = PlaceId, O = Operand> {
48    Chars(Chars<P, O>),
49    /// A figurative constant's byte, as many times as the pattern is long.
50    Fill(u8),
51}
52
53#[derive(Clone, Debug, PartialEq, Eq)]
54pub struct Bound<P = PlaceId, O = Operand> {
55    pub after: bool,
56    pub value: Chars<P, O>,
57}
58
59#[derive(Clone, Debug, PartialEq, Eq)]
60pub struct Converting<P = PlaceId, O = Operand> {
61    pub table: ConvertTable<P, O>,
62    pub bounds: Vec<Bound<P, O>>,
63}
64
65#[derive(Clone, Debug, PartialEq, Eq)]
66pub enum ConvertTable<P = PlaceId, O = Operand> {
67    /// Both operands literals: each distinct byte of the first with its byte of the second.
68    Built(Vec<(u8, u8)>),
69    /// Operands of different lengths abend when the statement runs.
70    Operands { from: Chars<P, O>, to: Chars<P, O> },
71}
72
73/// The op returns Arm(1) on overflow and Arm(0) otherwise.
74#[derive(Clone, Debug, PartialEq, Eq)]
75pub struct StringPlan<P = PlaceId, O = Operand> {
76    pub into: P,
77    /// WITH POINTER: read as an integer before the first source, stored after the last.
78    pub pointer: Option<(P, StorePlan)>,
79    pub sources: Vec<StringSource<P, O>>,
80}
81
82/// `delimiter` is None for DELIMITED BY SIZE.
83#[derive(Clone, Debug, PartialEq, Eq)]
84pub struct StringSource<P = PlaceId, O = Operand> {
85    pub chars: Chars<P, O>,
86    pub delimiter: Option<Chars<P, O>>,
87}
88
89/// The op returns Arm(1) on overflow and Arm(0) otherwise.
90#[derive(Clone, Debug, PartialEq, Eq)]
91pub struct UnstringPlan<P = PlaceId, O = Operand> {
92    pub source: P,
93    pub pointer: Option<(P, StorePlan)>,
94    /// Each DELIMITED BY operand, true for ALL.
95    pub delimiters: Vec<(bool, Chars<P, O>)>,
96    pub into: Vec<UnstringInto<P>>,
97    /// TALLYING IN, which the count of fields filled is added to.
98    pub tallying: Option<(P, StepPlan)>,
99}
100
101/// `plan` moves the field's bytes as an alphanumeric sender; COUNT IN stores the field's length.
102#[derive(Clone, Copy, Debug, PartialEq, Eq)]
103pub struct UnstringInto<P = PlaceId> {
104    pub target: P,
105    pub plan: MovePlan,
106    pub delimiter: Option<DelimiterIn<P>>,
107    pub count: Option<(P, StorePlan)>,
108}
109
110/// `found` moves the delimiter that ended the field, and `none` moves SPACE when none did.
111#[derive(Clone, Copy, Debug, PartialEq, Eq)]
112pub struct DelimiterIn<P = PlaceId> {
113    pub target: P,
114    pub found: MovePlan,
115    pub none: MovePlan,
116}
117
118codec_enum!(Chars { Literal(bytes) = 0, Place(place) = 1, Value(value) = 2 });
119codec_enum!(Inspected { Item(place) = 0, Value(value) = 1 });
120codec_struct!(InspectPlan { target, tallying, replacing, converting });
121codec_struct!(InspectPhrase { mode, pattern, by, counter, bounds });
122codec_enum!(Replacement { Chars(chars) = 0, Fill(byte) = 1 });
123codec_struct!(Bound { after, value });
124codec_struct!(Converting { table, bounds });
125codec_enum!(ConvertTable { Built(pairs) = 0, Operands { from, to } = 1 });
126codec_struct!(StringPlan { into, pointer, sources });
127codec_struct!(StringSource { chars, delimiter });
128codec_struct!(UnstringPlan { source, pointer, delimiters, into, tallying });
129codec_struct!(UnstringInto { target, plan, delimiter, count });
130codec_struct!(DelimiterIn { target, found, none });