1use super::logger::{LogLevel, Logger};
2use crate::core::{
3 error::{ErrorResult, Severity, StackFrame},
4 parser::statement::{Statement, StatementKind},
5 shared::value::Value,
6};
7use std::collections::HashMap;
8
9pub fn collect_errors_recursively(statements: &[Statement]) -> Vec<ErrorResult> {
16 let mut errors: Vec<ErrorResult> = Vec::new();
17
18 for stmt in statements {
19 match &stmt.kind {
20 StatementKind::Unknown => {
21 errors.push(ErrorResult {
22 message: format!("Unknown statement at line {}:{}", stmt.line, stmt.column),
23 line: stmt.line,
24 column: stmt.column,
25 severity: Severity::Warning,
26 stack: vec![StackFrame {
27 module: None,
28 context: Some("Unknown".to_string()),
29 line: stmt.line,
30 column: stmt.column,
31 }],
32 });
33 }
34 StatementKind::Error { message } => {
35 errors.push(ErrorResult {
36 message: message.clone(),
37 line: stmt.line,
38 column: stmt.column,
39 severity: Severity::Critical,
40 stack: vec![StackFrame {
41 module: None,
42 context: Some("Error".to_string()),
43 line: stmt.line,
44 column: stmt.column,
45 }],
46 });
47 }
48 StatementKind::Loop => {
49 if let Some(body_statements) = extract_loop_body_statements(&stmt.value) {
50 let nested = collect_errors_recursively(body_statements);
51 errors.extend(nested.into_iter().map(|mut e| {
52 e.stack.insert(
54 0,
55 StackFrame {
56 module: None,
57 context: Some("loop".to_string()),
58 line: stmt.line,
59 column: stmt.column,
60 },
61 );
62 e
63 }));
64 }
65 }
66 _ => {}
67 }
68 }
69
70 errors
71}
72
73fn extract_loop_body_statements(value: &Value) -> Option<&[Statement]> {
74 if let Value::Map(map) = value {
75 if let Some(Value::Block(statements)) = map.get("body") {
76 return Some(statements);
77 }
78 }
79 None
80}
81
82pub fn partition_errors(errors: Vec<ErrorResult>) -> (Vec<ErrorResult>, Vec<ErrorResult>) {
83 let mut warnings = Vec::new();
84 let mut criticals = Vec::new();
85 for e in errors {
86 match e.severity {
87 Severity::Warning => warnings.push(e),
88 Severity::Critical => criticals.push(e),
89 }
90 }
91 (warnings, criticals)
92}
93
94pub fn log_errors_with_stack(prefix: &str, warnings: &[ErrorResult], criticals: &[ErrorResult]) {
95 let logger = Logger::new();
96 if !warnings.is_empty() {
97 logger.log_message(
98 LogLevel::Warning,
99 &format!("{}: {} warning(s)", prefix, warnings.len()),
100 );
101 for w in warnings {
102 logger.log_message(LogLevel::Warning, &format!("- {}", w.message));
103 if let Some(frame) = w.stack.first() {
105 let module = frame.module.clone().unwrap_or_default();
106 logger.log_message(
107 LogLevel::Debug,
108 &format!(
109 " ↳ {}:{}:{} {}",
110 module,
111 frame.line,
112 frame.column,
113 frame.context.clone().unwrap_or_default()
114 ),
115 );
116 }
117 if w.stack.len() > 1 {
119 for (i, f) in w.stack.iter().enumerate().skip(1) {
120 let module = f.module.clone().unwrap_or_default();
121 logger.log_message(
122 LogLevel::Debug,
123 &format!(
124 " #{} {}:{}:{} {}",
125 i,
126 module,
127 f.line,
128 f.column,
129 f.context.clone().unwrap_or_default()
130 ),
131 );
132 }
133 }
134 }
135 }
136 if !criticals.is_empty() {
137 logger.log_message(
138 LogLevel::Error,
139 &format!("{}: {} critical error(s)", prefix, criticals.len()),
140 );
141 for c in criticals {
142 logger.log_message(LogLevel::Error, &format!("- {}", c.message));
143 if let Some(frame) = c.stack.first() {
144 let module = frame.module.clone().unwrap_or_default();
145 logger.log_message(
146 LogLevel::Error,
147 &format!(
148 " ↳ {}:{}:{} {}",
149 module,
150 frame.line,
151 frame.column,
152 frame.context.clone().unwrap_or_default()
153 ),
154 );
155 }
156 if c.stack.len() > 1 {
157 for (i, f) in c.stack.iter().enumerate().skip(1) {
158 let module = f.module.clone().unwrap_or_default();
159 logger.log_message(
160 LogLevel::Error,
161 &format!(
162 " #{} {}:{}:{} {}",
163 i,
164 module,
165 f.line,
166 f.column,
167 f.context.clone().unwrap_or_default()
168 ),
169 );
170 }
171 }
172 }
173 }
174}
175
176pub fn collect_all_errors_with_modules(
177 modules: &HashMap<String, Vec<Statement>>,
178) -> Vec<ErrorResult> {
179 let mut all = Vec::new();
180 for (module_path, stmts) in modules {
181 let mut errs = collect_errors_recursively(stmts);
182 for e in errs.iter_mut() {
183 if e.stack.is_empty() {
185 e.stack.push(StackFrame {
186 module: Some(module_path.clone()),
187 context: None,
188 line: e.line,
189 column: e.column,
190 });
191 } else {
192 if e.stack[0].module.is_none() {
193 e.stack[0].module = Some(module_path.clone());
194 }
195 }
196 }
197 all.extend(errs);
198 }
199 all
200}