1pub mod data;
2
3pub mod builtins;
4pub mod calcit;
5pub mod call_stack;
6pub mod call_tree;
7pub mod cli_args;
8pub mod codegen;
9pub mod detailed_snapshot;
10pub mod program;
11pub mod runner;
12pub mod snapshot;
13pub mod util;
14
15use calcit::{CalcitErrKind, LocatedWarning};
16use call_stack::CallStackList;
17use std::cell::RefCell;
18use std::fs;
19use std::path::Path;
20use std::sync::Arc;
21
22pub use calcit::{
23 Calcit, CalcitErr, CalcitFnTypeAnnotation, CalcitProc, CalcitSyntax, CalcitTypeAnnotation, ProcTypeSignature, SyntaxTypeSignature,
24};
25
26use crate::util::string::strip_shebang;
27
28pub fn load_core_snapshot() -> Result<snapshot::Snapshot, String> {
29 let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/calcit-core.rmp"));
31 let mut snapshot = snapshot::decode_binary_snapshot(bytes).map_err(|e| {
32 eprintln!("\n{e}");
33 "Failed to deserialize core snapshot".to_string()
34 })?;
35 let path = "calcit-internal://calcit-core.cirru";
36 let meta_ns = format!("{}.$meta", snapshot.package);
37 snapshot.files.insert(meta_ns.to_owned(), snapshot::gen_meta_ns(&meta_ns, path));
38 Ok(snapshot)
39}
40
41#[derive(Clone, Debug)]
42pub struct ProgramEntries {
43 pub init_fn: Arc<str>,
44 pub init_ns: Arc<str>,
45 pub init_def: Arc<str>,
46 pub reload_fn: Arc<str>,
47 pub reload_ns: Arc<str>,
48 pub reload_def: Arc<str>,
49}
50
51pub fn run_program(init_ns: Arc<str>, init_def: Arc<str>, params: &[Calcit]) -> Result<Calcit, CalcitErr> {
52 run_program_with_docs(init_ns, init_def, params)
53}
54
55pub fn run_program_with_docs(init_ns: Arc<str>, init_def: Arc<str>, params: &[Calcit]) -> Result<Calcit, CalcitErr> {
56 let check_warnings = RefCell::new(LocatedWarning::default_list());
57
58 match runner::preprocess::preprocess_ns_def(&init_ns, &init_def, &check_warnings, &CallStackList::default()) {
60 Ok(_) => (),
61 Err(failure) => {
62 eprintln!("\nfailed preprocessing, {failure}");
63 let headline = failure.headline();
64 call_stack::display_stack_with_docs(&headline, &failure.stack, failure.location.as_ref(), failure.hint.as_deref())?;
65 return CalcitErr::err_str(failure.kind, headline);
66 }
67 }
68
69 let warnings = check_warnings.borrow();
70 if !warnings.is_empty() {
71 return Err(CalcitErr {
72 kind: CalcitErrKind::Unexpected,
73 msg: format!("Found {} warnings, runner blocked", warnings.len()),
74 code: None,
75 warnings: Box::new(warnings.to_owned()),
76 stack: CallStackList::default(),
77 location: None,
78 hint: None,
79 });
80 }
81 match program::lookup_evaled_def(&init_ns, &init_def) {
82 None => CalcitErr::err_str(CalcitErrKind::Var, format!("entry not initialized: {init_ns}/{init_def}")),
83 Some(entry) => match entry {
84 Calcit::Fn { info, .. } => {
85 let result = runner::run_fn(params, &info, &CallStackList::default());
86 match result {
87 Ok(v) => Ok(v),
88 Err(failure) => {
89 call_stack::display_stack_with_docs(&failure.msg, &failure.stack, failure.location.as_ref(), failure.hint.as_deref())?;
90 Err(failure)
91 }
92 }
93 }
94 _ => CalcitErr::err_str(CalcitErrKind::Type, format!("expected function entry, got: {entry}")),
95 },
96 }
97}
98
99pub fn load_module(path: &str, base_dir: &Path, module_folder: &Path) -> Result<snapshot::Snapshot, String> {
100 let mut file_path = String::from(path);
101 if file_path.ends_with('/') {
102 file_path.push_str("compact.cirru");
103 }
104
105 let fullpath = if file_path.starts_with("./") {
106 base_dir.join(&file_path).as_path().to_owned()
107 } else if file_path.starts_with('/') {
108 Path::new(&file_path).to_owned()
109 } else {
110 module_folder.join(&file_path).as_path().to_owned()
111 };
112
113 let display_path = if file_path.starts_with("./") {
114 file_path.clone()
115 } else if file_path.starts_with('/') {
116 if let Ok(stripped) = Path::new(&file_path).strip_prefix(module_folder) {
117 format!("<mods>/{}", stripped.display())
118 } else {
119 file_path.clone()
120 }
121 } else {
122 format!("<mods>/{file_path}")
123 };
124
125 println!("loading: {display_path}");
126
127 let mut content = fs::read_to_string(&fullpath).unwrap_or_else(|_| panic!("expected Cirru snapshot {fullpath:?}"));
128 strip_shebang(&mut content);
129 let data = cirru_edn::parse(&content).map_err(|e| {
130 eprintln!("\nFailed to parse file '{}':", fullpath.display());
131 eprintln!("{e}");
132 format!("Failed to parse file '{}'", fullpath.display())
133 })?;
134 let snapshot = snapshot::load_snapshot_data(&data, &fullpath.display().to_string())?;
136 Ok(snapshot)
137}