Skip to main content

ironwork_exec/machine/
le_services.rs

1//! A CALL that reaches a Language Environment callable service: the walker builds the argument
2//! addresses and runs the CALL's phrases, and `rt::le` runs the service.
3
4use super::*;
5use crate::le::{self, LeHost};
6use std::rc::Rc;
7
8impl<'p> Machine<'p, '_, '_> {
9    pub(super) fn le_call(&mut self, c: &'p Call, name: &str) -> R<Flow> {
10        let mark = self.unit.mem.len();
11        let outcome = self.le_arguments(c).and_then(|args| self.le_service(name, &args, c.pos));
12        self.unit.release_temporaries(mark);
13        outcome?;
14        match &c.not_on_exception {
15            Some(body) => self.run_block(body),
16            None => Ok(Flow::Next),
17        }
18    }
19
20    /// Each argument's address in run-unit memory, as a CALL to a program passes it.
21    fn le_arguments(&mut self, c: &Call) -> R<Vec<Option<usize>>> {
22        let mut addresses = Vec::new();
23        for arg in &c.using {
24            let at = match (arg.mode, &arg.value) {
25                (_, None) => None,
26                (ArgMode::Reference, Some(Operand::Ref(r))) => Some(self.locate(r)?.offset),
27                (ArgMode::Value, Some(op)) => {
28                    let bytes = self.value_argument(op, c.pos)?;
29                    Some(self.unit.push_temporary(&bytes))
30                }
31                (_, Some(op)) => {
32                    let bytes = self.content_argument(op, c.pos)?;
33                    Some(self.unit.push_temporary(&bytes))
34                }
35            };
36            addresses.push(at);
37        }
38        Ok(addresses)
39    }
40
41    fn le_service(&mut self, name: &str, args: &[Option<usize>], pos: Pos) -> R<()> {
42        match le::service(name) {
43            Some(service) => le::call(self, service, args, pos),
44            None => Err(Abend::ironwork(format!("CALL {name}: not a service ironwork provides"), pos)),
45        }
46    }
47}
48
49impl<'w> LeHost<'w> for Machine<'_, '_, 'w> {
50    type Program = Rc<Compiled>;
51    type Loader = crate::unit::Library;
52
53    fn unit(&mut self) -> &mut RunUnit<'w> {
54        self.unit
55    }
56
57    fn page(&self) -> &'static CodePage {
58        self.page
59    }
60
61    fn method_name(program: &Rc<Compiled>) -> Option<String> {
62        program.program.oo.as_deref().and_then(|o| o.method()).map(|m| format!("{}.{}", m.class, m.name))
63    }
64}