pub mod actors;
pub mod error;
pub mod llm;
pub mod oauth;
pub mod oauth_openai;
pub mod runtime;
pub mod setup;
pub mod syntax;
pub mod value;
pub mod verify;
pub use error::Error;
pub use runtime::{Reactor, ReactorHandle};
pub use value::Value;
pub use verify::VerifiedProgram;
use std::path::{Path, PathBuf};
pub fn load<P: AsRef<Path>>(path: P) -> Result<VerifiedProgram, Error> {
let mut program = syntax::parse_file(path)?;
merge_auto_loaded(&mut program)?;
verify::run_passes(program)
}
pub fn load_str(source: &str) -> Result<VerifiedProgram, Error> {
let program = syntax::parse_str(source)?;
verify::run_passes(program)
}
pub fn auto_load_dir() -> Option<PathBuf> {
if let Some(d) = std::env::var_os("XDG_CONFIG_HOME") {
return Some(PathBuf::from(d).join("thal").join("auto"));
}
if let Some(home) = std::env::var_os("HOME") {
return Some(PathBuf::from(home).join(".config").join("thal").join("auto"));
}
None
}
fn merge_auto_loaded(program: &mut syntax::Program) -> Result<(), Error> {
let dir = match auto_load_dir() {
Some(d) => d,
None => return Ok(()),
};
if !dir.exists() {
return Ok(());
}
let entries = std::fs::read_dir(&dir).map_err(Error::Io)?;
let mut paths: Vec<PathBuf> = Vec::new();
for entry in entries.flatten() {
let p = entry.path();
if p.extension().and_then(|s| s.to_str()) == Some("thal") {
paths.push(p);
}
}
paths.sort();
for p in paths {
let extra = syntax::parse_file(&p)
.map_err(|e| Error::Parse(format!("auto-load {}: {e}", p.display())))?;
program.types.extend(extra.types);
program.mixins.extend(extra.mixins);
program.molecules.extend(extra.molecules);
program.reactions.extend(extra.reactions);
}
Ok(())
}