Skip to main content

ironwork_rt/lir/
class.rs

1//! A COBOL class definition (lir.md ยง9.8): its FACTORY and OBJECT data and its methods, each lowered
2//! as a program of its own.
3
4use super::{Program, SymId};
5use crate::codec_struct;
6use crate::module::ModuleError;
7use crate::module::codec::{Decode, Encode, Reader, Writer};
8use std::cell::Cell;
9
10/// Names are the defining program's symbols. `parent` is the external name of the class it
11/// inherits.
12#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct Class {
14    pub external: SymId,
15    pub parent: SymId,
16    pub factory: Option<ClassPart>,
17    pub object: Option<ClassPart>,
18    pub methods: Vec<Method>,
19}
20
21/// FACTORY or OBJECT data: a program whose storage is the data as its VALUE clauses leave it, and
22/// the offset of each 01 or 77 record in it.
23#[derive(Clone, Debug, PartialEq, Eq)]
24pub struct ClassPart {
25    pub data: Program,
26    pub records: Vec<u32>,
27}
28
29/// `params` and `returns` are Java type signatures. The method's LINKAGE records after its first
30/// `own_records` are its part's records, bound at each invocation to the object's or the factory's
31/// data.
32#[derive(Clone, Debug, PartialEq, Eq)]
33pub struct Method {
34    pub name: SymId,
35    pub factory: bool,
36    pub params: Vec<SymId>,
37    pub returns: Option<SymId>,
38    pub own_records: u16,
39    pub code: Program,
40}
41
42codec_struct!(ClassPart { data, records });
43codec_struct!(Method { name, factory, params, returns, own_records, code });
44
45thread_local! {
46    static IN_CLASS: Cell<bool> = const { Cell::new(false) };
47}
48
49impl Encode for Class {
50    fn encode(&self, w: &mut Writer) {
51        let Class { external, parent, factory, object, methods } = self;
52        external.encode(w);
53        parent.encode(w);
54        factory.encode(w);
55        object.encode(w);
56        methods.encode(w);
57    }
58}
59
60/// A method or part is a program and never a class, so a class inside one is refused before it is
61/// read, which keeps decoding from nesting deeper than one class.
62impl Decode for Class {
63    fn decode(r: &mut Reader<'_>) -> Result<Self, ModuleError> {
64        if IN_CLASS.get() {
65            return Err(r.malformed(r.position(), "a class definition inside a class definition"));
66        }
67        IN_CLASS.set(true);
68        let class = (|| {
69            Ok(Class {
70                external: Decode::decode(r)?,
71                parent: Decode::decode(r)?,
72                factory: Decode::decode(r)?,
73                object: Decode::decode(r)?,
74                methods: Decode::decode(r)?,
75            })
76        })();
77        IN_CLASS.set(false);
78        class
79    }
80}