This commit is contained in:
Chris Cochrun 2024-11-04 15:02:59 -06:00
parent e4d171667f
commit 25a451e23e
10 changed files with 1072 additions and 0 deletions

65
src/main.rs Normal file
View file

@ -0,0 +1,65 @@
use color_eyre::Result;
use regex::Regex;
use rustyline::{config::Configurer, error::ReadlineError};
pub mod reader;
pub mod types;
use types::*;
fn main() -> Result<()> {
let mut rl = rustyline::DefaultEditor::new()?;
rl.set_edit_mode(rustyline::EditMode::Vi);
let env = Environment::default();
loop {
let entry = rl.readline(">> ");
match entry {
Ok(line) => {
rl.add_history_entry(line.as_str())?;
eval(line.as_str().into(), env.clone())?;
},
Err(ReadlineError::Interrupted) => {
println!("CTRL-C");
break
},
Err(ReadlineError::Eof) => {
println!("CTRL-D");
break
},
Err(err) => {
println!("Error: {:?}", err);
break
}
}
}
Ok(())
}
#[derive(Default, Debug, Clone)]
pub struct Environment {
symbols: Vec<Symbol>,
functions: Vec<String>,
keywords: Vec<String>,
}
fn read_eval_print(str: &str) -> Result<()> {
// print(eval(read(str)));
Ok(())
}
fn eval(expr: Expression, env: Environment) -> Result<()> {
let regex = Regex::new(r#"^\(([[:ascii:]] .*)\)$"#).unwrap();
let exp = regex.captures_iter(&expr.expr);
for expr in exp {
// let regex = Regex::new(r#"^(\w)$"#).unwrap();
// let mut atom = regex.captures_iter(atom?.get(0).unwrap().as_str());
// for atom in atom {
// }
for atom in expr.iter() {
if let Some(atom) = atom {
println!("{:?}", atom);
};
}
}
println!("{}", expr.expr);
Ok(())
}

124
src/reader.rs Normal file
View file

@ -0,0 +1,124 @@
use std::{cell::RefCell, rc::Rc};
use crate::types::Symbol;
use crate::Value;
use color_eyre::{eyre::eyre, Result};
use lazy_static::lazy_static;
use regex::Regex;
#[derive(Debug, Default, Clone)]
struct Reader {
tokens: Vec<String>,
position: usize,
}
impl Reader {
fn next(&mut self) -> Option<&String> {
let token = self.position;
self.position += 1;
self.tokens.get(token)
}
fn peek(&self) -> Option<&String> {
let index = self.position;
self.tokens.get(index)
}
fn read_form(&mut self) -> Value {
let Some(first) = self.peek() else {
return Value::Nil;
};
let mut value = Value::Nil;
if first.as_str() == "(" {
value = self.read_list();
} else {
if let Some(atom) = self.read_atom() {
value = atom
}
};
value
}
fn read_atom(&mut self) -> Option<Value> {
let Some(token) = self.next() else {
return None;
};
if token != "(" {
Some(Value::from(token))
} else {
None
}
}
fn read_list(&mut self) -> Value {
let mut values = vec![];
let length = self.tokens.len();
let position = self.position;
while self.tokens.len() >= position {
if self.peek().unwrap().as_str() == ")" {
break;
}
values.push(self.read_form());
}
Value::from(values)
}
}
pub fn read(str: &str) -> Value {
let mut reader = tokenize(str);
let value = reader.read_form();
value
}
fn tokenize(str: &str) -> Reader {
lazy_static! {
static ref RE: Regex = Regex::new(
r###"[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"?|;.*|[^\s\[\]{}('"`,;)]+)"###
)
.unwrap();
}
let mut res = vec![];
for cap in RE.captures_iter(str) {
if cap[1].starts_with(';') {
continue;
}
res.push(String::from(&cap[1]));
}
Reader {
tokens: res,
position: 0,
}
}
#[cfg(test)]
mod test {
use std::fs::read_to_string;
use super::*;
use pretty_assertions::{assert_eq, assert_ne};
fn get_test_string() -> String {
read_to_string("./test_presentation.lisp").unwrap()
}
#[test]
fn test_tokenize() {
let test_vec = vec![
String::from("("),
String::from("hello"),
String::from("world"),
String::from(")"),
];
let reader = tokenize("(hello world)");
assert_eq!(test_vec, reader.tokens)
}
#[test]
fn test_read() {
let test_values = Value::List(vec![Value::Symbol(Symbol(String::from("hello")))]);
// let values = read(&get_test_string());
// let values = read("(hello world)");
// assert_eq!(test_values, values)
}
}

102
src/types.rs Normal file
View file

@ -0,0 +1,102 @@
use std::num::ParseIntError;
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Expression {
pub expr: String,
pub value: Value,
}
impl From<&str> for Expression {
fn from(value: &str) -> Self {
Self {
expr: value.to_string(),
value: Value::String(value.to_string()),
}
}
}
#[derive(Default, Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
pub enum Value {
List(Vec<Value>),
String(String),
Number(i64),
#[default]
Nil,
Function,
Symbol(Symbol),
Keyword(Keyword),
}
impl Value {
fn parse(str: &str) -> Self {
match str {
"a" => Self::Symbol(Symbol::from(str)),
_ => Self::Nil,
}
}
}
impl From<Vec<Value>> for Value {
fn from(values: Vec<Value>) -> Self {
Value::List(values)
}
}
impl From<&str> for Value {
fn from(s: &str) -> Self {
let s = s.to_string();
if let Ok(parse_result) = s.parse::<i64>() {
Value::Number(parse_result)
} else if let Some(s) = s.strip_prefix(":") {
Value::Keyword(Keyword(s.to_string()))
} else if s.starts_with(r#"""#) {
Value::String(s)
} else if s == "nil".to_owned() {
Value::Nil
} else {
Value::Symbol(Symbol(s))
}
}
}
impl From<String> for Value {
fn from(str: String) -> Self {
Self::from(str.as_str())
}
}
impl From<&String> for Value {
fn from(str: &String) -> Self {
Self::from(str.as_str())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Symbol(pub String);
impl From<&str> for Symbol {
fn from(s: &str) -> Self {
Symbol(String::from(s))
}
}
impl std::fmt::Display for Symbol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Keyword(pub String);
impl From<&str> for Keyword {
fn from(s: &str) -> Self {
Keyword(String::from(s))
}
}
impl std::fmt::Display for Keyword {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}