Skip to main content

ironwork_exec/
oo.rs

1//! Where a class definition is found. The run unit's objects and classes, and running them, are
2//! `rt::oo`; compiling and checking a class is `compile::oo`.
3
4pub use compile::oo::*;
5pub use compile::oo::{ClassCode, MethodCode, Part};
6pub use rt::oo::*;
7
8use syntax::ast::Program;
9
10pub(crate) fn refuse_to_run(program: &Program) -> Result<(), crate::Abend> {
11    match program.oo.as_ref().and_then(|o| o.class()) {
12        Some(c) => Err(crate::Abend { code: crate::abend::AbendCode::Ironwork, message: format!("{} is a class definition: run a program that uses it", c.name), pos: c.pos, file: None }),
13        None => Ok(()),
14    }
15}
16
17/// Where a COBOL class definition is found: among the programs already read, then in the program
18/// libraries, as a member named with the class's simple name or its full name with periods as
19/// underscores, with the path of the file it was read from. None means a Java class. See
20/// [`numeric::assumptions::CLASS_SEARCH`].
21pub(crate) fn find_class(library: &mut crate::unit::Library, external: &str) -> Result<Option<(Program, Option<String>)>, String> {
22    if external == JAVA_LANG_OBJECT {
23        return Ok(None);
24    }
25    if let Some(i) = library.programs.iter().position(|p| defined_class(p).as_deref() == Some(external)) {
26        return Ok(Some((library.programs.remove(i), None)));
27    }
28    let member = |n: &str| !n.is_empty() && n.chars().all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '$');
29    let simple = external.rsplit('.').next().unwrap_or(external).to_owned();
30    let mut names = vec![simple, external.replace('.', "_")];
31    names.dedup();
32    names.retain(|n| member(n));
33    for dir in library.dirs.clone() {
34        for name in &names {
35            for variant in [name.clone(), name.to_ascii_lowercase(), name.to_ascii_uppercase()] {
36                for ext in ["", ".cbl", ".CBL", ".cob", ".COB"] {
37                    let path = dir.join(format!("{variant}{ext}"));
38                    if !path.is_file() {
39                        continue;
40                    }
41                    let text = std::fs::read(&path).map(|b| syntax::copy::decode(&b)).map_err(|e| format!("{}: {e}", path.display()))?;
42                    let mut programs = syntax::parse_all_with(&text, &library.copy.with_program(&path)).map_err(|e| format!("class {external} does not compile: {}", e.place(&path.display().to_string())))?;
43                    if defined_class(&programs[0]).as_deref() == Some(external) {
44                        return Ok(Some((programs.remove(0), Some(path.display().to_string()))));
45                    }
46                }
47            }
48        }
49    }
50    Ok(None)
51}