Skip to content

Commit 7205b4a

Browse files
committed
The event emitter of the reader compiles.
The event emitter of the reader now compiles. I am leaving the project as is for now, though I may return later.
1 parent fb2b5aa commit 7205b4a

File tree

1 file changed

+177
-91
lines changed

1 file changed

+177
-91
lines changed

src/read.rs

Lines changed: 177 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,30 @@
11
use std::io;
22
use std::io::prelude::*;
33
use std::char;
4-
use super::{alloc, value};
4+
use std::iter::Peekable;
5+
use super::interp;
56

7+
#[derive(Debug)]
68
pub enum ReadError {
9+
/// EOF in list
710
EOFInList,
11+
12+
/// EOF in vector
813
EOFInVector,
14+
15+
/// Missing `)`
916
MissingCloseParen,
17+
18+
/// Input/output error
1019
IoError(io::Error),
20+
21+
/// EOF in string
1122
EOFInString,
23+
24+
/// EOF in symbol
1225
EOFInSymbol,
26+
27+
/// EOF after `#\\`
1328
EOFAfterSharpBackslash,
1429

1530
/// Bad sharpsign read macro
@@ -30,6 +45,9 @@ pub enum ReadError {
3045
/// Stream not valid UTF-8. The argument is
3146
/// the partial sequence accumulated.
3247
InvalidUtf8(u32),
48+
49+
/// `|` in symbol unescaped
50+
PipeInSymbol,
3351
}
3452

3553
/// An event that can be emitted by the reader or tree-walker, and which
@@ -93,6 +111,9 @@ pub enum Event {
93111
/// Unsyntax splicing #,@
94112
UnsyntaxSplicing,
95113

114+
/// Dot `.`
115+
Dot,
116+
96117
/// End of file
97118
EOF,
98119
}
@@ -103,7 +124,8 @@ enum StringOrSymbol {
103124
Symbol,
104125
}
105126

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)
107129
-> Result<char, ReadError> {
108130
if unicode_char <= 0x7F {
109131
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)
115137
let len = len - 1;
116138
let mut value: u32 = (unicode_char >> (len + 2)).into();
117139
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();
121142
value &= current << (len - count as u8)
122143
}
123144
char::from_u32(value).ok_or(ReadError::InvalidUtf8(value))
@@ -134,7 +155,7 @@ macro_rules! next {
134155
type ReadResult = Result<char, ReadError>;
135156

136157
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 {
138159
loop {
139160
let eof = ReadError::BadEscape;
140161
let mut escaped_char = 0;
@@ -157,10 +178,10 @@ fn handle_unicode_escape<R: BufRead>(file: &mut Bytes<R>) -> ReadResult {
157178
}
158179
}
159180

160-
fn process_escape<R: BufRead>(file: &mut Bytes<R>) -> ReadResult {
181+
fn process_escape<R: BufRead>(file: &mut Peekable<Bytes<R>>) -> ReadResult {
161182
let bad = ReadError::BadEscape;
162183
loop {
163-
return Ok(match next!(file, bad) {
184+
return Ok(match next!(file, ReadError::BadEscape) {
164185
b'n' => '\n',
165186
b't' => '\t',
166187
b'e' => '\x1b',
@@ -186,8 +207,9 @@ fn process_escape<R: BufRead>(file: &mut Bytes<R>) -> ReadResult {
186207

187208

188209

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> {
191213
use std::char;
192214
let premature_eof = || {
193215
match delimiter {
@@ -196,7 +218,7 @@ pub fn read_escaped<R: BufRead>(file: &mut Bytes<R>, delimiter: StringOrSymbol)
196218
}
197219
};
198220

199-
let buf = String::new();
221+
let mut buf = String::new();
200222
loop {
201223
buf.push(match next!(file, premature_eof()) {
202224
b'\\' => try!(process_escape(file)),
@@ -208,100 +230,164 @@ pub fn read_escaped<R: BufRead>(file: &mut Bytes<R>, delimiter: StringOrSymbol)
208230
}
209231
Ok(buf)
210232
}
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+
236234
pub struct Reader<'a, 'b, T: 'a + BufRead> {
237235
stream: &'a mut T,
238236
state: &'b mut interp::State,
239237
}
240238

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+
}
269243

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 {
274303
b'(' => Event::StartList(false),
275304
b'[' => Event::StartList(true),
276305
b'\'' => Event::Quote,
277306
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+
}
284333
}
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+
}
296335
b')' => Event::EndList(false),
297336
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))),
300339
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+
}));
305391
}
306392
}
307393
}

0 commit comments

Comments
 (0)