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}