calcit/
lib.rs

1#[macro_use]
2extern crate lazy_static;
3
4pub mod data;
5
6pub mod builtins;
7pub mod call_stack;
8pub mod cli_args;
9pub mod codegen;
10pub mod primes;
11pub mod program;
12pub mod runner;
13pub mod snapshot;
14pub mod util;
15
16use dirs::home_dir;
17use std::cell::RefCell;
18use std::fs;
19use std::path::Path;
20use std::sync::Arc;
21
22pub use primes::{Calcit, CalcitErr, CalcitItems};
23
24pub fn load_core_snapshot() -> Result<snapshot::Snapshot, String> {
25  // load core libs
26  let bytes = include_bytes!("./cirru/calcit-core.cirru");
27  let core_content = String::from_utf8_lossy(bytes).to_string();
28  let core_data = cirru_edn::parse(&core_content)?;
29  snapshot::load_snapshot_data(&core_data, "calcit-internal://calcit-core.cirru")
30}
31
32#[derive(Clone, Debug)]
33pub struct ProgramEntries {
34  pub init_fn: Arc<str>,
35  pub init_ns: Arc<str>,
36  pub init_def: Arc<str>,
37  pub reload_fn: Arc<str>,
38  pub reload_ns: Arc<str>,
39  pub reload_def: Arc<str>,
40}
41
42pub fn run_program(init_ns: Arc<str>, init_def: Arc<str>, params: CalcitItems) -> Result<Calcit, CalcitErr> {
43  let check_warnings: RefCell<Vec<String>> = RefCell::new(vec![]);
44
45  // preprocess to init
46  match runner::preprocess::preprocess_ns_def(
47    init_ns.to_owned(),
48    init_def.to_owned(),
49    init_def.to_owned(),
50    None,
51    &check_warnings,
52    &rpds::List::new_sync(),
53  ) {
54    Ok(_) => (),
55    Err(failure) => {
56      eprintln!("\nfailed preprocessing, {}", failure);
57      call_stack::display_stack(&failure.msg, &failure.stack)?;
58      return CalcitErr::err_str(failure.msg);
59    }
60  }
61
62  let warnings = check_warnings.into_inner();
63  if !warnings.is_empty() {
64    return Err(CalcitErr {
65      msg: format!("Found {} warnings, runner blocked", warnings.len()),
66      warnings,
67      stack: rpds::List::new_sync(),
68    });
69  }
70  match program::lookup_evaled_def(&init_ns, &init_def) {
71    None => CalcitErr::err_str(format!("entry not initialized: {}/{}", init_ns, init_def)),
72    Some(entry) => match entry {
73      Calcit::Fn {
74        def_ns, scope, args, body, ..
75      } => {
76        let result = runner::run_fn(&params, &scope, &args, &body, def_ns, &rpds::List::new_sync());
77        match result {
78          Ok(v) => Ok(v),
79          Err(failure) => {
80            eprintln!("\nfailed, {}", failure);
81            call_stack::display_stack(&failure.msg, &failure.stack)?;
82            Err(failure)
83          }
84        }
85      }
86      _ => CalcitErr::err_str(format!("expected function entry, got: {}", entry)),
87    },
88  }
89}
90
91pub fn load_module(path: &str, base_dir: &Path) -> Result<snapshot::Snapshot, String> {
92  let mut file_path = String::from(path);
93  if file_path.ends_with('/') {
94    file_path.push_str("compact.cirru");
95  }
96
97  let fullpath: String = if file_path.starts_with("./") {
98    let new_path = base_dir.join(file_path);
99    new_path.to_str().unwrap().to_string()
100  } else if file_path.starts_with('/') {
101    file_path
102  } else {
103    match home_dir() {
104      Some(buf) => {
105        let home = buf.as_path();
106        let p = home.join(".config/calcit/modules/").join(file_path);
107        p.to_str().unwrap().to_string()
108      }
109      None => return Err(String::from("failed to load $HOME")),
110    }
111  };
112
113  println!("loading module: {}", fullpath);
114
115  let content = fs::read_to_string(&fullpath).unwrap_or_else(|_| panic!("expected Cirru snapshot {:?}", fullpath));
116  let data = cirru_edn::parse(&content)?;
117  // println!("reading: {}", content);
118  let snapshot = snapshot::load_snapshot_data(&data, &fullpath)?;
119  Ok(snapshot)
120}