pub use compile::oo::*;
pub use compile::oo::{ClassCode, MethodCode, Part};
pub use rt::oo::*;
use syntax::ast::Program;
pub(crate) fn refuse_to_run(program: &Program) -> Result<(), crate::Abend> {
match program.oo.as_ref().and_then(|o| o.class()) {
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 }),
None => Ok(()),
}
}
pub(crate) fn find_class(library: &mut crate::unit::Library, external: &str) -> Result<Option<(Program, Option<String>)>, String> {
if external == JAVA_LANG_OBJECT {
return Ok(None);
}
if let Some(i) = library.programs.iter().position(|p| defined_class(p).as_deref() == Some(external)) {
return Ok(Some((library.programs.remove(i), None)));
}
let member = |n: &str| !n.is_empty() && n.chars().all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '$');
let simple = external.rsplit('.').next().unwrap_or(external).to_owned();
let mut names = vec![simple, external.replace('.', "_")];
names.dedup();
names.retain(|n| member(n));
for dir in library.dirs.clone() {
for name in &names {
for variant in [name.clone(), name.to_ascii_lowercase(), name.to_ascii_uppercase()] {
for ext in ["", ".cbl", ".CBL", ".cob", ".COB"] {
let path = dir.join(format!("{variant}{ext}"));
if !path.is_file() {
continue;
}
let text = std::fs::read(&path).map(|b| syntax::copy::decode(&b)).map_err(|e| format!("{}: {e}", path.display()))?;
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())))?;
if defined_class(&programs[0]).as_deref() == Some(external) {
return Ok(Some((programs.remove(0), Some(path.display().to_string()))));
}
}
}
}
}
Ok(None)
}