ocypode_lang/diagnostics/
mod.rs1pub mod parser;
2pub mod runtime;
3use crate::errors::{Error, ErrorKind};
4use miette::{GraphicalReportHandler, JSONReportHandler};
5use std::{env, fmt::Display};
6
7#[derive(Debug)]
9pub struct Diagnostic<T> {
10 pub diagnostic: Box<dyn miette::Diagnostic>,
11 pub handler: T,
12}
13
14impl<T: Default> Diagnostic<T> {
15 pub fn new(diagnostic: Box<dyn miette::Diagnostic>) -> Self {
17 Self {
18 diagnostic,
19 handler: T::default(),
20 }
21 }
22
23 pub fn rgb(self) -> Diagnostic<GraphicalReportHandler> {
25 Diagnostic {
26 diagnostic: self.diagnostic,
27 handler: GraphicalReportHandler::default()
28 .with_context_lines(3)
29 .with_theme(miette::GraphicalTheme {
30 characters: miette::ThemeCharacters::emoji(),
31 styles: matches!(env::var("NO_COLOR").as_deref(), Ok("1") | Ok("true"))
32 .then(miette::ThemeStyles::none)
33 .unwrap_or_else(miette::ThemeStyles::rgb),
34 }),
35 }
36 }
37}
38
39impl Diagnostic<GraphicalReportHandler> {
40 pub fn as_ascii(mut self) -> Self {
42 self.handler = self.handler.with_theme(miette::GraphicalTheme {
43 characters: miette::ThemeCharacters::ascii(),
44 styles: miette::ThemeStyles::ansi(),
45 });
46 self
47 }
48
49 pub fn with_context_lines(mut self, lines: usize) -> Self {
51 self.handler = self.handler.with_context_lines(lines);
52 self
53 }
54}
55
56impl Display for Diagnostic<GraphicalReportHandler> {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 self.handler.render_report(f, self.diagnostic.as_ref())
59 }
60}
61
62impl Display for Diagnostic<JSONReportHandler> {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 self.handler.render_report(f, self.diagnostic.as_ref())
65 }
66}
67
68pub fn as_diagnostic<T: Default>(err: Error, source: String, source_name: String) -> Diagnostic<T> {
69 match err.kind {
70 ErrorKind::InvalidName(ref name, ref reason, ref valid_name, ref statement_type) => {
71 Diagnostic::new(Box::new(parser::definitions::InvalidName {
72 src: miette::NamedSource::new(source_name, source),
73 name: name.clone(),
74 statement_type: statement_type.clone(),
75 reason: reason.clone(),
76 valid_name: valid_name.clone(),
77 span: err.span,
78 }))
79 }
80 ErrorKind::Parse(message) => Diagnostic::new(Box::new(parser::SyntaxError {
81 src: miette::NamedSource::new(source_name, source),
82 message,
83 span: err.span,
84 })),
85 ErrorKind::InvalidMainFunction(ref reason, ref help) => {
86 Diagnostic::new(Box::new(parser::definitions::InvalidMainFunction {
87 src: miette::NamedSource::new(source_name, source),
88 reason: reason.clone(),
89 help: help.clone(),
90 span: err.span,
91 }))
92 }
93 ErrorKind::UnDeclaredIdent(name) => {
94 Diagnostic::new(Box::new(runtime::idents::UnDeclaredIdent {
95 src: miette::NamedSource::new(source_name, source),
96 name,
97 span: err.span,
98 }))
99 }
100 ErrorKind::AlreadyDeclared(name, old_decl) => {
101 Diagnostic::new(Box::new(runtime::AlreadyDeclared {
102 src: miette::NamedSource::new(source_name, source),
103 name,
104 old_decl: old_decl.into(),
105 new_decl: err.span,
106 }))
107 }
108 ErrorKind::MissingMainFunction => {
109 Diagnostic::new(Box::new(runtime::functions::MissingMain {
110 src: miette::NamedSource::new(source_name, source),
111 }))
112 }
113 ErrorKind::InvalidExitCode(exit_code) => {
114 Diagnostic::new(Box::new(runtime::functions::InvalidExitCode {
115 src: miette::NamedSource::new(source_name, source),
116 code: exit_code,
117 span: err.span,
118 }))
119 }
120 ErrorKind::NotCallable(call_span) => {
121 Diagnostic::new(Box::new(runtime::idents::NotCallable {
122 src: miette::NamedSource::new(source_name, source),
123 call_span: call_span.into(),
124 span: err.span,
125 }))
126 }
127 ErrorKind::UncorrectArguments(args_count, func_span, params, func_name) => {
128 Diagnostic::new(Box::new(runtime::functions::UncorrectArguments {
129 src: miette::NamedSource::new(source_name, source),
130 args_count,
131 params: if !params.is_empty() {
132 format!(
133 "{} arguments, which are `{}`",
134 params.len(),
135 params
136 .into_iter()
137 .map(|p| p.ident.ident)
138 .collect::<Vec<_>>()
139 .join(", ")
140 )
141 } else {
142 "no arguments".to_owned()
143 },
144 func_span: func_span.into(),
145 func_name,
146 span: err.span,
147 }))
148 }
149 ErrorKind::UnexpectedType(expected, actual) => {
150 Diagnostic::new(Box::new(runtime::types::UnexpectedType {
151 src: miette::NamedSource::new(source_name, source),
152 expected,
153 actual,
154 span: err.span,
155 }))
156 }
157 ErrorKind::MultiplePackedParams(func_name) => {
158 Diagnostic::new(Box::new(parser::params::MultiplePackedParams {
159 src: miette::NamedSource::new(source_name, source),
160 func_name,
161 span: err.span,
162 }))
163 }
164 ErrorKind::PackedParamNotLast(param_name) => {
165 Diagnostic::new(Box::new(parser::params::PackedParamNotLast {
166 src: miette::NamedSource::new(source_name, source),
167 param_name,
168 span: err.span,
169 }))
170 }
171 ErrorKind::MultipleParamsWithTheSameName(param_name, func_name) => {
172 Diagnostic::new(Box::new(parser::params::MultipleParamsWithTheSameName {
173 src: miette::NamedSource::new(source_name, source),
174 param_name,
175 func_name,
176 span: err.span,
177 }))
178 }
179 ErrorKind::InvalidUnpackArg(type_name) => {
180 Diagnostic::new(Box::new(runtime::InvalidUnpackedArgument {
181 src: miette::NamedSource::new(source_name, source),
182 type_name,
183 span: err.span,
184 }))
185 }
186 ErrorKind::FormatError(reason, help_message) => {
187 Diagnostic::new(Box::new(runtime::FormatError {
188 src: miette::NamedSource::new(source_name, source),
189 reason,
190 help_message,
191 span: err.span,
192 }))
193 }
194 ErrorKind::Runtime(reason) => Diagnostic::new(Box::new(runtime::RuntimeError {
195 src: miette::NamedSource::new(source_name, source),
196 reason,
197 span: err.span,
198 })),
199 }
200}