making this work as a library
This commit is contained in:
parent
ba5b02074d
commit
37af7ff0ef
4 changed files with 160 additions and 1 deletions
|
@ -3,6 +3,10 @@ name = "crisp"
|
|||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["staticlib"]
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
color-eyre = "0.6.3"
|
||||
lazy_static = "1.5.0"
|
||||
|
|
|
@ -23,8 +23,12 @@ impl Environment {
|
|||
pub fn get_symbol(&self, symbol: &Symbol) -> &Value {
|
||||
if let Some(value) = self.symbols.get(symbol) {
|
||||
value
|
||||
} else {
|
||||
if let Some(env) = &*self.outer {
|
||||
env.get_symbol(symbol)
|
||||
} else {
|
||||
&Value::Nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
138
src/lib.rs
Normal file
138
src/lib.rs
Normal file
|
@ -0,0 +1,138 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use color_eyre::{
|
||||
eyre::{eyre, ContextCompat},
|
||||
Result,
|
||||
};
|
||||
use env::Environment;
|
||||
use printer::print;
|
||||
use reader::read;
|
||||
use regex::Regex;
|
||||
use rustyline::{config::Configurer, error::ReadlineError, Editor};
|
||||
|
||||
pub mod env;
|
||||
pub mod macros;
|
||||
pub mod printer;
|
||||
pub mod reader;
|
||||
pub mod types;
|
||||
use types::*;
|
||||
|
||||
pub fn main() -> Result<()> {
|
||||
let mut rl = Editor::<(), rustyline::history::DefaultHistory>::new().unwrap();
|
||||
if rl.load_history(".mal-history").is_err() {
|
||||
eprintln!("No previous history.");
|
||||
}
|
||||
rl.set_edit_mode(rustyline::EditMode::Vi);
|
||||
|
||||
let mut env = Environment::new();
|
||||
env.insert_symbol(
|
||||
Symbol::from("+"),
|
||||
Value::func(|args| {
|
||||
let nums: Vec<i64> = args
|
||||
.iter()
|
||||
.map(|a| match a {
|
||||
Value::Number(a) => Ok(*a),
|
||||
_ => Err(eyre!("Should be a number")),
|
||||
})
|
||||
.flatten()
|
||||
.collect();
|
||||
let total = nums
|
||||
.into_iter()
|
||||
.reduce(|acc, e| acc + e)
|
||||
.expect("shouldn't fail");
|
||||
Ok(Value::from(total))
|
||||
}),
|
||||
);
|
||||
env.insert_symbol(
|
||||
Symbol::from("-"),
|
||||
Value::func(|args| {
|
||||
let nums: Vec<i64> = args
|
||||
.iter()
|
||||
.map(|a| match a {
|
||||
Value::Number(a) => Ok(*a),
|
||||
_ => Err(eyre!("Should be a number")),
|
||||
})
|
||||
.flatten()
|
||||
.collect();
|
||||
let total = nums
|
||||
.into_iter()
|
||||
.reduce(|acc, n| acc - n)
|
||||
.expect("shouldn't fail");
|
||||
Ok(Value::from(total))
|
||||
}),
|
||||
);
|
||||
|
||||
loop {
|
||||
let entry = rl.readline(">> ");
|
||||
match entry {
|
||||
Ok(line) => {
|
||||
rl.add_history_entry(line.as_str())?;
|
||||
match read_eval_print(line.as_str(), &mut env) {
|
||||
Ok(s) => println!("{s}"),
|
||||
Err(e) => eprintln!("{e}"),
|
||||
}
|
||||
}
|
||||
Err(ReadlineError::Interrupted) => {
|
||||
println!("CTRL-C");
|
||||
break;
|
||||
}
|
||||
Err(ReadlineError::Eof) => {
|
||||
println!("CTRL-D");
|
||||
break;
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error: {:?}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_eval_print(str: &str, env: &mut Environment) -> Result<String> {
|
||||
Ok(print(&eval(&read(str), env)?))
|
||||
}
|
||||
|
||||
pub fn eval(expr: &Value, env: &mut Environment) -> Result<Value> {
|
||||
match expr {
|
||||
Value::Symbol(s) => {
|
||||
let symbol = env.get_symbol(s).to_owned();
|
||||
Ok(symbol)
|
||||
}
|
||||
Value::List(list) => {
|
||||
let mut args = vec![];
|
||||
let first = &list[0];
|
||||
if let Value::List(_) = first {
|
||||
eval(first, env)
|
||||
} else if let Value::Symbol(s) = first {
|
||||
if s == &Symbol("defvar".to_string()) {
|
||||
let second = &list[1];
|
||||
if let Value::Symbol(s) = second {
|
||||
Ok(Value::Symbol(s.clone()))
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
} else if s == &Symbol("let*".to_string()) {
|
||||
todo!()
|
||||
} else {
|
||||
let first = eval(first, env)?;
|
||||
for value in list.iter().skip(1) {
|
||||
if let Ok(return_value) = eval(value, env) {
|
||||
args.push(return_value)
|
||||
}
|
||||
}
|
||||
first.apply(args)
|
||||
}
|
||||
} else {
|
||||
let first = eval(first, env)?;
|
||||
for value in list.iter().skip(1) {
|
||||
if let Ok(return_value) = eval(value, env) {
|
||||
args.push(return_value)
|
||||
}
|
||||
}
|
||||
first.apply(args)
|
||||
}
|
||||
}
|
||||
value => Ok(value.to_owned()),
|
||||
}
|
||||
}
|
13
src/main.rs
13
src/main.rs
|
@ -104,6 +104,19 @@ fn eval(expr: &Value, env: &Environment) -> Result<Value> {
|
|||
let first = &list[0];
|
||||
if let Value::List(_) = first {
|
||||
eval(first, env)
|
||||
} else if let Value::Symbol(s) = first {
|
||||
if s == &Symbol("defvar".to_string()) {
|
||||
let second = &list[1];
|
||||
if let Value::Symbol(s) = second {
|
||||
Ok(Value::Symbol(s.clone()))
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
} else if s == &Symbol("let*".to_string()) {
|
||||
todo!()
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
} else {
|
||||
let first = eval(first, env)?;
|
||||
for value in list.iter().skip(1) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue