Skip to main content

ironwork_syntax/ast/
oo.rs

1//! Object-oriented COBOL as Enterprise COBOL has it, for Java interoperability: class definitions
2//! with factory and object paragraphs, methods, the REPOSITORY paragraph and INVOKE.
3
4use super::{DataEntry, Operand, Program, Ref, Stmt};
5use crate::Pos;
6
7/// What a program, class or method knows of classes.
8#[derive(Clone, Debug, Default, PartialEq, Eq)]
9pub struct Oo {
10    /// REPOSITORY CLASS entries: the outermost program's for it and its contained programs, the
11    /// class's for the class and each of its methods.
12    pub repository: Vec<ClassEntry>,
13    pub unit: OoUnit,
14}
15
16#[derive(Clone, Debug, Default, PartialEq, Eq)]
17pub enum OoUnit {
18    #[default]
19    Program,
20    Class(Box<ClassDef>),
21    Method(MethodOf),
22}
23
24/// `CLASS name [IS "external"]` in a REPOSITORY paragraph.
25#[derive(Clone, Debug, PartialEq, Eq)]
26pub struct ClassEntry {
27    pub name: String,
28    /// As written, case kept; or the name made into one as IBM makes it.
29    pub external: String,
30    pub pos: Pos,
31}
32
33/// The external class-name IBM forms from a class-name with no literal: uppercase, hyphens as
34/// zeros, a leading digit 1-9 as A-I and 0 as J.
35pub fn external_class_name(name: &str) -> String {
36    name.to_ascii_uppercase()
37        .chars()
38        .enumerate()
39        .map(|(i, c)| match c {
40            '-' => '0',
41            '0' if i == 0 => 'J',
42            '1'..='9' if i == 0 => (b'A' + (c as u8 - b'1')) as char,
43            c => c,
44        })
45        .collect()
46}
47
48impl Oo {
49    /// The external name of a class-name in the REPOSITORY.
50    pub fn external(&self, name: &str) -> Option<&str> {
51        self.repository.iter().find(|e| e.name == name).map(|e| e.external.as_str())
52    }
53
54    pub fn class(&self) -> Option<&ClassDef> {
55        match &self.unit {
56            OoUnit::Class(c) => Some(c),
57            _ => None,
58        }
59    }
60
61    pub fn method(&self) -> Option<&MethodOf> {
62        match &self.unit {
63            OoUnit::Method(m) => Some(m),
64            _ => None,
65        }
66    }
67}
68
69#[derive(Clone, Debug, PartialEq, Eq)]
70pub struct ClassDef {
71    pub name: String,
72    /// The class-name after INHERITS, which the REPOSITORY must name.
73    pub inherits: String,
74    pub factory: Option<ClassPart>,
75    pub object: Option<ClassPart>,
76    pub pos: Pos,
77}
78
79/// A FACTORY or OBJECT paragraph: its data, which the methods share, and its methods.
80#[derive(Clone, Debug, Default, PartialEq, Eq)]
81pub struct ClassPart {
82    pub working_storage: Vec<DataEntry>,
83    pub methods: Vec<Program>,
84    pub pos: Pos,
85}
86
87/// A method: the class that defines it, whether it is a factory method, and its name as written.
88#[derive(Clone, Debug, PartialEq, Eq)]
89pub struct MethodOf {
90    pub class: String,
91    pub factory: bool,
92    pub name: String,
93    pub pos: Pos,
94}
95
96#[derive(Clone, Debug, PartialEq, Eq)]
97pub enum InvokeMethod {
98    New,
99    /// A literal method name, case kept.
100    Named(String),
101    /// A data item holding the method name.
102    Identifier(Ref),
103}
104
105/// INVOKE: the object, class-name, SELF or SUPER in `target`, then what to run.
106#[derive(Clone, Debug, PartialEq, Eq)]
107pub struct Invoke {
108    pub target: Ref,
109    pub method: InvokeMethod,
110    /// The BY VALUE arguments: identifiers, literals and LENGTH OF.
111    pub using: Vec<Operand>,
112    pub returning: Option<Ref>,
113    pub on_exception: Option<Vec<Stmt>>,
114    pub not_on_exception: Option<Vec<Stmt>>,
115    pub pos: Pos,
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121
122    #[test]
123    fn external_names_as_ibm_forms_them() {
124        assert_eq!(external_class_name("Account"), "ACCOUNT");
125        assert_eq!(external_class_name("my-class_1"), "MY0CLASS_1");
126        assert_eq!(external_class_name("1st-class"), "AST0CLASS");
127        assert_eq!(external_class_name("0ne"), "JNE");
128    }
129}