1
1
use std:: io;
2
2
use std:: io:: prelude:: * ;
3
3
use std:: char;
4
- use super :: { alloc, value} ;
4
+ use std:: iter:: Peekable ;
5
+ use super :: interp;
5
6
7
+ #[ derive( Debug ) ]
6
8
pub enum ReadError {
9
+ /// EOF in list
7
10
EOFInList ,
11
+
12
+ /// EOF in vector
8
13
EOFInVector ,
14
+
15
+ /// Missing `)`
9
16
MissingCloseParen ,
17
+
18
+ /// Input/output error
10
19
IoError ( io:: Error ) ,
20
+
21
+ /// EOF in string
11
22
EOFInString ,
23
+
24
+ /// EOF in symbol
12
25
EOFInSymbol ,
26
+
27
+ /// EOF after `#\\`
13
28
EOFAfterSharpBackslash ,
14
29
15
30
/// Bad sharpsign read macro
@@ -30,6 +45,9 @@ pub enum ReadError {
30
45
/// Stream not valid UTF-8. The argument is
31
46
/// the partial sequence accumulated.
32
47
InvalidUtf8 ( u32 ) ,
48
+
49
+ /// `|` in symbol unescaped
50
+ PipeInSymbol ,
33
51
}
34
52
35
53
/// An event that can be emitted by the reader or tree-walker, and which
@@ -93,6 +111,9 @@ pub enum Event {
93
111
/// Unsyntax splicing #,@
94
112
UnsyntaxSplicing ,
95
113
114
+ /// Dot `.`
115
+ Dot ,
116
+
96
117
/// End of file
97
118
EOF ,
98
119
}
@@ -103,7 +124,8 @@ enum StringOrSymbol {
103
124
Symbol ,
104
125
}
105
126
106
- fn char_from_stream_and_byte < R : BufRead > ( file : & mut Bytes < R > , unicode_char : u8 )
127
+ fn char_from_stream_and_byte < R : BufRead > ( file : & mut Peekable < Bytes < R > > ,
128
+ unicode_char : u8 )
107
129
-> Result < char , ReadError > {
108
130
if unicode_char <= 0x7F {
109
131
return Ok ( unicode_char as char ) ;
@@ -115,9 +137,8 @@ fn char_from_stream_and_byte<R: BufRead>(file: &mut Bytes<R>, unicode_char: u8)
115
137
let len = len - 1 ;
116
138
let mut value: u32 = ( unicode_char >> ( len + 2 ) ) . into ( ) ;
117
139
value <<= len * 6 ;
118
- for ( count, current_byte_value) in file. take ( len. into ( ) ) . enumerate ( ) {
119
- let current: u32 = try!( current_byte_value. map_err (
120
- ReadError :: IoError ) ) . into ( ) ;
140
+ for ( count, current_byte_value) in file. take ( len. into ( ) ) . enumerate ( ) {
141
+ let current: u32 = try!( current_byte_value. map_err ( ReadError :: IoError ) ) . into ( ) ;
121
142
value &= current << ( len - count as u8 )
122
143
}
123
144
char:: from_u32 ( value) . ok_or ( ReadError :: InvalidUtf8 ( value) )
@@ -134,7 +155,7 @@ macro_rules! next {
134
155
type ReadResult = Result < char , ReadError > ;
135
156
136
157
use std:: io:: Bytes ;
137
- fn handle_unicode_escape < R : BufRead > ( file : & mut Bytes < R > ) -> ReadResult {
158
+ fn handle_unicode_escape < R : BufRead > ( file : & mut Peekable < Bytes < R > > ) -> ReadResult {
138
159
loop {
139
160
let eof = ReadError :: BadEscape ;
140
161
let mut escaped_char = 0 ;
@@ -157,10 +178,10 @@ fn handle_unicode_escape<R: BufRead>(file: &mut Bytes<R>) -> ReadResult {
157
178
}
158
179
}
159
180
160
- fn process_escape < R : BufRead > ( file : & mut Bytes < R > ) -> ReadResult {
181
+ fn process_escape < R : BufRead > ( file : & mut Peekable < Bytes < R > > ) -> ReadResult {
161
182
let bad = ReadError :: BadEscape ;
162
183
loop {
163
- return Ok ( match next ! ( file, bad ) {
184
+ return Ok ( match next ! ( file, ReadError :: BadEscape ) {
164
185
b'n' => '\n' ,
165
186
b't' => '\t' ,
166
187
b'e' => '\x1b' ,
@@ -186,8 +207,9 @@ fn process_escape<R: BufRead>(file: &mut Bytes<R>) -> ReadResult {
186
207
187
208
188
209
189
- pub fn read_escaped < R : BufRead > ( file : & mut Bytes < R > , delimiter : StringOrSymbol )
190
- -> Result < String , ReadError > {
210
+ fn read_escaped < R : BufRead > ( file : & mut Peekable < Bytes < R > > ,
211
+ delimiter : StringOrSymbol )
212
+ -> Result < String , ReadError > {
191
213
use std:: char;
192
214
let premature_eof = || {
193
215
match delimiter {
@@ -196,7 +218,7 @@ pub fn read_escaped<R: BufRead>(file: &mut Bytes<R>, delimiter: StringOrSymbol)
196
218
}
197
219
} ;
198
220
199
- let buf = String :: new ( ) ;
221
+ let mut buf = String :: new ( ) ;
200
222
loop {
201
223
buf. push ( match next ! ( file, premature_eof( ) ) {
202
224
b'\\' => try!( process_escape ( file) ) ,
@@ -208,100 +230,164 @@ pub fn read_escaped<R: BufRead>(file: &mut Bytes<R>, delimiter: StringOrSymbol)
208
230
}
209
231
Ok ( buf)
210
232
}
211
- // if delimiter == UndelimitedSymbol && c.is_whitespace() {
212
- // break
213
- // } else {
214
- // c
215
- // }
216
- // }
217
- // let bad = ReadError::BadEscape;
218
- // loop {
219
- // return Ok(match next!(file, bad) {
220
- // b'n' => '\n',
221
- // b't' => '\t',
222
- // b'e' => '\x1b',
223
- // b'b' => '\x08',
224
- // b'v' => '\x0b',
225
- // b'\r' => match next!(file, bad) {
226
- // Some(b'\n') => continue,
227
- // _ => return Err(bad),
228
- // },
229
- // b'\n' => continue,
230
- // b'x' | b'u' => try!(handle_unicode_escape(file)),
231
- // literal@b'|'|b'"'|b'\\'|b'#'|b'`'|b','|b'\'' => literal.into(),
232
- // _ => return Err(bad),
233
- // })
234
- // }
235
- //
233
+
236
234
pub struct Reader < ' a , ' b , T : ' a + BufRead > {
237
235
stream : & ' a mut T ,
238
236
state : & ' b mut interp:: State ,
239
237
}
240
238
241
- // let chars = file.chars().peekable();
242
- // let mut depth = 1;
243
- // let ref mut heap = state.heap;
244
- // let run_macros_self_evaluating = |mut value| while let Some(x) = vec.pop()
245
- // {
246
- // match x {
247
- // State::InList(ref x)|State::InVec(ref x) => {
248
- // x += 1
249
- // }
250
- // State::ReadEval => unimplemented!(),
251
- //
252
- // State::Quote | State::Unquote | State::Quasiquote |
253
- // State::Syntax | State::Unsyntax | State::Quasisyntax => {
254
- // state.push_nil();
255
- // state.list(2)
256
- // }
257
- // }
258
- // };
259
- //
260
-
261
-
262
-
263
- pub fn read < R : BufRead > ( file : & mut Bytes < R > ) -> Result < Event , ReadError > {
264
- let handle_splicing = |file : & mut Bytes < R > , nosplice, splice| match file. peek ( ) {
265
- Some ( Ok ( '@' ) ) => { file. next ( ) ; Ok ( splice) }
266
- Some ( Ok ( _) ) | None => Ok ( nosplice) ,
267
- Some ( x) => x,
268
- } ;
239
+ pub struct EventSource < ' a , R : ' a + BufRead > {
240
+ file : & ' a mut Peekable < Bytes < R > > ,
241
+ last_chr : Option < u8 > ,
242
+ }
269
243
270
- loop {
271
- let next: Option < Result < u8 , io:: Error > > = file. next ( ) ;
272
- if let Some ( c) = next {
273
- return Ok ( match try!( c. map_err ( ReadError :: IoError ) ) {
244
+ impl < ' a , R : BufRead > EventSource < ' a , R > {
245
+ pub fn new ( reader : & ' a mut Peekable < Bytes < R > > ) -> Self {
246
+ EventSource {
247
+ file : reader,
248
+ last_chr : Default :: default ( ) ,
249
+ }
250
+ }
251
+ }
252
+ impl < ' a , R : BufRead > Iterator for EventSource < ' a , R > {
253
+ type Item = Result < Event , ReadError > ;
254
+
255
+ fn next ( & mut self ) -> Option < <Self as Iterator >:: Item > {
256
+ let handle_splicing = |file : & mut Peekable < Bytes < R > > , nosplice : Event , splice : Event | {
257
+ let res1 = {
258
+ let q = file. peek ( ) ;
259
+ match q {
260
+ Some ( & Ok ( b'@' ) ) => ( Ok ( splice) , true ) ,
261
+ Some ( & Ok ( _) ) | None => ( Ok ( nosplice) , false ) ,
262
+ Some ( & Err ( ref _a) ) => ( Err ( ( ) ) , true ) ,
263
+ }
264
+ } ;
265
+ match res1 {
266
+ ( Ok ( good) , take_char) => {
267
+ if take_char {
268
+ file. next ( ) ;
269
+ }
270
+ Ok ( good)
271
+ }
272
+ ( Err ( ( ) ) , false ) => unreachable ! ( ) ,
273
+ ( Err ( ( ) ) , true ) => Err ( file. next ( ) . unwrap ( ) . unwrap_err ( ) ) ,
274
+ }
275
+ } ;
276
+
277
+ macro_rules! my_try {
278
+ ( $exp: expr) => {
279
+ match $exp {
280
+ Ok ( x) => x,
281
+ Err ( x) => return Some ( Err ( x) ) ,
282
+ }
283
+ }
284
+ }
285
+
286
+ macro_rules! iter_next {
287
+ ( $exp: expr, $err: expr) => {
288
+ my_try!( my_try!( $exp. next( ) . ok_or( $err) ) . map_err( |x|ReadError :: IoError ( x) ) )
289
+ }
290
+ }
291
+ loop {
292
+ let chr = if let Some ( chr) = self . last_chr {
293
+ chr
294
+ } else {
295
+ let next: Option < Result < u8 , io:: Error > > = self . file . next ( ) ;
296
+ if let Some ( c) = next {
297
+ my_try ! ( c. map_err( ReadError :: IoError ) )
298
+ } else {
299
+ return None ;
300
+ }
301
+ } ;
302
+ return Some ( Ok ( match chr {
274
303
b'(' => Event :: StartList ( false ) ,
275
304
b'[' => Event :: StartList ( true ) ,
276
305
b'\'' => Event :: Quote ,
277
306
b'`' => Event :: Quasiquote ,
278
- b',' => try!( handle_splicing ( file, Event :: Unquote , Event :: UnquoteSplicing ) ) ,
279
- b'#' => match next ! ( file, ReadError :: EOFAfterSharp ) {
280
- b'.' => Event :: ReadEval ,
281
- b'\\' => {
282
- let byte = next ! ( file, ReadError :: EOFAfterSharpBackslash ) ;
283
- Event :: Char ( try!( char_from_stream_and_byte ( file, byte) ) )
307
+ b',' => {
308
+ my_try ! ( handle_splicing( self . file, Event :: Unquote , Event :: UnquoteSplicing )
309
+ . map_err( ReadError :: IoError ) )
310
+ }
311
+ b'#' => {
312
+ match iter_next ! ( self . file, ReadError :: EOFAfterSharp ) {
313
+ b'.' => Event :: ReadEval ,
314
+ b'\\' => {
315
+ let byte = iter_next ! ( self . file, ReadError :: EOFAfterSharpBackslash ) ;
316
+ Event :: Char ( my_try ! ( char_from_stream_and_byte( self . file, byte) ) )
317
+ }
318
+ b't' => Event :: True ,
319
+ b'f' => Event :: False ,
320
+ b'\'' => Event :: Syntax ,
321
+ b'`' => Event :: Quasisyntax ,
322
+ b',' => {
323
+ my_try ! ( handle_splicing( self . file,
324
+ Event :: Unsyntax ,
325
+ Event :: UnsyntaxSplicing )
326
+ . map_err( ReadError :: IoError ) )
327
+ }
328
+ b'(' => Event :: StartVec ,
329
+ dispatch_char => {
330
+ return Some ( Err ( ReadError :: BadSharpMacro ( [ dispatch_char as char ,
331
+ '\0' ] ) ) )
332
+ }
284
333
}
285
- b't' => Event :: True ,
286
- b'f' => Event :: False ,
287
- b'\'' => Event :: Syntax ,
288
- b'`' => Event :: Quasisyntax ,
289
- b',' => try!( handle_splicing ( file, Event :: Unsyntax ,
290
- Event :: UnsyntaxSplicing ) ) ,
291
- b'(' => Event :: StartVec ,
292
- dispatch_char =>
293
- return Err ( ReadError :: BadSharpMacro ( [ dispatch_char as char ,
294
- '\0' ] ) )
295
- } ,
334
+ }
296
335
b')' => Event :: EndList ( false ) ,
297
336
b']' => Event :: EndList ( true ) ,
298
- b'"' => Event :: Str ( try !( read_escaped ( file, StringOrSymbol :: String ) ) ) ,
299
- b'|' => Event :: Symbol ( try !( read_escaped ( file, StringOrSymbol :: Symbol ) ) ) ,
337
+ b'"' => Event :: Str ( my_try ! ( read_escaped( self . file, StringOrSymbol :: String ) ) ) ,
338
+ b'|' => Event :: Symbol ( my_try ! ( read_escaped( self . file, StringOrSymbol :: Symbol ) ) ) ,
300
339
b'\t' ...b'\r' | b' ' => continue , // ASCII whitespace
301
-
302
- } )
303
- } else {
304
- return Ok ( Event :: EOF ) ;
340
+ val => {
341
+ let chr = if val < 0x7F {
342
+ val as char
343
+ } else {
344
+ my_try ! ( char_from_stream_and_byte( self . file, val) )
345
+ } ;
346
+ if chr. is_whitespace ( ) {
347
+ continue ;
348
+ }
349
+ let mut buf = String :: new ( ) ;
350
+ buf. push ( chr) ;
351
+ loop {
352
+ let chr = if let Some ( x) = self . file . next ( ) {
353
+ my_try ! ( x. map_err( ReadError :: IoError ) )
354
+ } else {
355
+ break ;
356
+ } ;
357
+ match chr {
358
+ b'\\' => buf. push ( my_try ! ( process_escape( self . file) ) ) ,
359
+ b'|' => return Some ( Err ( ReadError :: PipeInSymbol ) ) ,
360
+ a @ b'"' |
361
+ a @ b'\'' |
362
+ a @ b'`' |
363
+ a @ b',' |
364
+ a @ b'(' |
365
+ a @ b'[' |
366
+ a @ b']' |
367
+ a @ b')' |
368
+ a @ b'{' |
369
+ a @ b'}' => {
370
+ self . last_chr = Some ( a) ;
371
+ break ;
372
+ }
373
+ b'\t' ...b'\r' | b' ' => break , // ASCII whitespace
374
+ chr => {
375
+ let unicode_char = my_try ! ( char_from_stream_and_byte( self . file,
376
+ chr) ) ;
377
+ if unicode_char. is_whitespace ( ) {
378
+ break ;
379
+ }
380
+ buf. push ( unicode_char)
381
+ }
382
+ }
383
+ }
384
+ return Some ( Ok ( if & buf == "." {
385
+ Event :: Dot
386
+ } else {
387
+ Event :: Symbol ( buf)
388
+ } ) ) ;
389
+ }
390
+ } ) ) ;
305
391
}
306
392
}
307
393
}
0 commit comments