Cleaning repl

Cleaning repl, removing multi-statement repl, further implementation as
separated code from the rest

Signed-off-by: teo3300 <matteo.rogora@live.it>
This commit is contained in:
teo3300
2023-06-10 03:10:47 +02:00
parent ce21d3b728
commit 7be624e032
3 changed files with 41 additions and 85 deletions

View File

@ -29,10 +29,8 @@ fn main() -> io::Result<()> {
// Perform rep on whole available input // Perform rep on whole available input
match rep(&input) { match rep(&input) {
Ok(output) => { Ok(output) => {
for el in output { num += 1;
num += 1; println!("[{}]> {}", num, output);
println!("[{}]> {}", num, el);
}
} }
Err(err) => { Err(err) => {
if line == "\n" { if line == "\n" {

View File

@ -19,26 +19,23 @@ impl Reader {
Reader { tokens, ptr: 0 } Reader { tokens, ptr: 0 }
} }
fn avail(&self) -> bool { // May be improved
self.ptr < self.tokens.len() fn get_token(&self, i: usize) -> Result<String, MalErr> {
match self.tokens.get(i) {
Some(token) => Ok(token.to_string()),
None => Err("Unexpected EOF".to_string()),
}
} }
/// Returns the token at the current position /// Returns the token at the current position
fn peek(&self) -> Result<String, MalErr> { fn peek(&self) -> Result<String, MalErr> {
match self.tokens.get(self.ptr) { self.get_token(self.ptr)
Some(token) => Ok(token.to_string()),
None => Err("Unexpected EOF, Missing parenthesis?".to_string()),
}
} }
/// Returns the token at current position and increment current position /// Returns the token at current position and increment current position
// TODO: PLEASE USE THE PEEK FUNCTION
fn next(&mut self) -> Result<String, MalErr> { fn next(&mut self) -> Result<String, MalErr> {
self.ptr += 1; self.ptr += 1;
match self.tokens.get(self.ptr - 1) { self.get_token(self.ptr - 1)
Some(token) => Ok(token.to_string()),
None => Err("Unexpected EOF, Missing parenthesis?".to_string()),
}
} }
/// Repeatedly calls `read_form` of the reader object until it finds a ")" token /// Repeatedly calls `read_form` of the reader object until it finds a ")" token
@ -50,44 +47,36 @@ impl Reader {
self.next()?; self.next()?;
let mut vector = Vec::new(); let mut vector = Vec::new();
loop {
let token = self.peek()?; while self.peek()? != terminator {
if token == terminator {
break;
}
vector.push(self.read_form()?) vector.push(self.read_form()?)
} }
self.next()?; self.next()?;
match terminator { match terminator {
")" => Ok(List(vector)), ")" => Ok(List(vector)),
"]" => Ok(Vector(vector)), "]" => Ok(Vector(vector)),
"}" => make_map(vector), "}" => make_map(vector),
_ => Err(format!("Unknown collection terminator: {}", terminator)), _ => Err("Unknown collection terminator".to_string()),
} }
} }
/// Read atomic token and return appropriate scalar () /// Read atomic token and return appropriate scalar ()
fn read_atom(&mut self) -> MalRet { fn read_atom(&mut self) -> MalRet {
let token = self.next()?; match &self.next()?[..] {
let re_digits = Regex::new(r"^-?[0-9]+$").unwrap(); ")" | "]" | "}" => Err("Missing open parenthesis".to_string()),
match token.as_str() {
")" | "]" | "}" => Err(format!("Lone parenthesis {}", token)),
"false" => Ok(Bool(false)), "false" => Ok(Bool(false)),
"true" => Ok(Bool(true)), "true" => Ok(Bool(true)),
"nil" => Ok(Nil), "nil" => Ok(Nil),
_ => { tk => {
if re_digits.is_match(&token) { if Regex::new(r"^-?[0-9]+$").unwrap().is_match(tk) {
Ok(Int(token.parse::<isize>().unwrap())) Ok(Int(tk.parse::<isize>().unwrap()))
} else if token.starts_with('\"') { } else if tk.starts_with('\"') {
if token.ends_with('\"') { Ok(Str(map_key(KeyVar::Str, &unescape_str(tk))))
Ok(Str(map_key(KeyVar::Str, &unescape_str(&token)))) } else if tk.starts_with(':') {
} else { Ok(Key(map_key(KeyVar::Key, tk)))
Err("Unterminated string, expected \"".to_string())
}
} else if token.starts_with(':') {
Ok(Key(map_key(KeyVar::Key, &token)))
} else { } else {
Ok(Sym(map_key(KeyVar::Sym, &token))) Ok(Sym(map_key(KeyVar::Sym, tk)))
} }
} }
} }
@ -99,9 +88,8 @@ impl Reader {
/// "(" -> call `read_list` /// "(" -> call `read_list`
/// otherwise -> call `read_atom` /// otherwise -> call `read_atom`
fn read_form(&mut self) -> MalRet { fn read_form(&mut self) -> MalRet {
let token = self.peek()?;
// String slice containing the whole string // String slice containing the whole string
match &token[..] { match &self.peek()?[..] {
// Consume "(" and parse list // Consume "(" and parse list
"(" => self.read_list(")"), "(" => self.read_list(")"),
"[" => self.read_list("]"), "[" => self.read_list("]"),
@ -114,43 +102,17 @@ impl Reader {
/// Call `tokenize` on a string /// Call `tokenize` on a string
/// Create anew Reader with the tokens /// Create anew Reader with the tokens
/// Call read_from with the reader instance /// Call read_from with the reader instance
/// TODO: catch errors pub fn read_str(input: &str) -> MalRet {
pub fn read_str(input: &str) -> Result<Vec<MalType>, MalErr> { Reader::new(tokenize(input)).read_form()
let tokens = tokenize(input);
match tokens.len() {
0 => Ok(vec![Nil]),
_ => {
let mut reader = Reader::new(tokens);
let mut res = Vec::new();
while reader.avail() {
match reader.read_form() {
Err(err) => return Err(err),
Ok(any) => res.push(any),
};
}
Ok(res)
}
}
} }
/// Read a string and return a list of tokens in it (following regex in README) /// Read a string and return a list of tokens in it (following regex in README)
// Add error handling for strings that are not terminated // Add error handling for strings that are not terminated
fn tokenize(input: &str) -> Vec<String> { fn tokenize(input: &str) -> Vec<String> {
let mut tokens = Vec::new(); Regex::new(r###"[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"?|;.*\n|[^\s\[\]{}('"`,;)]*)"###)
.unwrap()
let re = Regex::new( .captures_iter(input)
r###"[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"?|;.*\n|[^\s\[\]{}('"`,;)]*)"###, .map(|e| e[1].to_string())
) .filter(|e| !e.is_empty() || !e.starts_with(';'))
.unwrap(); .collect::<Vec<String>>()
for match_str in re.captures_iter(input) {
if !match_str[1].is_empty() {
// Drop comments
if match_str[1].starts_with(';') {
continue;
}
tokens.push(match_str[1].to_string());
}
}
tokens
} }

View File

@ -6,11 +6,11 @@
use crate::printer::pr_str; use crate::printer::pr_str;
use crate::reader::read_str; use crate::reader::read_str;
use crate::types::{MalErr, MalType}; use crate::types::{MalRet, MalType};
#[allow(non_snake_case)] #[allow(non_snake_case)]
/// Read input and generate an ast /// Read input and generate an ast
fn READ(input: &str) -> Result<Vec<MalType>, MalErr> { fn READ(input: &str) -> MalRet {
match read_str(input) { match read_str(input) {
Ok(ast) => Ok(ast), Ok(ast) => Ok(ast),
Err(err) => Err(format!("@ READ: {}", err)), Err(err) => Err(format!("@ READ: {}", err)),
@ -19,22 +19,18 @@ fn READ(input: &str) -> Result<Vec<MalType>, MalErr> {
#[allow(non_snake_case)] #[allow(non_snake_case)]
/// Evaluate the generated ast /// Evaluate the generated ast
fn EVAL(ast: Vec<MalType>) -> Vec<MalType> { fn EVAL(ast: MalType) -> MalRet {
ast Ok(ast)
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
/// Print out the result of the evaluation /// Print out the result of the evaluation
fn PRINT(input: Vec<MalType>) -> Vec<String> { fn PRINT(output: MalType) -> String {
let mut ret = Vec::new(); pr_str(&output, true)
for expr in input {
ret.push(pr_str(&expr, true))
}
ret
} }
pub fn rep(input: &str) -> Result<Vec<String>, MalErr> { pub fn rep(input: &str) -> Result<String, String> {
let ast = READ(input)?; let ast = READ(input)?;
let out = EVAL(ast); let out = EVAL(ast)?;
Ok(PRINT(out)) Ok(PRINT(out))
} }