Format the reader module
This commit is contained in:
parent
5181c84696
commit
25c58c27c2
157
src/reader.rs
157
src/reader.rs
|
@ -1,44 +1,42 @@
|
||||||
use crate::ast::{Expr, Number};
|
use crate::ast::{Expr, Number};
|
||||||
use std::io::{Read, BufReader};
|
use std::io::{BufReader, Read};
|
||||||
|
|
||||||
pub type ReadResult = Result<Expr, String>;
|
pub type ReadResult = Result<Expr, String>;
|
||||||
|
|
||||||
pub struct ExprReader {
|
pub struct ExprReader {
|
||||||
read_stack: Vec<char>
|
read_stack: Vec<char>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExprReader {
|
impl ExprReader {
|
||||||
|
|
||||||
fn new() -> ExprReader {
|
fn new() -> ExprReader {
|
||||||
ExprReader {
|
ExprReader { read_stack: vec![] }
|
||||||
read_stack: vec![]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_char<T: Read>(&mut self, reader: &mut BufReader<T>, skip_whitespace: bool) -> Option<char> {
|
fn get_char<T: Read>(
|
||||||
|
&mut self,
|
||||||
|
reader: &mut BufReader<T>,
|
||||||
|
skip_whitespace: bool,
|
||||||
|
) -> Option<char> {
|
||||||
loop {
|
loop {
|
||||||
match self.read_stack.pop() {
|
match self.read_stack.pop() {
|
||||||
Some(c) if !c.is_whitespace() || !skip_whitespace =>
|
Some(c) if !c.is_whitespace() || !skip_whitespace => return Some(c),
|
||||||
{
|
|
||||||
return Some(c)
|
|
||||||
},
|
|
||||||
Some(_) => continue,
|
Some(_) => continue,
|
||||||
None => ()
|
None => (),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Rust is weird, it doesn't provide a way to read from a buffer char by char.
|
// Rust is weird, it doesn't provide a way to read from a buffer char by char.
|
||||||
let mut single_char_buff = [0];
|
let mut single_char_buff = [0];
|
||||||
let bytes_read = reader.read(&mut single_char_buff);
|
let bytes_read = reader.read(&mut single_char_buff);
|
||||||
match bytes_read {
|
match bytes_read {
|
||||||
Ok(n) if n > 0 => {},
|
Ok(n) if n > 0 => {}
|
||||||
Ok(_) => return None,
|
Ok(_) => return None,
|
||||||
Err(_) => return None
|
Err(_) => return None,
|
||||||
};
|
};
|
||||||
let ch = single_char_buff[0] as char;
|
let ch = single_char_buff[0] as char;
|
||||||
|
|
||||||
match ch {
|
match ch {
|
||||||
c if !c.is_whitespace() || !skip_whitespace => return Some(c),
|
c if !c.is_whitespace() || !skip_whitespace => return Some(c),
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,19 +47,26 @@ impl ExprReader {
|
||||||
|
|
||||||
// Look ahead. AFAIK Rust doesn't provide any unread functoinality like Java input streams which
|
// Look ahead. AFAIK Rust doesn't provide any unread functoinality like Java input streams which
|
||||||
// sucks.
|
// sucks.
|
||||||
fn peek_char<T: Read>(&mut self, reader: &mut BufReader<T>, skip_whitespace: bool) -> Option<char> {
|
fn peek_char<T: Read>(
|
||||||
|
&mut self,
|
||||||
|
reader: &mut BufReader<T>,
|
||||||
|
skip_whitespace: bool,
|
||||||
|
) -> Option<char> {
|
||||||
match self.get_char(reader, skip_whitespace) {
|
match self.get_char(reader, skip_whitespace) {
|
||||||
Some(c) => {
|
Some(c) => {
|
||||||
self.unget_char(c);
|
self.unget_char(c);
|
||||||
Some(c)
|
Some(c)
|
||||||
},
|
}
|
||||||
None => None
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_quoted_expr<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
|
fn read_quoted_expr<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
|
||||||
let rest = self.read_expr(reader)?;
|
let rest = self.read_expr(reader)?;
|
||||||
Ok(Expr::Cons(Box::new(Expr::Symbol("quote".to_string())), Box::new(rest)))
|
Ok(Expr::Cons(
|
||||||
|
Box::new(Expr::Symbol("quote".to_string())),
|
||||||
|
Box::new(rest),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_unquoted_expr<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
|
fn read_unquoted_expr<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
|
||||||
|
@ -70,21 +75,27 @@ impl ExprReader {
|
||||||
// Move forward in the buffer since we peeked it
|
// Move forward in the buffer since we peeked it
|
||||||
let _ = self.get_char(reader, true);
|
let _ = self.get_char(reader, true);
|
||||||
let rest = self.read_expr(reader)?;
|
let rest = self.read_expr(reader)?;
|
||||||
Ok(Expr::Cons(Box::new(Expr::Symbol("unquote-splicing".to_string())),
|
Ok(Expr::Cons(
|
||||||
Box::new(rest)))
|
Box::new(Expr::Symbol("unquote-splicing".to_string())),
|
||||||
},
|
Box::new(rest),
|
||||||
|
))
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let rest = self.read_expr(reader)?;
|
let rest = self.read_expr(reader)?;
|
||||||
Ok(Expr::Cons(Box::new(Expr::Symbol("unquote".to_string())),
|
Ok(Expr::Cons(
|
||||||
Box::new(rest)))
|
Box::new(Expr::Symbol("unquote".to_string())),
|
||||||
|
Box::new(rest),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_quasiquoted_expr<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
|
fn read_quasiquoted_expr<T: Read>(&mut self, reader: &mut BufReader<T>) -> ReadResult {
|
||||||
let rest = self.read_expr(reader)?;
|
let rest = self.read_expr(reader)?;
|
||||||
Ok(Expr::Cons(Box::new(Expr::Symbol("quasiquote".to_string())),
|
Ok(Expr::Cons(
|
||||||
Box::new(rest)))
|
Box::new(Expr::Symbol("quasiquote".to_string())),
|
||||||
|
Box::new(rest),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: We might want to replace Cons with an actual List struct
|
// TODO: We might want to replace Cons with an actual List struct
|
||||||
|
@ -95,15 +106,15 @@ impl ExprReader {
|
||||||
// is it an empty list ?
|
// is it an empty list ?
|
||||||
// TODO: we might want to return an actual empty list here
|
// TODO: we might want to return an actual empty list here
|
||||||
Some(')') => return Ok(Expr::Nil),
|
Some(')') => return Ok(Expr::Nil),
|
||||||
_ => return Err(e)
|
_ => return Err(e),
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
let rest = match self.get_char(reader, true) {
|
let rest = match self.get_char(reader, true) {
|
||||||
Some(e) => {
|
Some(e) => {
|
||||||
self.unget_char(e);
|
self.unget_char(e);
|
||||||
self.read_list(reader)?
|
self.read_list(reader)?
|
||||||
},
|
}
|
||||||
None => return Err("Unexpected EOF, expected . or symbol".to_string())
|
None => return Err("Unexpected EOF, expected . or symbol".to_string()),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Expr::Cons(Box::new(first), Box::new(rest)))
|
Ok(Expr::Cons(Box::new(first), Box::new(rest)))
|
||||||
|
@ -111,10 +122,28 @@ impl ExprReader {
|
||||||
|
|
||||||
fn is_valid_for_identifier(&self, c: char) -> bool {
|
fn is_valid_for_identifier(&self, c: char) -> bool {
|
||||||
match c {
|
match c {
|
||||||
'!' | '$' | '%' | '&' | '*' | '+' | '-' | '.' | '~' |
|
'!'
|
||||||
'/' | ':' | '<' | '=' | '>' | '?' | '@' | '^' | '_' |
|
| '$'
|
||||||
'a'..='z' | 'A'..='Z' | '0'..='9' => true,
|
| '%'
|
||||||
_ => false
|
| '&'
|
||||||
|
| '*'
|
||||||
|
| '+'
|
||||||
|
| '-'
|
||||||
|
| '.'
|
||||||
|
| '~'
|
||||||
|
| '/'
|
||||||
|
| ':'
|
||||||
|
| '<'
|
||||||
|
| '='
|
||||||
|
| '>'
|
||||||
|
| '?'
|
||||||
|
| '@'
|
||||||
|
| '^'
|
||||||
|
| '_'
|
||||||
|
| 'a'..='z'
|
||||||
|
| 'A'..='Z'
|
||||||
|
| '0'..='9' => true,
|
||||||
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,11 +155,14 @@ impl ExprReader {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
s.push(ch);
|
s.push(ch);
|
||||||
s
|
s
|
||||||
},
|
}
|
||||||
Some(e) => {
|
Some(e) => {
|
||||||
return Err(format!("Unexpected character: got {}, expected a symbol", e))
|
return Err(format!(
|
||||||
},
|
"Unexpected character: got {}, expected a symbol",
|
||||||
None => return Err("Unexpected EOF".to_string())
|
e
|
||||||
|
))
|
||||||
|
}
|
||||||
|
None => return Err("Unexpected EOF".to_string()),
|
||||||
};
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -139,8 +171,8 @@ impl ExprReader {
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
self.unget_char(v);
|
self.unget_char(v);
|
||||||
break;
|
break;
|
||||||
},
|
}
|
||||||
None => break
|
None => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,9 +188,9 @@ impl ExprReader {
|
||||||
'n' => Some('\n'),
|
'n' => Some('\n'),
|
||||||
'r' => Some('\r'),
|
'r' => Some('\r'),
|
||||||
't' => Some('\t'),
|
't' => Some('\t'),
|
||||||
_ => None
|
_ => None,
|
||||||
},
|
},
|
||||||
None => None
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,29 +205,26 @@ impl ExprReader {
|
||||||
'\"' => break,
|
'\"' => break,
|
||||||
'\\' => match self.read_escape_char(reader) {
|
'\\' => match self.read_escape_char(reader) {
|
||||||
Some(v) => string.push(v),
|
Some(v) => string.push(v),
|
||||||
None => return Err(format!("Unexpected char to escape, got {}", e))
|
None => return Err(format!("Unexpected char to escape, got {}", e)),
|
||||||
},
|
},
|
||||||
//'\n' => return Err("Unescaped newlines are not allowed in string literals".to_string()),
|
//'\n' => return Err("Unescaped newlines are not allowed in string literals".to_string()),
|
||||||
_ => string.push(e)
|
_ => string.push(e),
|
||||||
},
|
},
|
||||||
None => return Err("Unexpected EOF while scanning a string".to_string())
|
None => return Err("Unexpected EOF while scanning a string".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Expr::Str(string))
|
Ok(Expr::Str(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_number<T: Read>(&mut self, reader: &mut BufReader<T>, neg: bool) -> ReadResult {
|
fn read_number<T: Read>(&mut self, reader: &mut BufReader<T>, neg: bool) -> ReadResult {
|
||||||
|
|
||||||
let mut is_double = false;
|
let mut is_double = false;
|
||||||
let mut string = (if neg {
|
let mut string = (if neg { "-" } else { "" }).to_string();
|
||||||
"-"
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
}).to_string();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match self.get_char(reader, false) {
|
match self.get_char(reader, false) {
|
||||||
Some(e) if e == '.' && is_double => return Err("A double with more that one '.' ???".to_string()),
|
Some(e) if e == '.' && is_double => {
|
||||||
|
return Err("A double with more that one '.' ???".to_string())
|
||||||
|
}
|
||||||
Some(e) if e == '.' => {
|
Some(e) if e == '.' => {
|
||||||
is_double = true;
|
is_double = true;
|
||||||
string.push(e);
|
string.push(e);
|
||||||
|
@ -205,7 +234,7 @@ impl ExprReader {
|
||||||
self.unget_char(e);
|
self.unget_char(e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
None => break
|
None => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if is_double {
|
if is_double {
|
||||||
|
@ -239,11 +268,10 @@ impl ExprReader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Neg number
|
|
||||||
// }
|
_ => self._read_symbol(reader),
|
||||||
_ => self._read_symbol(reader)
|
|
||||||
},
|
},
|
||||||
None => Err("Unexpected EOF while scanning atom".to_string())
|
None => Err("Unexpected EOF while scanning atom".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,23 +285,26 @@ impl ExprReader {
|
||||||
'(' => self.read_list(reader),
|
'(' => self.read_list(reader),
|
||||||
//'[' => self.read_vector(reader),
|
//'[' => self.read_vector(reader),
|
||||||
//'{' => self.read_map(reader),
|
//'{' => self.read_map(reader),
|
||||||
_ => {
|
_ => {
|
||||||
self.unget_char(c);
|
self.unget_char(c);
|
||||||
self.read_symbol(reader)
|
self.read_symbol(reader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
None => Ok(Expr::NoMatch)
|
None => Ok(Expr::NoMatch),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_from_buffer<T: Read>(&mut self, reader: &mut BufReader<T>) -> Result<Vec<Expr>, String> {
|
pub fn read_from_buffer<T: Read>(
|
||||||
|
&mut self,
|
||||||
|
reader: &mut BufReader<T>,
|
||||||
|
) -> Result<Vec<Expr>, String> {
|
||||||
let mut ast = vec![];
|
let mut ast = vec![];
|
||||||
loop {
|
loop {
|
||||||
match self.read_expr(reader) {
|
match self.read_expr(reader) {
|
||||||
Ok(Expr::NoMatch) => break,
|
Ok(Expr::NoMatch) => break,
|
||||||
Err(v) => return Err(v),
|
Err(v) => return Err(v),
|
||||||
Ok(v) => ast.push(v)
|
Ok(v) => ast.push(v),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(ast)
|
Ok(ast)
|
||||||
|
@ -284,10 +315,8 @@ impl ExprReader {
|
||||||
let mut buf_reader = BufReader::new(reader);
|
let mut buf_reader = BufReader::new(reader);
|
||||||
self.read_from_buffer(&mut buf_reader)
|
self.read_from_buffer(&mut buf_reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn read_string(input: &str) -> Result<Vec<Expr>, String> {
|
pub fn read_string(input: &str) -> Result<Vec<Expr>, String> {
|
||||||
let mut reader = ExprReader::new();
|
let mut reader = ExprReader::new();
|
||||||
reader.read(input)
|
reader.read(input)
|
||||||
|
|
Loading…
Reference in New Issue