Skip to content

Commit 04d6d80

Browse files
Enhance error printing and query source span availability (#391)
## Usage and product changes We improve the error messages to show a `^` column indicator along with `-->` line indicator: ``` define attribute name value string; --> entity person owns name @range(0..10); ^ ``` We also expose more information about where in the original query spans which sourced various internal data structures. ## Implementation * Improve error message printing * Include further information about `Span`s throughout TypeQL data structures
1 parent b4310fa commit 04d6d80

37 files changed

+684
-146
lines changed

rust/annotation.rs

Lines changed: 96 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use std::fmt::{self, Write};
88

99
use crate::{
10-
common::{identifier::Identifier, token, Span},
10+
common::{identifier::Identifier, token, Span, Spanned},
1111
util::write_joined,
1212
value::{IntegerLiteral, Literal, StringLiteral},
1313
};
@@ -27,6 +27,24 @@ pub enum Annotation {
2727
Values(Values),
2828
}
2929

30+
impl Spanned for Annotation {
31+
fn span(&self) -> Option<Span> {
32+
match self {
33+
Annotation::Abstract(annotation) => annotation.span(),
34+
Annotation::Cardinality(annotation) => annotation.span(),
35+
Annotation::Cascade(annotation) => annotation.span(),
36+
Annotation::Distinct(annotation) => annotation.span(),
37+
Annotation::Independent(annotation) => annotation.span(),
38+
Annotation::Key(annotation) => annotation.span(),
39+
Annotation::Range(annotation) => annotation.span(),
40+
Annotation::Regex(annotation) => annotation.span(),
41+
Annotation::Subkey(annotation) => annotation.span(),
42+
Annotation::Unique(annotation) => annotation.span(),
43+
Annotation::Values(annotation) => annotation.span(),
44+
}
45+
}
46+
}
47+
3048
impl fmt::Display for Annotation {
3149
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3250
match self {
@@ -47,7 +65,7 @@ impl fmt::Display for Annotation {
4765

4866
#[derive(Debug, Clone, Eq, PartialEq)]
4967
pub struct Abstract {
50-
span: Option<Span>,
68+
pub span: Option<Span>,
5169
}
5270

5371
impl Abstract {
@@ -56,6 +74,12 @@ impl Abstract {
5674
}
5775
}
5876

77+
impl Spanned for Abstract {
78+
fn span(&self) -> Option<Span> {
79+
self.span
80+
}
81+
}
82+
5983
impl fmt::Display for Abstract {
6084
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6185
write!(f, "@{}", token::Annotation::Abstract)
@@ -64,7 +88,7 @@ impl fmt::Display for Abstract {
6488

6589
#[derive(Debug, Clone, Eq, PartialEq)]
6690
pub struct Cardinality {
67-
span: Option<Span>,
91+
pub span: Option<Span>,
6892
pub range: CardinalityRange,
6993
}
7094

@@ -74,6 +98,12 @@ impl Cardinality {
7498
}
7599
}
76100

101+
impl Spanned for Cardinality {
102+
fn span(&self) -> Option<Span> {
103+
self.span
104+
}
105+
}
106+
77107
impl fmt::Display for Cardinality {
78108
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79109
write!(f, "@{}({})", token::Annotation::Cardinality, self.range)
@@ -98,7 +128,7 @@ impl fmt::Display for CardinalityRange {
98128

99129
#[derive(Debug, Clone, Eq, PartialEq)]
100130
pub struct Cascade {
101-
span: Option<Span>,
131+
pub span: Option<Span>,
102132
}
103133

104134
impl Cascade {
@@ -107,6 +137,12 @@ impl Cascade {
107137
}
108138
}
109139

140+
impl Spanned for Cascade {
141+
fn span(&self) -> Option<Span> {
142+
self.span
143+
}
144+
}
145+
110146
impl fmt::Display for Cascade {
111147
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112148
write!(f, "@{}", token::Annotation::Cascade)
@@ -115,7 +151,7 @@ impl fmt::Display for Cascade {
115151

116152
#[derive(Debug, Clone, Eq, PartialEq)]
117153
pub struct Distinct {
118-
span: Option<Span>,
154+
pub span: Option<Span>,
119155
}
120156

121157
impl Distinct {
@@ -124,6 +160,12 @@ impl Distinct {
124160
}
125161
}
126162

163+
impl Spanned for Distinct {
164+
fn span(&self) -> Option<Span> {
165+
self.span
166+
}
167+
}
168+
127169
impl fmt::Display for Distinct {
128170
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129171
write!(f, "@{}", token::Annotation::Distinct)
@@ -132,7 +174,7 @@ impl fmt::Display for Distinct {
132174

133175
#[derive(Debug, Clone, Eq, PartialEq)]
134176
pub struct Independent {
135-
span: Option<Span>,
177+
pub span: Option<Span>,
136178
}
137179

138180
impl Independent {
@@ -141,6 +183,12 @@ impl Independent {
141183
}
142184
}
143185

186+
impl Spanned for Independent {
187+
fn span(&self) -> Option<Span> {
188+
self.span
189+
}
190+
}
191+
144192
impl fmt::Display for Independent {
145193
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146194
write!(f, "@{}", token::Annotation::Independent)
@@ -149,7 +197,7 @@ impl fmt::Display for Independent {
149197

150198
#[derive(Debug, Clone, Eq, PartialEq)]
151199
pub struct Key {
152-
span: Option<Span>,
200+
pub span: Option<Span>,
153201
}
154202

155203
impl Key {
@@ -158,6 +206,12 @@ impl Key {
158206
}
159207
}
160208

209+
impl Spanned for Key {
210+
fn span(&self) -> Option<Span> {
211+
self.span
212+
}
213+
}
214+
161215
impl fmt::Display for Key {
162216
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163217
write!(f, "@{}", token::Annotation::Key)
@@ -166,7 +220,7 @@ impl fmt::Display for Key {
166220

167221
#[derive(Debug, Clone, Eq, PartialEq)]
168222
pub struct Range {
169-
span: Option<Span>,
223+
pub span: Option<Span>,
170224
pub min: Option<Literal>,
171225
pub max: Option<Literal>,
172226
}
@@ -177,6 +231,12 @@ impl Range {
177231
}
178232
}
179233

234+
impl Spanned for Range {
235+
fn span(&self) -> Option<Span> {
236+
self.span
237+
}
238+
}
239+
180240
impl fmt::Display for Range {
181241
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182242
write!(f, "@{}(", token::Annotation::Range)?;
@@ -194,7 +254,7 @@ impl fmt::Display for Range {
194254

195255
#[derive(Debug, Clone, Eq, PartialEq)]
196256
pub struct Regex {
197-
span: Option<Span>,
257+
pub span: Option<Span>,
198258
pub regex: StringLiteral,
199259
}
200260

@@ -204,6 +264,12 @@ impl Regex {
204264
}
205265
}
206266

267+
impl Spanned for Regex {
268+
fn span(&self) -> Option<Span> {
269+
self.span
270+
}
271+
}
272+
207273
impl fmt::Display for Regex {
208274
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209275
write!(f, "@{}({})", token::Annotation::Regex, self.regex.value)
@@ -212,7 +278,7 @@ impl fmt::Display for Regex {
212278

213279
#[derive(Debug, Clone, Eq, PartialEq)]
214280
pub struct Subkey {
215-
span: Option<Span>,
281+
pub span: Option<Span>,
216282
pub ident: Identifier,
217283
}
218284

@@ -222,6 +288,12 @@ impl Subkey {
222288
}
223289
}
224290

291+
impl Spanned for Subkey {
292+
fn span(&self) -> Option<Span> {
293+
self.span
294+
}
295+
}
296+
225297
impl fmt::Display for Subkey {
226298
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227299
write!(f, "@{}({})", token::Annotation::Subkey, self.ident)
@@ -230,7 +302,7 @@ impl fmt::Display for Subkey {
230302

231303
#[derive(Debug, Clone, Eq, PartialEq)]
232304
pub struct Unique {
233-
span: Option<Span>,
305+
pub span: Option<Span>,
234306
}
235307

236308
impl Unique {
@@ -239,6 +311,12 @@ impl Unique {
239311
}
240312
}
241313

314+
impl Spanned for Unique {
315+
fn span(&self) -> Option<Span> {
316+
self.span
317+
}
318+
}
319+
242320
impl fmt::Display for Unique {
243321
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244322
write!(f, "@{}", token::Annotation::Unique)
@@ -247,7 +325,7 @@ impl fmt::Display for Unique {
247325

248326
#[derive(Debug, Clone, Eq, PartialEq)]
249327
pub struct Values {
250-
span: Option<Span>,
328+
pub span: Option<Span>,
251329
pub values: Vec<Literal>,
252330
}
253331

@@ -257,6 +335,12 @@ impl Values {
257335
}
258336
}
259337

338+
impl Spanned for Values {
339+
fn span(&self) -> Option<Span> {
340+
self.span
341+
}
342+
}
343+
260344
impl fmt::Display for Values {
261345
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
262346
write!(f, "@{}(", token::Annotation::Values)?;

rust/common/error/mod.rs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ use std::{error::Error as StdError, fmt};
99
use itertools::Itertools;
1010
use pest::error::{Error as PestError, LineColLocation};
1111

12-
use crate::{error_messages, util::write_joined, Identifier};
12+
use crate::{common::Spannable, error_messages, util::write_joined, Identifier};
1313

1414
#[macro_use]
1515
mod macros;
1616

17-
const SYNTAX_ERROR_INDENT: usize = 4;
18-
const SYNTAX_ERROR_INDICATOR: &str = "--> ";
17+
pub(crate) const SYNTAX_ANNOTATED_INDENT: usize = 4;
18+
pub(crate) const SYNTAX_ANNOTATED_INDICATOR_LINE: &str = "--> ";
19+
pub(crate) const SYNTAX_ANNOTATED_INDICATOR_COL: &str = "^";
1920

2021
#[derive(Clone, Debug, Eq, PartialEq)]
2122
pub struct Error {
@@ -38,23 +39,16 @@ impl From<Vec<TypeQLError>> for Error {
3839
}
3940

4041
pub(crate) fn syntax_error<T: pest::RuleType>(query: &str, error: PestError<T>) -> TypeQLError {
41-
let (error_line_nr, error_col) = match error.line_col {
42+
let (error_line_nr, error_col_nr) = match error.line_col {
4243
LineColLocation::Pos((line, col)) => (line, col),
4344
LineColLocation::Span((line, col), _) => (line, col),
4445
};
45-
// error_line_nr is 1-indexed, we operate on 0-offset
46+
// error_line_nr and error_col_nr is 1-indexed, we operate on 0-offset
4647
let error_line = error_line_nr - 1;
48+
let error_col = error_col_nr - 1;
4749
let formatted_error = query
48-
.lines()
49-
.enumerate()
50-
.map(|(i, line)| {
51-
if i == error_line {
52-
format!("{SYNTAX_ERROR_INDICATOR}{line}")
53-
} else {
54-
format!("{}{line}", " ".repeat(SYNTAX_ERROR_INDENT))
55-
}
56-
})
57-
.join("\n");
50+
.extract_annotated_line_col(error_line, error_col, usize::MAX, usize::MAX)
51+
.unwrap_or_else(|| String::new());
5852
TypeQLError::SyntaxErrorDetailed { error_line_nr, error_col, formatted_error }
5953
}
6054

@@ -76,7 +70,7 @@ pub fn collect_err(i: impl IntoIterator<Item = Result<(), Error>>) -> Result<(),
7670
error_messages! { TypeQLError
7771
code: "TQL", type: "TypeQL Error",
7872
SyntaxErrorDetailed { error_line_nr: usize, error_col: usize, formatted_error: String } =
79-
3: "There is a syntax error at {error_line_nr}:{error_col}:\n{formatted_error}",
73+
3: "There is a syntax error near {error_line_nr}:{error_col}:\n{formatted_error}",
8074
InvalidCasting { enum_name: &'static str, variant: &'static str, expected_variant: &'static str, typename: &'static str } =
8175
4: "Enum '{enum_name}::{variant}' does not match '{expected_variant}', and cannot be unwrapped into '{typename}'.",
8276
InvalidLiteral { variant: &'static str, expected_variant: &'static str } =

rust/common/identifier.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::{
1616

1717
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
1818
pub struct Identifier {
19-
span: Option<Span>,
19+
pub span: Option<Span>,
2020
ident: String,
2121
}
2222

0 commit comments

Comments
 (0)