Adding some info functions and tests

This commit is contained in:
teo3300
2024-04-16 09:35:35 +09:00
parent 5c9aa39750
commit 0ec8923abc
10 changed files with 108 additions and 9 deletions

View File

@ -1,4 +1,5 @@
use std::env;
use std::rc::Rc;
use crate::env::{any_zero, arithmetic_op, car, comparison_op, env_new, env_set, mal_exit, Env};
@ -34,7 +35,7 @@ macro_rules! env_init {
use crate::parse_tools::read_file;
use crate::printer::pr_str;
use crate::reader::{read_str, Reader};
use crate::types::MalType::{Fun, Int, List, Nil, Str};
use crate::types::MalType::{Atom, Fun, Int, List, Nil, Str};
use crate::types::{mal_assert, mal_equals, MalErr};
pub fn ns_init() -> Env {
@ -62,6 +63,8 @@ pub fn ns_init() -> Env {
"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"),
"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"),
"deref" => Fun(|a| Ok(car(a)?.if_atom()?.clone()), "Return the content of the atom argumet"),
"env" => Fun(|a| match env::var(car(a)?.if_string()?) {
Ok(s) => Ok(Str(s.into())),
_ => Ok(Nil),

View File

@ -21,6 +21,7 @@ forms!(NAME_DEF : "def!",
NAME_FN : "fn*",
NAME_FN_ALT : "λ",
NAME_HELP : "help",
NAME_HELP_ALT: "h",
NAME_FIND : "find",
NAME_QUOTE : "quote",
NAME_OK : "ok?",
@ -188,7 +189,7 @@ pub fn eval(ast: &MalType, env: Env) -> MalRet {
NAME_FN | NAME_FN_ALT /* :) */ => {
return fn_star_form(args, env.clone())
}
NAME_HELP => return help_form(args, env.clone()),
NAME_HELP | NAME_HELP_ALT => return help_form(args, env.clone()),
NAME_FIND => return find_form(args, env.clone()),
// Oh God, what have I done
NAME_QUOTE => return Ok(car(args)?.clone()),

View File

@ -45,4 +45,14 @@ mod functional {
fn forms() {
test!("forms")
}
#[test]
fn lists() {
test!("lists")
}
#[test]
fn atoms() {
test!("atoms")
}
}

View File

@ -92,7 +92,7 @@ pub fn interactive(env: Env) {
// // Read line to compose program input
// let mut line = String::new();
// io::stdin().read_line(&mut line).unwrap();
let line = rl.readline("user> ");
let line = rl.readline("; user> ");
match line {
Ok(line) => {
@ -105,7 +105,7 @@ pub fn interactive(env: Env) {
// Perform rep on whole available input
match rep(&parser, &env) {
Ok(output) => output.iter().for_each(|el| eprintln!("[{}]> {}", num, el)),
Ok(output) => output.iter().for_each(|el| println!("; [{}]> {}", num, el)),
Err(error) => {
if error.is_recoverable() {
// && line != "\n" {

View File

@ -53,6 +53,7 @@ pub fn pr_str(ast: &MalType, print_readably: bool) -> String {
),
M::Fun(..) => "#<builtin>".to_string(),
M::MalFun { .. } => "#<function>".to_string(),
M::Atom(sub) => format!("Atom({})", pr_str(sub, print_readably)),
}
}
@ -61,7 +62,7 @@ pub fn prt(ast: &MalType) -> String {
}
pub fn print_malfun(sym: &str, params: Rc<MalType>, ast: Rc<MalType>) {
println!("{}\t[function]: {}", sym, prt(&params));
println!("; {}\t[function]: {}", sym, prt(&params));
ast.as_ref()
.if_list()
.unwrap_or(&[])

View File

@ -25,6 +25,7 @@ pub enum MalType {
Str(MalStr),
Int(isize),
Bool(bool),
Atom(Rc<MalType>),
Nil,
}
@ -74,6 +75,15 @@ 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 {
Key(match self {
M::Nil => "ʞ:nil",
@ -83,9 +93,10 @@ impl MalType {
M::Key(_) => "ʞ:key",
M::Str(_) => "ʞ:string",
M::Sym(_) => "ʞ:symbol",
M::List(_) => "ʞ:ist",
M::List(_) => "ʞ:list",
M::Vector(_) => "ʞ:vector",
M::Map(_) => "ʞ:map",
M::Atom(_) => "ʞ:atom",
}
.into())
}