surrealdb_core/syn/error/
mod.rs1use crate::syn::token::Span;
2use std::fmt::Display;
3
4mod location;
5mod mac;
6mod render;
7pub use location::Location;
8pub(crate) use mac::{bail, syntax_error};
9pub use render::{RenderedError, Snippet};
10
11#[derive(Debug, Clone, Copy)]
12pub enum MessageKind {
13 Suggestion,
14 Error,
15}
16
17#[derive(Debug)]
18enum DiagnosticKind {
19 Cause(String),
20 Span {
21 kind: MessageKind,
22 span: Span,
23 label: Option<String>,
24 },
25}
26
27#[derive(Debug)]
28pub struct Diagnostic {
29 kind: DiagnosticKind,
30 next: Option<Box<Diagnostic>>,
31}
32
33#[derive(Debug)]
35pub struct SyntaxError {
36 diagnostic: Box<Diagnostic>,
37 data_pending: bool,
38}
39
40impl SyntaxError {
41 pub fn new<T>(message: T) -> Self
43 where
44 T: Display,
45 {
46 let diagnostic = Diagnostic {
47 kind: DiagnosticKind::Cause(message.to_string()),
48 next: None,
49 };
50
51 Self {
52 diagnostic: Box::new(diagnostic),
53 data_pending: false,
54 }
55 }
56
57 pub fn is_data_pending(&self) -> bool {
59 self.data_pending
60 }
61
62 pub fn with_data_pending(mut self) -> Self {
65 self.data_pending = true;
66 self
67 }
68
69 pub fn with_span(mut self, span: Span, kind: MessageKind) -> Self {
70 self.diagnostic = Box::new(Diagnostic {
71 kind: DiagnosticKind::Span {
72 kind,
73 span,
74 label: None,
75 },
76 next: Some(self.diagnostic),
77 });
78 self
79 }
80
81 pub fn with_labeled_span<T: Display>(
82 mut self,
83 span: Span,
84 kind: MessageKind,
85 label: T,
86 ) -> Self {
87 self.diagnostic = Box::new(Diagnostic {
88 kind: DiagnosticKind::Span {
89 kind,
90 span,
91 label: Some(label.to_string()),
92 },
93 next: Some(self.diagnostic),
94 });
95 self
96 }
97
98 pub fn with_cause<T: Display>(mut self, t: T) -> Self {
99 self.diagnostic = Box::new(Diagnostic {
100 kind: DiagnosticKind::Cause(t.to_string()),
101 next: Some(self.diagnostic),
102 });
103 self
104 }
105
106 pub fn render_on(&self, source: &str) -> RenderedError {
107 let mut res = RenderedError {
108 errors: Vec::new(),
109 snippets: Vec::new(),
110 };
111 Self::render_on_inner(&self.diagnostic, source, &mut res);
112 res
113 }
114
115 pub fn render_on_bytes(&self, source: &[u8]) -> RenderedError {
116 let source = String::from_utf8_lossy(source);
117 self.render_on(&source)
118 }
119
120 fn render_on_inner(diagnostic: &Diagnostic, source: &str, res: &mut RenderedError) {
121 if let Some(ref x) = diagnostic.next {
122 Self::render_on_inner(x, source, res);
123 }
124
125 match diagnostic.kind {
126 DiagnosticKind::Cause(ref x) => res.errors.push(x.clone()),
127 DiagnosticKind::Span {
128 ref span,
129 ref label,
130 ref kind,
131 } => {
132 let locations = Location::range_of_span(source, *span);
133 let snippet = Snippet::from_source_location_range(
134 source,
135 locations,
136 label.as_ref().map(|x| x.as_str()),
137 *kind,
138 );
139 res.snippets.push(snippet)
140 }
141 }
142 }
143}