Skip to main content

ironwork_exec/machine/
facts.rs

1//! What `rt` asks of the running program, and the statement inputs `rt` takes, built from the AST
2//! with the walker's references as handles.
3
4use super::*;
5use compile::facts::Facts;
6use crate::files::{Dd, Keying, Open};
7use crate::printer::{self, Space};
8use rt::callee::Arguments;
9use rt::fileio::{self, Advance, Files};
10use rt::host::{Host, Values};
11use rt::lir::{self, Chars, Replacement};
12use rt::text;
13use rt::unit::UnitHost;
14use std::rc::Rc;
15
16impl<'p> Machine<'p, '_, '_> {
17    /// Holds no borrow of the machine, so a call can take it beside `self.unit`.
18    pub(super) fn facts(&self) -> Facts<'p> {
19        Facts { layout: self.layout, collating: self.collating, options: self.options, page: self.page, decimal_point: self.decimal_point() }
20    }
21}
22
23/// An INSPECT phrase, its literals read as the inspected item's characters when the statement runs.
24pub(super) fn inspect_phrase(p: &InspectPhrase) -> text::InspectPhrase<&Ref, &Operand> {
25    let by = p.by.as_ref().map(|op| Replacement::Chars(chars(op)));
26    text::InspectPhrase { mode: p.mode, pattern: p.pattern.as_ref().map(chars), by, counter: p.counter.as_ref(), bounds: bounds(&p.bounds) }
27}
28
29/// An operand as STRING, UNSTRING and INSPECT take it: an item's storage, or anything else's value.
30pub(super) fn chars(op: &Operand) -> Chars<&Ref, &Operand> {
31    match op {
32        Operand::Ref(r) => Chars::Place(r),
33        other => Chars::Value(other),
34    }
35}
36
37pub(super) fn bounds(bounds: &[Bound]) -> Vec<lir::Bound<&Ref, &Operand>> {
38    bounds.iter().map(|b| lir::Bound { after: b.after, value: chars(&b.value) }).collect()
39}
40
41impl<'a, 'p> Host<&'a Ref> for Machine<'p, '_, '_> {
42    type Facts = Facts<'p>;
43
44    fn facts(&self) -> Facts<'p> {
45        Machine::facts(self)
46    }
47
48    fn mem(&mut self) -> &mut [u8] {
49        &mut self.unit.mem
50    }
51
52    fn taint(&mut self) -> Option<&mut rt::taint::Taint> {
53        self.unit.taint.as_mut()
54    }
55
56    fn locate(&mut self, place: &'a Ref, receiving: bool) -> R<Loc> {
57        self.locate_as(place, receiving)
58    }
59
60    fn integer(&mut self, place: &'a Ref, pos: Pos) -> R<i64> {
61        Machine::integer(self, &Expr::Operand(Operand::Ref(place.clone())), pos)
62    }
63
64    fn assign(&mut self, dest: Loc, val: Val, src: Option<Loc>, pos: Pos) -> R<()> {
65        store::assign(&self.facts(), self.unit, dest, val, src, pos)
66    }
67
68    fn store_fixed(&mut self, dest: Loc, value: &Fixed, pos: Pos) -> R<()> {
69        store::store_fixed(&self.facts(), self.unit, dest, value, false, pos)
70    }
71}
72
73impl<'a> Values<&'a Ref, &'a Operand> for Machine<'_, '_, '_> {
74    fn value(&mut self, operand: &&'a Operand, pos: Pos) -> R<Val> {
75        self.operand(operand, pos)
76    }
77}
78
79impl<'w> UnitHost<'w> for Machine<'_, '_, 'w> {
80    type Program = Rc<Compiled>;
81    type Loader = crate::unit::Library;
82
83    fn unit(&mut self) -> &mut RunUnit<'w> {
84        self.unit
85    }
86}
87
88impl<'a, 'w> Arguments<'w, &'a Ref, &'a Operand> for Machine<'_, '_, 'w> {
89    fn item(&self, operand: &&'a Operand) -> Option<&'a Ref> {
90        match *operand {
91            Operand::Ref(r) => Some(r),
92            _ => None,
93        }
94    }
95
96    fn length_of(&self, operand: &&'a Operand) -> bool {
97        matches!(operand, Operand::LengthOf(_))
98    }
99
100    fn content_item(&mut self, place: &'a Ref) -> R<Loc> {
101        let loc = self.locate(place)?;
102        self.numcheck(loc, false, place.pos)?;
103        Ok(loc)
104    }
105}
106
107/// An integer the file verbs have the walker evaluate: a LINAGE value or an ADVANCING count.
108#[derive(Clone, Copy)]
109pub(super) enum Int<'a> {
110    Linage(&'a LinageValue),
111    Count(&'a Expr),
112}
113
114impl<'p> Machine<'p, '_, '_> {
115    /// File k's SELECT and FD as `rt::fileio` takes them.
116    pub(super) fn file_desc(&self, k: usize) -> fileio::File<'p, &'p Ref, Int<'p>> {
117        let (program, layout) = (self.program, self.layout);
118        let decl = &program.files[k];
119        let counter = layout.linage_counters.get(k).copied().flatten().map(|i| {
120            let item = &layout.items[i];
121            Loc { offset: self.base + item.offset as usize, len: item.size as usize, kind: item.kind, item: i }
122        });
123        fileio::File {
124            index: k,
125            name: &decl.name,
126            assign: &decl.assign,
127            assign_item: decl.assign_item.as_ref().map(|a| (&a.reference, decl.pos)),
128            organization: match decl.organization {
129                Organization::Sequential => lir::Organization::Sequential,
130                Organization::LineSequential => lir::Organization::LineSequential,
131                Organization::Indexed => lir::Organization::Indexed,
132                Organization::Relative => lir::Organization::Relative,
133            },
134            access: match decl.access {
135                Access::Sequential => lir::Access::Sequential,
136                Access::Random => lir::Access::Random,
137                Access::Dynamic => lir::Access::Dynamic,
138            },
139            optional: decl.optional,
140            format: self.described_format(k),
141            status: decl.status.as_ref(),
142            relative: decl.relative_key.as_ref(),
143            linage: decl.linage.as_ref().map(|l| fileio::Linage {
144                lines: Int::Linage(&l.lines),
145                footing: l.footing.as_ref().map(Int::Linage),
146                top: l.top.as_ref().map(Int::Linage),
147                bottom: l.bottom.as_ref().map(Int::Linage),
148                counter,
149            }),
150            carriage: self.carriage[k].map(|c| lir::Carriage { machine: c.machine, reserved: c.reserved }),
151            area: self.area(k),
152            read_lengths: {
153                let (shortest, longest) = compile::read_lengths(decl, layout, k, self.options.vlr);
154                (shortest as usize, longest as usize)
155            },
156            depending: decl.record_depending.as_ref().map(|item| {
157                let (shortest, longest) = compile::varying_lengths(decl, layout, k);
158                fileio::Depending { item, lengths: (shortest as usize, longest as usize) }
159            }),
160        }
161    }
162}
163
164pub(super) fn spacing(space: Space) -> lir::Spacing {
165    match space {
166        Space::Lines(n) => lir::Spacing::Lines(n),
167        Space::Channel(c) => lir::Spacing::Channel(c),
168        Space::PageMode => lir::Spacing::PageMode,
169    }
170}
171
172pub(super) fn advance(a: &Advancing) -> Advance<'_, Int<'_>> {
173    match a {
174        Advancing::Lines { before, count } => Advance::Lines { before: *before, count: Int::Count(count) },
175        Advancing::Page { before } => Advance::Page { before: *before },
176        Advancing::Mnemonic { before, name, environment } => Advance::Mnemonic { before: *before, space: printer::mnemonic_space(environment).map(spacing), name, environment },
177    }
178}
179
180impl<'a> Files<&'a Ref, Int<'a>> for Machine<'_, '_, '_> {
181    fn slot(&mut self, k: usize) -> &mut Option<Open> {
182        self.unit.file(self.me, k)
183    }
184
185    fn locked(&mut self, k: usize) -> &mut bool {
186        self.unit.locked(self.me, k)
187    }
188
189    fn dd(&self, assign: &str) -> Option<Dd> {
190        self.unit.dds.assigned(assign)
191    }
192
193    fn notify(&mut self, event: Event<'_>) {
194        self.unit.notify(event);
195    }
196
197    fn sink(&mut self, kind: &'static str, pos: Pos, operand: &str) {
198        Machine::sink(self, kind, pos, operand);
199    }
200
201    fn int(&mut self, value: Int<'a>, pos: Pos) -> R<i64> {
202        match value {
203            Int::Linage(v) => self.linage_value(v, pos),
204            Int::Count(e) => self.integer(e, pos),
205        }
206    }
207
208    fn keying(&mut self, k: usize, pos: Pos) -> R<Keying> {
209        Machine::keying(self, k, pos)
210    }
211
212    fn key_value(&mut self, k: usize, keying: &Keying, key: &'a Ref, partial: bool, pos: Pos) -> R<(usize, Vec<u8>)> {
213        self.key_named(k, keying, key, partial, pos)
214    }
215}