1
- use std:: { error:: Error , fmt:: Display , path:: Path , str :: FromStr } ;
1
+ use std:: { cell :: OnceCell , error:: Error , fmt:: Display , path:: Path } ;
2
2
3
3
use cfgrammar:: {
4
4
newlinecache:: NewlineCache ,
@@ -16,7 +16,7 @@ use unicode_width::UnicodeWidthStr;
16
16
pub struct SpannedDiagnosticFormatter < ' a > {
17
17
src : & ' a str ,
18
18
path : & ' a Path ,
19
- nlc : NewlineCache ,
19
+ nlc : OnceCell < NewlineCache > ,
20
20
}
21
21
22
22
fn pidx_prods_data < StorageT > ( ast : & GrammarAST , pidx : PIdx < StorageT > ) -> ( Vec < String > , Vec < Span > )
@@ -36,11 +36,19 @@ where
36
36
37
37
impl < ' a > SpannedDiagnosticFormatter < ' a > {
38
38
#[ allow( clippy:: result_unit_err) ]
39
- pub fn new ( src : & ' a str , path : & ' a Path ) -> Result < Self , ( ) > {
40
- Ok ( Self {
39
+ pub fn new ( src : & ' a str , path : & ' a Path ) -> Self {
40
+ Self {
41
41
src,
42
42
path,
43
- nlc : NewlineCache :: from_str ( src) ?,
43
+ nlc : OnceCell :: new ( ) ,
44
+ }
45
+ }
46
+
47
+ pub fn nlc ( & self ) -> & NewlineCache {
48
+ self . nlc . get_or_init ( || {
49
+ let mut nlc = NewlineCache :: new ( ) ;
50
+ nlc. feed ( self . src ) ;
51
+ nlc
44
52
} )
45
53
}
46
54
@@ -60,7 +68,7 @@ impl<'a> SpannedDiagnosticFormatter<'a> {
60
68
pub fn file_location_msg ( & self , msg : & str , span : Option < Span > ) -> String {
61
69
if let Some ( span) = span {
62
70
let ( line, col) = self
63
- . nlc
71
+ . nlc ( )
64
72
. byte_to_line_num_and_col_num ( self . src , span. start ( ) )
65
73
. unwrap_or ( ( 0 , 0 ) ) ;
66
74
format ! ( "{} at {}:{line}:{col}" , msg, self . path. display( ) )
@@ -85,11 +93,11 @@ impl<'a> SpannedDiagnosticFormatter<'a> {
85
93
underline_c : char ,
86
94
) -> String {
87
95
let mut out = String :: new ( ) ;
88
- let ( start_byte, end_byte) = self . nlc . span_line_bytes ( span) ;
96
+ let ( start_byte, end_byte) = self . nlc ( ) . span_line_bytes ( span) ;
89
97
// Produce an underline underneath a span which may cover multiple lines, and a message on the last line.
90
98
let mut source_lines = self . src [ start_byte..end_byte] . lines ( ) . peekable ( ) ;
91
99
while let Some ( source_line) = source_lines. next ( ) {
92
- let ( line_start_byte, _) = self . nlc . span_line_bytes ( span) ;
100
+ let ( line_start_byte, _) = self . nlc ( ) . span_line_bytes ( span) ;
93
101
let span_offset_from_start = span. start ( ) - line_start_byte;
94
102
95
103
// An underline bounded by the current line.
@@ -99,7 +107,7 @@ impl<'a> SpannedDiagnosticFormatter<'a> {
99
107
. min ( span. start ( ) + ( source_line. len ( ) - span_offset_from_start) ) ,
100
108
) ;
101
109
let ( line_num, _) = self
102
- . nlc
110
+ . nlc ( )
103
111
. byte_to_line_num_and_col_num ( self . src , span. start ( ) )
104
112
. expect ( "Span must correlate to a line in source" ) ;
105
113
// Print the line_num/source text for the line.
@@ -137,13 +145,13 @@ impl<'a> SpannedDiagnosticFormatter<'a> {
137
145
let mut spans = e. spans ( ) . iter ( ) . enumerate ( ) . peekable ( ) ;
138
146
while let Some ( ( span_num, span) ) = spans. next ( ) {
139
147
let ( line, _) = self
140
- . nlc
148
+ . nlc ( )
141
149
. byte_to_line_num_and_col_num ( self . src , span. start ( ) )
142
150
. unwrap_or ( ( 0 , 0 ) ) ;
143
151
let next_line = spans
144
152
. peek ( )
145
153
. map ( |( _, span) | span)
146
- . map ( |s| self . nlc . byte_to_line_num ( s. start ( ) ) . unwrap_or ( line) )
154
+ . map ( |s| self . nlc ( ) . byte_to_line_num ( s. start ( ) ) . unwrap_or ( line) )
147
155
. unwrap_or ( line) ;
148
156
// Is this line contiguous with the next, if not prefix it with dots.
149
157
let dots = if next_line - line > 1 { "..." } else { "" } ;
@@ -180,7 +188,7 @@ impl<'a> SpannedDiagnosticFormatter<'a> {
180
188
) -> String {
181
189
let mut lines = spans
182
190
. clone ( )
183
- . map ( |span| self . nlc . span_line_bytes ( span) )
191
+ . map ( |span| self . nlc ( ) . span_line_bytes ( span) )
184
192
. collect :: < Vec < _ > > ( ) ;
185
193
lines. dedup ( ) ;
186
194
assert ! ( lines. len( ) == 1 ) ;
@@ -192,10 +200,10 @@ impl<'a> SpannedDiagnosticFormatter<'a> {
192
200
// ____ ___
193
201
// indent indent
194
202
let ( line_at_start, _) = self
195
- . nlc
203
+ . nlc ( )
196
204
. byte_to_line_num_and_col_num ( self . src , first_span. start ( ) )
197
205
. expect ( "Span should correlate to a line in source" ) ;
198
- let ( line_start_byte, end_byte) = self . nlc . span_line_bytes ( * first_span) ;
206
+ let ( line_start_byte, end_byte) = self . nlc ( ) . span_line_bytes ( * first_span) ;
199
207
// Print the line_num/source text for the line.
200
208
out. push_str ( & format ! (
201
209
"{}| {}\n " ,
@@ -304,15 +312,15 @@ impl<'a> SpannedDiagnosticFormatter<'a> {
304
312
305
313
let mut prod_lines = r_prod_spans
306
314
. iter ( )
307
- . map ( |span| self . nlc . span_line_bytes ( * span) )
315
+ . map ( |span| self . nlc ( ) . span_line_bytes ( * span) )
308
316
. collect :: < Vec < _ > > ( ) ;
309
317
prod_lines. sort ( ) ;
310
318
prod_lines. dedup ( ) ;
311
319
312
320
for lines in & prod_lines {
313
321
let mut spans_on_line = Vec :: new ( ) ;
314
322
for span in & r_prod_spans {
315
- if lines == & self . nlc . span_line_bytes ( * span) {
323
+ if lines == & self . nlc ( ) . span_line_bytes ( * span) {
316
324
spans_on_line. push ( * span)
317
325
}
318
326
}
@@ -375,7 +383,7 @@ mod test {
375
383
fn underline_multiline_span_test ( ) {
376
384
let s = "\n aaaaaabbb\n bbb\n bbbb\n " ;
377
385
let test_path = PathBuf :: from ( "test" ) ;
378
- let formatter = SpannedDiagnosticFormatter :: new ( s, & test_path) . unwrap ( ) ;
386
+ let formatter = SpannedDiagnosticFormatter :: new ( s, & test_path) ;
379
387
380
388
let span = Span :: new ( 7 , 7 + 12 ) ;
381
389
let out = format ! (
@@ -413,7 +421,7 @@ mod test {
413
421
fn underline_single_line_span_test ( ) {
414
422
let s = "\n aaaaaabbb bbb bbbb\n " ;
415
423
let test_path = PathBuf :: from ( "test" ) ;
416
- let formatter = SpannedDiagnosticFormatter :: new ( s, & test_path) . unwrap ( ) ;
424
+ let formatter = SpannedDiagnosticFormatter :: new ( s, & test_path) ;
417
425
418
426
let span = Span :: new ( 7 , 7 + 12 ) ;
419
427
let out = format ! (
@@ -442,7 +450,7 @@ mod test {
442
450
fn span_prefix ( ) {
443
451
let s = "\n aaaaaabbb\n bbb\n bbbb\n " ;
444
452
let test_path = PathBuf :: from ( "test" ) ;
445
- let formatter = SpannedDiagnosticFormatter :: new ( s, & test_path) . unwrap ( ) ;
453
+ let formatter = SpannedDiagnosticFormatter :: new ( s, & test_path) ;
446
454
// For raw string alignment.
447
455
let mut out = String :: from ( "\n " ) ;
448
456
// On occasion we want dots to signal that the lines are not contiguous.
@@ -473,7 +481,7 @@ mod test {
473
481
fn span_prefix_2 ( ) {
474
482
let s = "\n \n \n \n \n \n \n \n \n \n \n aaaaaabbb\n bbb\n bbbb\n " ;
475
483
let test_path = PathBuf :: from ( "test" ) ;
476
- let formatter = SpannedDiagnosticFormatter :: new ( s, & test_path) . unwrap ( ) ;
484
+ let formatter = SpannedDiagnosticFormatter :: new ( s, & test_path) ;
477
485
let mut out = String :: from ( "\n " ) ;
478
486
// On occasion we want dots to signal that the lines are not contiguous.
479
487
out. push_str ( & formatter. prefixed_underline_span_with_text (
@@ -504,7 +512,7 @@ mod test {
504
512
let crabs = " 🦀🦀🦀 " ;
505
513
let crustaceans = format ! ( "\" {crabs}\n {crabs}\" " ) ;
506
514
let test_path = PathBuf :: from ( "test" ) ;
507
- let formatter = SpannedDiagnosticFormatter :: new ( & crustaceans, & test_path) . unwrap ( ) ;
515
+ let formatter = SpannedDiagnosticFormatter :: new ( & crustaceans, & test_path) ;
508
516
// For raw string alignment.
509
517
let mut out = String :: from ( "\n " ) ;
510
518
out. push_str ( & formatter. underline_span_with_text (
@@ -528,7 +536,7 @@ mod test {
528
536
let lobster = "🦞" ;
529
537
let crustaceans = format ! ( "{crab}{lobster}{crab}{crab}{lobster}" ) ;
530
538
let test_path = PathBuf :: from ( "test" ) ;
531
- let formatter = SpannedDiagnosticFormatter :: new ( & crustaceans, & test_path) . unwrap ( ) ;
539
+ let formatter = SpannedDiagnosticFormatter :: new ( & crustaceans, & test_path) ;
532
540
// For raw string alignment.
533
541
let mut out = String :: from ( "\n " ) ;
534
542
out. push_str ( & formatter. prefixed_underline_span_with_text (
@@ -560,7 +568,7 @@ mod test {
560
568
fn underline_single_line_spans_test ( ) {
561
569
let s = "\n aaaaaabbb bbb bbbb\n " ;
562
570
let test_path = PathBuf :: from ( "test" ) ;
563
- let formatter = SpannedDiagnosticFormatter :: new ( s, & test_path) . unwrap ( ) ;
571
+ let formatter = SpannedDiagnosticFormatter :: new ( s, & test_path) ;
564
572
let spans = [ ( 7 , 10 ) , ( 11 , 14 ) , ( 15 , 19 ) ]
565
573
. iter ( )
566
574
. map ( |( i, j) : & ( usize , usize ) | Span :: new ( * i, * j) ) ;
@@ -617,7 +625,7 @@ mod test {
617
625
let lobster = "🦞" ;
618
626
let crustaceans = format ! ( "{crab}{lobster}{crab}{lobster}" ) ;
619
627
let test_path = PathBuf :: from ( "test" ) ;
620
- let formatter = SpannedDiagnosticFormatter :: new ( & crustaceans, & test_path) . unwrap ( ) ;
628
+ let formatter = SpannedDiagnosticFormatter :: new ( & crustaceans, & test_path) ;
621
629
// For raw string alignment.
622
630
let mut out = String :: from ( "\n " ) ;
623
631
let spans = [
0 commit comments