@@ -7,11 +7,11 @@ use std::collections::HashMap;
7
7
use std:: fmt:: Write ;
8
8
9
9
use serde:: { Deserialize , Serialize } ;
10
+ use utils:: count_newlines;
10
11
use wasm_bindgen:: prelude:: * ;
11
12
12
13
use crate :: error:: RenderError ;
13
14
use crate :: error:: Result ;
14
- use crate :: utils:: log;
15
15
16
16
#[ derive( Debug , PartialEq ) ]
17
17
pub enum CommandType {
@@ -39,6 +39,11 @@ pub enum Token<'a> {
39
39
Command ( Command < ' a > ) ,
40
40
}
41
41
42
+ pub struct ParsingData {
43
+ line : usize ,
44
+ ch : usize ,
45
+ }
46
+
42
47
#[ wasm_bindgen]
43
48
#[ derive( Serialize , Deserialize , Debug ) ]
44
49
pub struct ParserConfig {
@@ -115,35 +120,56 @@ impl<'a> Parser<'a> {
115
120
Parser { content, config }
116
121
}
117
122
118
- fn parse_command_tag ( & self , i : & ' a str ) -> Result < ( CommandType , & ' a str ) > {
123
+ fn generate_backtrace ( & self , d : & ParsingData ) -> String {
124
+ let line = self . content . lines ( ) . skip ( d. line as usize ) . next ( ) . unwrap ( ) ;
125
+ let line_ch: usize = self
126
+ . content
127
+ . split ( '\n' )
128
+ . take ( d. line as usize )
129
+ . map ( |l| l. len ( ) +1 )
130
+ . sum ( ) ;
131
+ let ch = d. ch - line_ch;
132
+ let mut spaces: String = ( 0 ..ch-1 ) . map ( |_| ' ' ) . collect ( ) ;
133
+ spaces += "^" ;
134
+ let s = format ! ( "line {} col {}:\n \n {}\n {}" , d. line + 1 , ch, line, spaces) ;
135
+ s
136
+ }
137
+
138
+ fn parse_command_tag ( & self , i : & ' a str , d : & mut ParsingData ) -> Result < ( CommandType , & ' a str ) > {
119
139
let c = i. chars ( ) . next ( ) ;
120
140
let c = match c {
121
141
Some ( c) => c,
122
- None => return Err ( RenderError :: MissingCommandTag ) ,
142
+ None => return Err ( RenderError :: MissingCommandType ( self . generate_backtrace ( d ) ) ) ,
123
143
} ;
124
144
125
145
// TODO: improve this
126
146
let mut input = i;
127
147
let cmd_type = if c == self . config . execution {
128
148
input = & i[ 1 ..] ;
149
+ d. ch += 1 ;
129
150
CommandType :: Execution
130
151
} else if c == self . config . interpolate {
131
152
input = & i[ 1 ..] ;
153
+ d. ch += 1 ;
132
154
CommandType :: Interpolate
133
155
} else {
134
156
if self . config . interpolate == '\0' {
135
157
CommandType :: Interpolate
136
158
} else if self . config . execution == '\0' {
137
159
CommandType :: Execution
138
160
} else {
139
- return Err ( RenderError :: MissingCommandTag ) ;
161
+ return Err ( RenderError :: MissingCommandType ( self . generate_backtrace ( d ) ) ) ;
140
162
}
141
163
} ;
142
164
143
165
Ok ( ( cmd_type, input) )
144
166
}
145
167
146
- fn parse_whitespace ( & self , i : & ' a str ) -> Result < ( Option < Whitespace > , & ' a str ) > {
168
+ fn parse_whitespace (
169
+ & self ,
170
+ i : & ' a str ,
171
+ d : & mut ParsingData ,
172
+ ) -> Result < ( Option < Whitespace > , & ' a str ) > {
147
173
let c = i. chars ( ) . next ( ) ;
148
174
let whitespace = match c {
149
175
Some ( c) => {
@@ -160,15 +186,17 @@ impl<'a> Parser<'a> {
160
186
let mut input = i;
161
187
if whitespace. is_some ( ) {
162
188
input = & i[ 1 ..] ;
189
+ d. ch += 1 ;
163
190
}
164
191
Ok ( ( whitespace, input) )
165
192
}
166
193
167
- fn parse_closing_tag ( & self , i : & ' a str ) -> Result < ( & ' a str , & ' a str ) > {
194
+ fn parse_closing_tag ( & self , i : & ' a str , d : & mut ParsingData ) -> Result < ( & ' a str , & ' a str ) > {
168
195
let ( content, i) = match i. split_once ( & self . config . closing_tag ) {
169
196
Some ( x) => x,
170
- None => return Err ( RenderError :: MissingClosingTag ) ,
197
+ None => return Err ( RenderError :: MissingClosingTag ( self . generate_backtrace ( d ) ) ) ,
171
198
} ;
199
+ d. ch += self . config . closing_tag . len ( ) ;
172
200
Ok ( ( content, i) )
173
201
}
174
202
@@ -186,7 +214,7 @@ impl<'a> Parser<'a> {
186
214
res. iter ( ) . collect ( )
187
215
}
188
216
189
- pub fn trim_whitespace < ' b > (
217
+ fn trim_whitespace < ' b > (
190
218
& self ,
191
219
i : & ' b str ,
192
220
whitespace : Option < & Whitespace > ,
@@ -210,7 +238,7 @@ impl<'a> Parser<'a> {
210
238
}
211
239
}
212
240
x
213
- } ,
241
+ }
214
242
Some ( '\r' ) => {
215
243
let mut x = 1 ;
216
244
if left {
@@ -245,25 +273,34 @@ impl<'a> Parser<'a> {
245
273
pub fn parse_tokens ( & self ) -> Result < Vec < Token > > {
246
274
let mut tokens = vec ! [ ] ;
247
275
let mut input = self . content ;
276
+ let mut parsing_data = ParsingData { ch : 0 , line : 0 } ;
248
277
249
278
while let Some ( ( text, i) ) = input. split_once ( & self . config . opening_tag ) {
279
+ parsing_data. ch += self . config . opening_tag . len ( ) ;
280
+
250
281
if !text. is_empty ( ) {
251
282
tokens. push ( Token :: Text ( text) ) ;
283
+ parsing_data. ch += text. len ( ) ;
284
+ parsing_data. line += count_newlines ( text) ;
252
285
}
253
286
254
- let ( cmd_type , i) = self . parse_command_tag ( i ) ?;
255
- let ( opening_whitespace , i) = self . parse_whitespace ( i ) ?;
256
- let ( part1, i) = self . parse_closing_tag ( i) ?;
287
+ let ( opening_whitespace , i) = self . parse_whitespace ( i , & mut parsing_data ) ?;
288
+ let ( cmd_type , i) = self . parse_command_tag ( i , & mut parsing_data ) ?;
289
+ let ( part1, i) = self . parse_closing_tag ( i, & mut parsing_data ) ?;
257
290
258
291
// TODO: improve that
259
292
let content_whitespace = & part1[ part1. len ( ) - 1 ..] ;
260
- let ( closing_whitespace, _) = self . parse_whitespace ( content_whitespace) ?;
293
+ let ( closing_whitespace, _) =
294
+ self . parse_whitespace ( content_whitespace, & mut parsing_data) ?;
261
295
let content = if closing_whitespace. is_none ( ) {
262
296
part1
263
297
} else {
264
298
& part1[ ..part1. len ( ) - 1 ]
265
299
} ;
266
300
301
+ parsing_data. ch += content. len ( ) ;
302
+ parsing_data. line += count_newlines ( content) ;
303
+
267
304
let command = Command {
268
305
r#type : cmd_type,
269
306
opening_whitespace,
@@ -276,6 +313,8 @@ impl<'a> Parser<'a> {
276
313
}
277
314
if !input. is_empty ( ) {
278
315
tokens. push ( Token :: Text ( input) ) ;
316
+ parsing_data. ch += input. len ( ) ;
317
+ parsing_data. line += count_newlines ( input) ;
279
318
}
280
319
281
320
Ok ( tokens)
@@ -362,13 +401,11 @@ impl Renderer {
362
401
let parser = Parser :: new ( content, & self . config ) ;
363
402
let tokens = parser. parse_tokens ( ) ?;
364
403
let fn_body = parser. generate_js ( tokens) ;
365
- let async_fn = match self
366
- . async_constructor
367
- . call2 (
368
- & JsValue :: NULL ,
369
- & JsValue :: from ( "tp" ) ,
370
- & JsValue :: from ( & fn_body) . into ( ) ,
371
- ) {
404
+ let async_fn = match self . async_constructor . call2 (
405
+ & JsValue :: NULL ,
406
+ & JsValue :: from ( "tp" ) ,
407
+ & JsValue :: from ( & fn_body) . into ( ) ,
408
+ ) {
372
409
Ok ( f) => f,
373
410
Err ( _) => return Err ( RenderError :: SyntaxError ) ,
374
411
} ;
0 commit comments