yes
This commit is contained in:
parent
e4d171667f
commit
25a451e23e
10 changed files with 1072 additions and 0 deletions
65
src/main.rs
Normal file
65
src/main.rs
Normal 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
124
src/reader.rs
Normal 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
102
src/types.rs
Normal 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)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue