Improved read

- no need to parse the input multiple times
- read function is more clean

Signed-off-by: teo3300 <matteo.rogora@live.it>
This commit is contained in:
teo3300
2023-11-14 10:29:39 +09:00
parent a3d402fed2
commit 0cca2f2b9b
5 changed files with 135 additions and 104 deletions

View File

@ -1,64 +1,16 @@
// io lib to read input and print output
use std::env::args;
use std::io::{self, Write};
mod env;
mod eval;
mod parse_tools;
mod printer;
mod reader;
mod types;
use env::{env_init, Env};
use regex::Regex;
use std::fs::File;
use std::io::{BufRead, BufReader};
use types::MalErr;
mod step4_if_fn_do;
use step4_if_fn_do::rep;
mod types;
fn load_file(filename: &str, env: &Env) -> io::Result<()> {
let file = File::open(filename)?;
let reader = BufReader::new(file);
let mut last: Result<Vec<String>, MalErr> = Ok(Vec::new());
let comment_line = Regex::new(r#"^[\s]*;.*"#).unwrap();
let mut input = String::new();
for line in reader.lines() {
match line {
Ok(line) => {
// Read line to compose program inpu
if line == "" || comment_line.is_match(&line) {
continue; // Don't even add it
} else {
input.push_str(format!("{}\n", &line).as_str());
}
last = match rep(&input, env) {
Err(error) if error.is_recoverable() => Err(error),
tmp => {
input = String::new();
tmp.map_err(|error| {
println!("; Error @ {}", error.message());
error
})
}
}
}
Err(err) => eprintln!("Error reading line: {}", err),
}
}
match last {
Err(error) => println!(
"; ERROR parsing: '{}'\n; {}\n; the environment is in an unknown state",
filename,
error.message()
),
_ => {}
}
Ok(())
}
use env::env_init;
use parse_tools::{load_file, interactive};
fn main() {
let reply_env = env_init();
@ -69,35 +21,5 @@ fn main() {
let _ = load_file(filename, &reply_env);
}
let mut num = 0;
loop {
let mut input = String::new();
loop {
print!("user> ");
// Flush the prompt to appear before command
let _ = io::stdout().flush();
// Read line to compose program input
let mut line = String::new();
io::stdin().read_line(&mut line).unwrap();
input.push_str(&line);
if input != "\n" {
// Perform rep on whole available input
match rep(&input, &reply_env) {
Ok(output) => output.iter().for_each(|el| println!("[{}]> {}", num, el)),
Err(error) => {
if error.is_recoverable() && line != "\n" {
continue;
}
println!("; [{}]> Error @ {}", num, error.message());
}
}
num += 1;
}
break;
}
}
interactive(reply_env);
}

87
src/parse_tools.rs Normal file
View File

@ -0,0 +1,87 @@
use crate::env::Env;
use crate::reader::Reader;
use crate::step4_if_fn_do::rep;
use crate::types::MalErr;
use regex::Regex;
use std::fs::File;
use std::io::{self, BufRead, BufReader};
pub fn load_file(filename: &str, env: &Env) -> io::Result<()> {
let file = File::open(filename)?;
let reader = BufReader::new(file);
let mut last: Result<Vec<String>, MalErr> = Ok(Vec::new());
let comment_line = Regex::new(r#"^[\s]*;.*"#).unwrap();
let parser = Reader::new();
for line in reader.lines() {
match line {
Ok(line) => {
// Read line to compose program inpu
if line == "" || comment_line.is_match(&line) {
continue; // Don't even add it
} else {
parser.push(&line);
}
last = match rep(&parser, env) {
Err(error) if error.is_recoverable() => {
Err(error)
}
tmp => {
parser.clear();
tmp.map_err(|error| {
println!("; Error @ {}", error.message());
error
})
}
}
}
Err(err) => eprintln!("Error reading line: {}", err),
}
}
match last {
Err(error) => println!(
"; ERROR parsing: '{}'\n; {}\n; the environment is in an unknown state",
filename,
error.message()
),
_ => {}
}
Ok(())
}
use std::io::Write;
pub fn interactive(env: Env) {
let mut num = 0;
let parser = Reader::new();
loop {
parser.clear();
loop {
print!("user> ");
// Flush the prompt to appear before command
let _ = io::stdout().flush();
// Read line to compose program input
let mut line = String::new();
io::stdin().read_line(&mut line).unwrap();
parser.push(&line);
// Perform rep on whole available input
match rep(&parser, &env) {
Ok(output) => output.iter().for_each(|el| println!("[{}]> {}", num, el)),
Err(error) => {
if error.is_recoverable() {// && line != "\n" {
continue;
}
println!("; [{}]> Error @ {}", num, error.message());
}
}
num += 1;
break;
}
}
}

View File

@ -1,5 +1,4 @@
use std::cell::Cell;
use std::cell::{Cell, RefCell};
// Specyfy components in "types"
use crate::types::*;
@ -9,7 +8,7 @@ use crate::types::MalType::*;
use regex::Regex;
pub struct Reader {
tokens: Vec<String>,
tokens: RefCell<Vec<String>>,
ptr: Cell<usize>,
}
@ -19,13 +18,31 @@ type Tokens = Vec<String>;
// Status on return should always be The last element of the last opened lists
// (append to the "last" list) while traversing
impl Reader {
pub fn new(input: &str) -> Reader {
Reader { tokens: tokenize(input), ptr: Cell::new(0) }
pub fn new() -> Reader {
Reader {
tokens: RefCell::new(Vec::new()),
ptr: Cell::new(0),
}
}
pub fn push(&self, input: &str) {
self.ptr.set(0);
// reset the state of the parser and push the additional strings
self.tokens
.borrow_mut()
.append(&mut tokenize(input))
}
pub fn clear(&self) {
self.ptr.set(0);
*self.tokens
.borrow_mut() = Vec::new();
}
// May be improved
fn get_token(&self, i: usize) -> Result<String, MalErr> {
self.tokens
.borrow()
.get(i)
.ok_or(MalErr::recoverable("Unexpected EOF"))
.cloned()
@ -103,9 +120,9 @@ impl Reader {
_ => self.read_atom(),
}
}
pub fn ended(&self) -> bool {
self.tokens.len() == self.ptr.get()
self.tokens.borrow().len() == self.ptr.get()
}
}
@ -119,11 +136,13 @@ pub fn read_str(reader: &Reader) -> MalRet {
/// Read a string and return a list of tokens in it (following regex in README)
// Add error handling for strings that are not terminated
fn tokenize(input: &str) -> Tokens {
let tokens = Regex::new(r###"[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"?|;.*\n|[^\s\[\]{}('"`,;)]*)"###)
.unwrap()
.captures_iter(input)
.map(|e| e[1].to_string())
.filter(|e| !(e.is_empty() || e.starts_with(';')))
.collect::<Vec<String>>();
let tokens = Regex::new(
r###"[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"?|;.*|[^\s\[\]{}('"`,;)]*)"###,
)
.unwrap()
.captures_iter(input)
.map(|e| e[1].to_string())
.filter(|e| !(e.is_empty() || e.starts_with(';')))
.collect::<Vec<String>>();
tokens
}

View File

@ -28,13 +28,14 @@ fn PRINT(output: MalType) -> String {
pr_str(&output, true)
}
pub fn rep(input: &str, env: &Env) -> Result<Vec<String>, MalErr> {
let reader = Reader::new(input);
pub fn rep(reader: &Reader, env: &Env) -> Result<Vec<String>, MalErr> {
let mut ret_str = Vec::new();
loop {
let ast = READ(&reader)?;
let out = EVAL(ast, env.clone())?;
ret_str.push(PRINT(out));
if reader.ended(){break Ok(ret_str);}
if reader.ended() {
break Ok(ret_str);
}
}
}