Implemented Atom type

Only functions available
- atom
- deref (aliased as @)
- reset!
This commit is contained in:
teo3300
2024-05-24 17:31:15 +09:00
parent 0ec8923abc
commit 06adb25362
5 changed files with 49 additions and 31 deletions

5
.gitignore vendored
View File

@ -7,4 +7,7 @@ src/#*
src/*~ src/*~
# history file # history file
.mal-history .mal-history
# stupid macos
.DS_Store

View File

@ -1,5 +1,4 @@
use std::env; use std::{cell::RefCell, env, rc::Rc};
use std::rc::Rc;
use crate::env::{any_zero, arithmetic_op, car, comparison_op, env_new, env_set, mal_exit, Env}; use crate::env::{any_zero, arithmetic_op, car, comparison_op, env_new, env_set, mal_exit, Env};
@ -36,7 +35,7 @@ use crate::parse_tools::read_file;
use crate::printer::pr_str; use crate::printer::pr_str;
use crate::reader::{read_str, Reader}; use crate::reader::{read_str, Reader};
use crate::types::MalType::{Atom, Fun, Int, List, Nil, Str}; use crate::types::MalType::{Atom, Fun, Int, List, Nil, Str};
use crate::types::{mal_assert, mal_equals, MalErr}; use crate::types::{mal_assert, mal_equals, reset_bang, MalErr};
pub fn ns_init() -> Env { pub fn ns_init() -> Env {
env_init!(None, env_init!(None,
@ -63,8 +62,9 @@ pub fn ns_init() -> Env {
"assert" => Fun(mal_assert, "Return an error if assertion fails"), "assert" => Fun(mal_assert, "Return an error if assertion fails"),
"read-string" => Fun(|a| read_str(Reader::new().push(car(a)?.if_string()?)).map_err(MalErr::severe), "Tokenize and read the first argument"), "read-string" => Fun(|a| read_str(Reader::new().push(car(a)?.if_string()?)).map_err(MalErr::severe), "Tokenize and read the first argument"),
"slurp" => Fun(|a| Ok(Str(read_file(car(a)?.if_string()?)?)), "Read a file and return the content as a string"), "slurp" => Fun(|a| Ok(Str(read_file(car(a)?.if_string()?)?)), "Read a file and return the content as a string"),
"atom" => Fun(|a| Ok(Atom(Rc::new(car(a)?.clone()))), "Return an atom pointing to the given arg"), "atom" => Fun(|a| Ok(Atom(Rc::new(RefCell::new(car(a)?.clone())))), "Return an atom pointing to the given arg"),
"deref" => Fun(|a| Ok(car(a)?.if_atom()?.clone()), "Return the content of the atom argumet"), "deref" => Fun(|a| match car(a)? { Atom(a) => Ok(a.borrow().clone()), _ => todo!("Cacca suprema") }, "Return the content of the atom argumet"),
"reset!" => Fun(reset_bang, "Set the value of the first argument to the second argument"),
"env" => Fun(|a| match env::var(car(a)?.if_string()?) { "env" => Fun(|a| match env::var(car(a)?.if_string()?) {
Ok(s) => Ok(Str(s.into())), Ok(s) => Ok(Str(s.into())),
_ => Ok(Nil), _ => Ok(Nil),

View File

@ -53,7 +53,7 @@ pub fn pr_str(ast: &MalType, print_readably: bool) -> String {
), ),
M::Fun(..) => "#<builtin>".to_string(), M::Fun(..) => "#<builtin>".to_string(),
M::MalFun { .. } => "#<function>".to_string(), M::MalFun { .. } => "#<function>".to_string(),
M::Atom(sub) => format!("Atom({})", pr_str(sub, print_readably)), M::Atom(sub) => format!("Atom({})", pr_str(&sub.borrow(), print_readably)),
} }
} }

View File

@ -133,6 +133,13 @@ impl Reader {
self.read_form()?, self.read_form()?,
]))) ])))
} }
"@" => {
self.next()?;
Ok(List(Rc::new([
MalType::Sym("deref".into()),
self.read_form()?,
])))
}
_ => self.read_atom(), _ => self.read_atom(),
} }
} }

View File

@ -1,5 +1,5 @@
use crate::env::{car_cdr, Env}; use crate::env::{car_cdr, Env};
use std::{collections::HashMap, rc::Rc}; use std::{cell::RefCell, collections::HashMap, rc::Rc};
pub type MalStr = Rc<str>; pub type MalStr = Rc<str>;
pub type MalArgs = Rc<[MalType]>; pub type MalArgs = Rc<[MalType]>;
@ -25,7 +25,7 @@ pub enum MalType {
Str(MalStr), Str(MalStr),
Int(isize), Int(isize),
Bool(bool), Bool(bool),
Atom(Rc<MalType>), Atom(Rc<RefCell<MalType>>),
Nil, Nil,
} }
@ -75,29 +75,21 @@ impl MalType {
} }
} }
pub fn if_atom(&self) -> Result<&MalType, MalErr> {
match self {
Self::Atom(sym) => Ok(sym),
_ => Err(MalErr::unrecoverable(
format!("{:?} is not an atom", prt(self)).as_str(),
)),
}
}
pub fn label_type(&self) -> MalType { pub fn label_type(&self) -> MalType {
Key(match self { Key(("ʞ:".to_owned()
M::Nil => "ʞ:nil", + match self {
M::Bool(_) => "ʞ:bool", M::Nil => "nil",
M::Int(_) => "ʞ:int", M::Bool(_) => "bool",
M::Fun(_, _) | M::MalFun { .. } => "ʞ:lambda", M::Int(_) => "int",
M::Key(_) => "ʞ:key", M::Fun(_, _) | M::MalFun { .. } => "lambda",
M::Str(_) => "ʞ:string", M::Key(_) => "key",
M::Sym(_) => "ʞ:symbol", M::Str(_) => "string",
M::List(_) => "ʞ:list", M::Sym(_) => "symbol",
M::Vector(_) => "ʞ:vector", M::List(_) => "list",
M::Map(_) => "ʞ:map", M::Vector(_) => "vector",
M::Atom(_) => "ʞ:atom", M::Map(_) => "map",
} M::Atom(_) => "atom",
})
.into()) .into())
} }
} }
@ -135,6 +127,22 @@ pub fn mal_assert(args: &[MalType]) -> MalRet {
Ok(M::Nil) Ok(M::Nil)
} }
pub fn reset_bang(args: &[MalType]) -> MalRet {
if args.len() < 2 {
return Err(MalErr::unrecoverable("reset requires two arguments"));
}
let val = &args[1];
match &args[0] {
M::Atom(sym) => {
*std::cell::RefCell::<_>::borrow_mut(sym) = val.clone();
Ok(val.clone())
}
_ => Err(MalErr::unrecoverable(
format!("{:?} is not an atom", prt(&args[1])).as_str(),
)),
}
}
#[derive(PartialEq, Clone, Copy, Debug)] #[derive(PartialEq, Clone, Copy, Debug)]
pub enum Severity { pub enum Severity {
Recoverable, Recoverable,