Skip to main content

crisp_errors/
display.rs

1use crate::result::{CrispErrorEnum, ErrorResult, ErrorSig};
2use crisp_typeck::{InferredSig, format_ty};
3
4pub fn format_error_sig(sig: &ErrorSig, typed: Option<&InferredSig>) -> String {
5    let ret = typed
6        .map(|t| format_ty(&t.ret))
7        .unwrap_or_else(|| "()".into());
8    if !sig.fallible {
9        if let Some(ts) = typed {
10            let params = ts
11                .params
12                .iter()
13                .map(|(n, t)| format!("{n}: {}", format_ty(t)))
14                .collect::<Vec<_>>()
15                .join(", ");
16            return format!("{}({params}) -> {ret}", sig.name);
17        }
18        return format!("{}() -> {ret}", sig.name);
19    }
20
21    let params = typed
22        .map(|t| {
23            t.params
24                .iter()
25                .map(|(n, ty)| format!("{n}: {}", format_ty(ty)))
26                .collect::<Vec<_>>()
27                .join(", ")
28        })
29        .unwrap_or_default();
30
31    let err_set = sig.errors.iter().cloned().collect::<Vec<_>>().join(" | ");
32
33    if params.is_empty() {
34        format!("{}() -> {ret} ! {err_set}", sig.name)
35    } else {
36        format!("{}({params}) -> {ret} ! {err_set}", sig.name)
37    }
38}
39
40pub fn format_crisp_error_enum(en: &CrispErrorEnum) -> String {
41    if en.variants.is_empty() {
42        return "// CrispError: (no fallible functions)".into();
43    }
44    let mut lines = vec![
45        "#[derive(Debug)]".to_string(),
46        "enum CrispError {".to_string(),
47    ];
48    for v in &en.variants {
49        if v.name == "Thrown" {
50            lines.push("    Thrown(String),".into());
51        } else {
52            lines.push(format!("    {}({}),", v.name, v.payload_type));
53        }
54    }
55    lines.push("}".into());
56    lines.join("\n")
57}
58
59pub fn format_errors_crate(result: &ErrorResult, typed: &crisp_typeck::TypedCrate) -> String {
60    let mut lines: Vec<String> = result
61        .signatures
62        .values()
63        .map(|sig| {
64            let key = format!("{}::{}", sig.module, sig.name);
65            format_error_sig(sig, typed.signatures.get(&key))
66        })
67        .collect();
68    lines.sort();
69    let mut out = lines.join("\n");
70    if !result.crisp_error.variants.is_empty() {
71        out.push_str("\n\n");
72        out.push_str(&format_crisp_error_enum(&result.crisp_error));
73    }
74    out
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80    use crate::ErrorPass;
81    use crisp_typeck::TypeChecker;
82    use std::path::PathBuf;
83
84    #[test]
85    fn format_fallible_read_config() {
86        let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/fallible");
87        let typed = TypeChecker::check_crate(&root).unwrap();
88        let errors = ErrorPass::analyze_crate(&root).unwrap();
89        let out = format_errors_crate(&errors, &typed);
90        assert!(out.contains("read_config"));
91        assert!(out.contains("IoError"));
92        assert!(out.contains("enum CrispError"));
93    }
94}