Skip to content

Commit

Permalink
feat: completed a demo of mani :)
Browse files Browse the repository at this point in the history
  • Loading branch information
algebraic-dev committed Jul 2, 2023
1 parent 0f4e3fe commit 6210a1e
Show file tree
Hide file tree
Showing 19 changed files with 848 additions and 224 deletions.
1 change: 1 addition & 0 deletions soft-interpreter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ fxhash = "0.2.1"
im-rc = "15.1.0"
libc = "0.2.146"
pathdiff = "0.2.1"
rustyline = "12.0.0"
thiserror = "1.0.40"
unescape = "0.1.0"
47 changes: 38 additions & 9 deletions soft-interpreter/src/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ impl Frame {
.cloned()
}

pub fn set(&mut self, id: &str, value: Value) -> Option<Value> {
for stack in self.stack.iter_mut().rev() {
if let Some(old) = stack.remove(id) {
stack.insert(id.to_string(), value);
return Some(old);
}
}
None
}

/// Inserts a variable in the current frame.
pub fn insert(&mut self, id: String, value: Value) {
self.stack.back_mut().unwrap().insert(id, value);
Expand All @@ -50,6 +60,11 @@ impl Frame {
self.stack.push_back(im_rc::HashMap::new());
}

/// Pushes a new scope in the current frame.
pub fn child(&mut self, hashmap: im_rc::HashMap<String, Value>) {
self.stack.push_back(hashmap);
}

/// Pops the current scope from the current frame.
pub fn pop(&mut self) {
self.stack.pop_back();
Expand Down Expand Up @@ -93,7 +108,7 @@ impl Environment {
};

Self {
frames: vec![Frame::new(None, false, start.clone())],
frames: vec![Frame::new(None, true, start.clone())],
expanded: false,
global: Expr::HashMap(Default::default()).into(),
location: start,
Expand All @@ -116,23 +131,26 @@ impl Environment {
self.register_external("tail", intrinsics::tail);
self.register_external("cons", intrinsics::cons);
self.register_external("list", intrinsics::list);
self.register_external("match", intrinsics::match_);

self.register_external("read", intrinsics::read);
self.register_external("flush", intrinsics::flush);
self.register_external("print", intrinsics::print);
self.register_external("read-file", intrinsics::read_file);
self.register_external("parse", intrinsics::parse);
self.register_external("import", intrinsics::import);
self.register_external("while", intrinsics::while_);

self.register_external("and", intrinsics::and);
self.register_external("or", intrinsics::or);

self.register_external("fn*", intrinsics::fn_);
self.register_external("if", intrinsics::if_);
self.register_external("let", intrinsics::letm);
self.register_external("set", intrinsics::setm);
self.register_external("letrec", intrinsics::letrec);
self.register_external("set*", intrinsics::set);
self.register_external("setm*", intrinsics::setm);
self.register_external("setm*", intrinsics::set_macro);
self.register_external("quote", intrinsics::quote);
self.register_external("expand", intrinsics::expand);
self.register_external("block", intrinsics::block);
Expand Down Expand Up @@ -169,11 +187,12 @@ impl Environment {
self.register_external("vec", intrinsics::vec);

self.register_external("hash-map", intrinsics::hash_map);
self.register_external("hash-map/get", intrinsics::hash_map_get);
self.register_external("hash-map/set!", intrinsics::hash_map_set);
self.register_external("hash-map/keys", intrinsics::hash_map_keys);
self.register_external("hash-map/vals", intrinsics::hash_map_vals);
self.register_external("hash-map/len", intrinsics::hash_map_len);
self.register_external("map/get", intrinsics::hash_map_get);
self.register_external("map/set!", intrinsics::hash_map_set);
self.register_external("map/remove!", intrinsics::hash_map_remove);
self.register_external("map/keys", intrinsics::hash_map_keys);
self.register_external("map/vals", intrinsics::hash_map_vals);
self.register_external("map/len", intrinsics::hash_map_len);

self.register_external("string/len", intrinsics::string_length);
self.register_external("string/slice", intrinsics::string_slice);
Expand All @@ -187,7 +206,9 @@ impl Environment {

self.register_external("to-string", intrinsics::to_string);
self.register_external("to-int", intrinsics::to_int);
self.register_external("to-id", intrinsics::to_id);
self.register_external("to-atom", intrinsics::to_atom);
self.register_external("clone", intrinsics::clone);

self.register_external("try*", intrinsics::try_);
self.register_external("throw", intrinsics::throw);
Expand All @@ -202,10 +223,18 @@ impl Environment {
.last()
.unwrap()
.find(id)
.ok_or_else(|| RuntimeError::UndefinedName(id.to_owned()))
.ok_or_else(|| RuntimeError::from(format!("undefined name: {}", id)))
.or_else(|_| self.get_def(id).map(|x| x.value))
}

pub fn set(&mut self, id: &str, value: Value) -> Result<Value, RuntimeError> {
self.frames
.last_mut()
.unwrap()
.set(id, value)
.ok_or_else(|| RuntimeError::from(format!("undefined name: {}", id)))
}

pub fn get_def(&self, id: &str) -> Result<Def, RuntimeError> {
let Expr::HashMap(ref mut map) = self.global.clone().borrow_mut().kind else {
return Err(RuntimeError::from(
Expand All @@ -216,7 +245,7 @@ impl Environment {
let value = map
.get(id)
.map(|x| x.1.clone())
.ok_or_else(|| RuntimeError::UndefinedName(id.to_owned()))?
.ok_or_else(|| RuntimeError::from(format!("undefined name: {}", id)))?
.assert_vector()?;

if value.len() >= 3 {
Expand Down
6 changes: 0 additions & 6 deletions soft-interpreter/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,6 @@ use crate::value::{Expr, Location, Value};

#[derive(Error, Debug, Clone)]
pub enum RuntimeError {
#[error("undefined name '{0}'")]
UndefinedName(String),

#[error("cannot call as function '{0}'")]
NotCallable(Value),

#[error("unmatched parenthesis")]
UnmatchedParenthesis(Location),

Expand Down
7 changes: 5 additions & 2 deletions soft-interpreter/src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,10 @@ impl Closure {
}
}
_ => {
return Err(RuntimeError::NotCallable(ret_head));
return Err(RuntimeError::from(format!(
"not callable: {}",
ret_head
)))
}
};
}
Expand Down Expand Up @@ -165,7 +168,7 @@ impl Value {
Ok(res) => Ok(res),
Err(err) => Err(err),
},
_ => Err(RuntimeError::NotCallable(head)),
_ => Err(RuntimeError::from(format!("not callable: {}", head))),
}
}
_ => Ok(Trampoline::Return(self)),
Expand Down
9 changes: 7 additions & 2 deletions soft-interpreter/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::{
environment::Environment,
error::RuntimeError::{ExpectedList, NotCallable},
error::RuntimeError::{self, ExpectedList},
value::{
Expr::{Cons, Function, Id},
Value,
Expand Down Expand Up @@ -41,7 +41,12 @@ impl Value {
return Err(err);
}
},
_ => return Err(NotCallable(head.value.clone())),
_ => {
return Err(RuntimeError::from(format!(
"not callable: {}",
head.value.clone()
)))
}
}
}
_ => return Ok(expr),
Expand Down
14 changes: 13 additions & 1 deletion soft-interpreter/src/intrinsics/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ pub fn letm(scope: CallScope<'_>) -> Result<Trampoline> {
Ok(Trampoline::returning(Expr::Nil))
}

/// set : id -> a -> nil
pub fn setm(scope: CallScope<'_>) -> Result<Trampoline> {
scope.assert_arity(2)?;

let name = scope.at(0).assert_identifier()?;
let value = scope.at(1).run(scope.env)?;

scope.env.set(&name, value)?;

Ok(Trampoline::returning(Expr::Nil))
}

/// set : id -> a -> nil
pub fn letrec(scope: CallScope<'_>) -> Result<Trampoline> {
scope.assert_arity(2)?;
Expand Down Expand Up @@ -44,7 +56,7 @@ pub fn set(scope: CallScope<'_>) -> Result<Trampoline> {
}

/// setm : id -> a -> nil
pub fn setm(scope: CallScope<'_>) -> Result<Trampoline> {
pub fn set_macro(scope: CallScope<'_>) -> Result<Trampoline> {
scope.assert_arity(2)?;

let name = scope.at(0).assert_identifier()?;
Expand Down
17 changes: 17 additions & 0 deletions soft-interpreter/src/intrinsics/hashmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,23 @@ pub fn hash_map_set(scope: CallScope<'_>) -> Result<Trampoline> {
}
}

pub fn hash_map_remove(scope: CallScope<'_>) -> Result<Trampoline> {
scope.assert_arity(2)?;

let map = scope.at(0).run(scope.env)?;
let key = scope.at(1).run(scope.env)?;

let borrow = map.borrow_mut();

match borrow.kind {
Expr::HashMap(ref mut map) => {
map.remove(&key.stringify());
Ok(Trampoline::returning(Expr::Nil))
}
_ => Err(RuntimeError::from("expected hash-map")),
}
}

pub fn hash_map_keys(scope: CallScope<'_>) -> Result<Trampoline> {
scope.assert_arity(1)?;

Expand Down
40 changes: 31 additions & 9 deletions soft-interpreter/src/intrinsics/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,21 +74,31 @@ pub fn import(scope: CallScope<'_>) -> Result<Trampoline> {
.location
.file
.clone()
.map(PathBuf::from)
.unwrap_or_else(|| std::env::current_dir().unwrap());
.map(|str| {
if str == "<repl>" {
std::env::current_dir().unwrap()
} else {
let mut cwd = PathBuf::from(str);
cwd.pop();
cwd
}
})
.unwrap();

let path = scope.at(0).assert_string()?;
cwd.pop();

cwd.push(path);

let cwd = cwd.canonicalize().unwrap();
let Ok(cwd) = cwd.canonicalize() else {
let msg = format!("cannot find file '{}'", cwd.display());
return Err(RuntimeError::UserError(Value::from(Expr::Str(msg))))
};

if scope.env.imported_files.contains(&cwd) {
return Ok(Trampoline::returning(Expr::Nil));
} else {
scope.env.imported_files.insert(cwd.clone());
}
// if scope.env.imported_files.contains(&cwd) {
// return Ok(Trampoline::returning(Expr::Nil));
// } else {
// scope.env.imported_files.insert(cwd.clone());
// }

let cwd = pathdiff::diff_paths(cwd, std::env::current_dir().unwrap()).unwrap();

Expand All @@ -105,3 +115,15 @@ pub fn import(scope: CallScope<'_>) -> Result<Trampoline> {

Ok(Trampoline::returning(Expr::Nil))
}

pub fn while_(scope: CallScope<'_>) -> Result<Trampoline> {
scope.assert_arity(2)?;

let mut result = Expr::Nil.into();

while scope.at(0).run(scope.env)?.to_bool() {
result = scope.at(1).run(scope.env)?;
}

Ok(Trampoline::returning(result))
}
Loading

0 comments on commit 6210a1e

Please sign in to comment.