use crate::data::cirru;
use crate::data::edn;
use crate::primes::{Calcit, CalcitItems};
use cirru_edn::Edn;
use std::collections::HashMap;
use std::fmt;
use std::fs;
use std::hash::Hash;
use std::sync::Arc;
#[derive(Debug, PartialEq, Clone, Eq, Ord, PartialOrd, Hash)]
pub struct CalcitStack {
pub ns: Arc<str>,
pub def: Arc<str>,
pub code: Calcit, pub args: Box<CalcitItems>,
pub kind: StackKind,
}
#[derive(Debug, PartialEq, Clone, Eq, Ord, PartialOrd, Hash)]
pub enum StackKind {
Fn,
Proc,
Macro,
Syntax, Codegen, }
impl fmt::Display for CalcitStack {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "TODO")
}
}
pub type CallStackList = rpds::ListSync<CalcitStack>;
pub fn extend_call_stack(
stack: &CallStackList,
ns: Arc<str>,
def: Arc<str>,
kind: StackKind,
code: Calcit,
args: &CalcitItems,
) -> CallStackList {
stack.push_front(CalcitStack {
ns,
def,
code,
args: Box::new(args.to_owned()),
kind,
})
}
pub fn show_stack(stack: &CallStackList) {
println!("\ncall stack:");
for s in stack {
let is_macro = s.kind == StackKind::Macro;
println!(" {}/{}{}", s.ns, s.def, if is_macro { "\t ~macro" } else { "" });
}
}
pub fn display_stack(failure: &str, stack: &CallStackList) -> Result<(), String> {
eprintln!("\nFailure: {}", failure);
eprintln!("\ncall stack:");
for s in stack {
let is_macro = s.kind == StackKind::Macro;
eprintln!(" {}/{}{}", s.ns, s.def, if is_macro { "\t ~macro" } else { "" });
}
let mut stack_list: Vec<Edn> = Vec::with_capacity(stack.len());
for s in stack {
let mut info: HashMap<Edn, Edn> = HashMap::with_capacity(4);
info.insert(Edn::kwd("def"), Edn::str(format!("{}/{}", s.ns, s.def)));
info.insert(Edn::kwd("code"), Edn::Quote(cirru::calcit_to_cirru(&s.code)?));
let mut args: Vec<Edn> = Vec::with_capacity(s.args.len());
for a in &*s.args {
args.push(edn::calcit_to_edn(a)?);
}
info.insert(Edn::kwd("args"), Edn::List(args));
info.insert(Edn::kwd("kind"), Edn::kwd(&name_kind(&s.kind)));
stack_list.push(Edn::Map(info))
}
let mut data: HashMap<Edn, Edn> = HashMap::with_capacity(2);
data.insert(Edn::kwd("message"), Edn::str(failure));
data.insert(Edn::kwd("stack"), Edn::List(stack_list));
let content = cirru_edn::format(&Edn::Map(data), true)?;
let _ = fs::write(ERROR_SNAPSHOT, content);
eprintln!("\nrun `cat {}` to read stack details.", ERROR_SNAPSHOT);
Ok(())
}
const ERROR_SNAPSHOT: &str = ".calcit-error.cirru";
fn name_kind(k: &StackKind) -> String {
match k {
StackKind::Fn => String::from("fn"),
StackKind::Proc => String::from("proc"),
StackKind::Macro => String::from("macro"),
StackKind::Syntax => String::from("syntax"),
StackKind::Codegen => String::from("codegen"),
}
}