1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate nanoid;

mod data;

pub mod builtins;
pub mod call_stack;
pub mod cli_args;
pub mod codegen;
pub mod primes;
pub mod program;
pub mod runner;
pub mod snapshot;
pub mod util;

use dirs::home_dir;
use std::fs;
use std::path::Path;
use std::time::Instant;

pub use primes::Calcit;

pub fn load_core_snapshot() -> Result<snapshot::Snapshot, String> {
  // load core libs
  let bytes = include_bytes!("./cirru/calcit-core.cirru");
  let core_content = String::from_utf8_lossy(bytes).to_string();
  let core_data = cirru_edn::parse(&core_content)?;
  snapshot::load_snapshot_data(core_data)
}

pub fn run_program(init_fn: &str, program_code: &program::ProgramCodeData) -> Result<(), String> {
  let started_time = Instant::now();

  let (init_ns, init_def) = util::string::extract_ns_def(init_fn)?;
  // preprocess to init
  match runner::preprocess::preprocess_ns_def(&init_ns, &init_def, &program_code, &init_def) {
    Ok(_) => (),
    Err(failure) => {
      println!("\nfailed preprocessing, {}", failure);
      call_stack::display_stack(&failure)?;
      return Err(failure);
    }
  }

  match program::lookup_evaled_def(&init_ns, &init_def) {
    None => Err(format!("entry not initialized: {}/{}", init_ns, init_def)),
    Some(entry) => match entry {
      Calcit::Fn(_, f_ns, _, def_scope, args, body) => {
        let result = runner::run_fn(&im::vector![], &def_scope, &args, &body, &f_ns, &program_code);
        match result {
          Ok(v) => {
            let duration = Instant::now().duration_since(started_time);
            println!("took {}ms: {}", duration.as_micros() as f64 / 1000.0, v);
            Ok(())
          }
          Err(failure) => {
            println!("\nfailed, {}", failure);
            call_stack::display_stack(&failure)?;
            Err(failure)
          }
        }
      }
      _ => Err(format!("expected function entry, got: {}", entry)),
    },
  }
}

pub fn load_module(path: &str, base_dir: &Path) -> Result<snapshot::Snapshot, String> {
  let mut file_path = String::from(path);
  if file_path.ends_with('/') {
    file_path.push_str("compact.cirru");
  }

  let fullpath: String = if file_path.starts_with("./") {
    let new_path = base_dir.join(file_path);
    new_path.to_str().unwrap().to_string()
  } else if file_path.starts_with('/') {
    file_path
  } else {
    match home_dir() {
      Some(buf) => {
        let home = buf.as_path();
        let p = home.join(".config/calcit/modules/").join(file_path);
        p.to_str().unwrap().to_string()
      }
      None => return Err(String::from("failed to load $HOME")),
    }
  };

  println!("loading module: {}", fullpath);

  let content = fs::read_to_string(&fullpath).expect(&format!("expected Cirru snapshot {:?}", fullpath));
  let data = cirru_edn::parse(&content)?;
  // println!("reading: {}", content);
  let snapshot = snapshot::load_snapshot_data(data)?;
  Ok(snapshot)
}