Better? type management

Signed-off-by: teo3300 <matteo.rogora@live.it>
This commit is contained in:
teo3300
2023-11-15 18:25:38 +09:00
parent 3c5b03a2a8
commit 0e85435635
5 changed files with 66 additions and 86 deletions

View File

@ -35,25 +35,16 @@ pub fn call_func(func: &MalType, args: &[MalType]) -> MalRet {
}
}
fn if_number(val: &MalType) -> Result<isize, MalErr> {
match val {
Int(val) => Ok(*val),
_ => Err(MalErr::unrecoverable(
format!("{:?} is not a number", prt(val)).as_str(),
)),
}
}
pub fn arithmetic_op(set: isize, f: fn(isize, isize) -> isize, args: &[MalType]) -> MalRet {
if args.is_empty() {
return Ok(Int(set));
}
let mut left = if_number(&args[0])?;
let mut left = args[0].if_number()?;
if args.len() > 1 {
let right = &args[1..];
for el in right {
left = f(left, if_number(el)?);
left = f(left, el.if_number()?);
}
}
@ -64,9 +55,9 @@ use MalType::{Bool, Nil};
pub fn comparison_op(f: fn(isize, isize) -> bool, args: &[MalType]) -> MalRet {
let (left, rights) = car_cdr(args)?;
let mut left = if_number(left)?;
let mut left = left.if_number()?;
for right in rights {
let right = if_number(right)?;
let right = right.if_number()?;
if !f(left, right) {
return Ok(Nil);
}

View File

@ -1,5 +1,5 @@
use crate::core::{arithmetic_op, comparison_op, core_exit};
use crate::types::{MalErr, MalType::*};
use crate::types::MalErr;
use crate::types::{MalMap, MalRet, MalType};
use std::cell::RefCell;
use std::rc::Rc;
@ -54,7 +54,7 @@ pub fn env_set(env: &Env, sym: &str, val: &MalType) -> MalType {
val.clone()
}
pub fn env_get(env: &Env, sym: &String) -> MalRet {
pub fn env_get(env: &Env, sym: &str) -> MalRet {
match env.data.borrow().get(sym) {
Some(val) => Ok(val.clone()),
None => match env.outer.clone() {
@ -66,32 +66,17 @@ pub fn env_get(env: &Env, sym: &String) -> MalRet {
}
}
use crate::printer::prt;
pub fn env_binds(outer: Env, binds: &MalType, exprs: &[MalType]) -> Result<Env, MalErr> {
let env = env_new(Some(outer));
match binds {
List(binds) => {
if binds.len() != exprs.len() {
return Err(MalErr::unrecoverable("Env init with unmatched length"));
} // TODO: May be possible to leave this be and not set additional elements at all
for (bind, expr) in binds.iter().zip(exprs.iter()) {
match bind {
Sym(sym) => {
env_set(&env, sym, expr);
}
_ => {
return Err(MalErr::unrecoverable(
format!("Initializing environment: {:?} is not a symbol", prt(bind))
.as_str(),
))
}
}
}
Ok(env)
}
_ => Err(MalErr::unrecoverable("init: first argument must be a list")),
let binds = binds.if_list()?;
if binds.len() != exprs.len() {
return Err(MalErr::unrecoverable("Wrong number of arguments"));
} // TODO: May be possible to leave this be and not set additional elements at all
for (bind, expr) in binds.iter().zip(exprs.iter()) {
let bind = bind.if_symbol()?;
env_set(&env, bind, expr);
}
Ok(env)
}
use crate::types::MalType::{Fun, Str};

View File

@ -1,6 +1,6 @@
use std::rc::Rc;
use crate::core::{call_func, car_cdr, scream};
use crate::core::{call_func, car_cdr};
use crate::env::Env;
use crate::env::{env_get, env_new, env_set};
use crate::printer::prt;
@ -10,13 +10,9 @@ use crate::types::{MalArgs, MalErr, MalMap, MalRet, MalType};
/// Resolve the first element of the list as the function name and call it
/// with the other elements as arguments
fn eval_func(list: &MalType) -> MalRet {
match list {
List(list) => {
let (func, args) = car_cdr(list)?;
call_func(func, args)
}
_ => scream(),
}
let list = list.if_list()?;
let (func, args) = car_cdr(list)?;
call_func(func, args)
}
// When evaluating an expression it's possible
@ -35,17 +31,9 @@ fn def_bang_form(list: &[MalType], env: Env) -> MalRet {
if list.len() != 2 {
return Err(MalErr::unrecoverable("def! form: needs 2 arguments"));
}
match &list[0] {
Sym(sym) => Ok(env_set(&env, sym.as_str(), &eval(&list[1], env.clone())?)),
_ => Err(MalErr::unrecoverable(
format!(
"def! Assigning {:?} to {:?}, which is not a symbol",
prt(&list[1]),
prt(&list[0])
)
.as_str(),
)),
}
let (car, _) = car_cdr(list)?;
let sym = car.if_symbol()?;
Ok(env_set(&env, sym, &eval(&list[1], env.clone())?))
}
/// let* special form:
@ -56,22 +44,20 @@ fn let_star_form(list: &[MalType], env: Env) -> MalRet {
let inner_env = env_new(Some(env.clone()));
// change the inner environment
let (car, cdr) = car_cdr(list)?;
match car {
List(list) if list.len() % 2 == 0 => {
// TODO: Find a way to avoid index looping that is ugly
for i in (0..list.len()).step_by(2) {
def_bang_form(&list[i..=i + 1], inner_env.clone())?;
}
if cdr.is_empty() {
// TODO: check if it exists a better way to do this
Ok(Nil)
} else {
eval(&cdr[0], inner_env)
}
let list = car.if_list()?;
if list.len() % 2 == 0 {
// TODO: Find a way to avoid index looping that is ugly
for i in (0..list.len()).step_by(2) {
def_bang_form(&list[i..=i + 1], inner_env.clone())?;
}
_ => Err(MalErr::unrecoverable(
"First argument of let* must be a list of pair definitions",
)),
if cdr.is_empty() {
// TODO: check if it exists a better way to do this
Ok(Nil)
} else {
eval(&cdr[0], inner_env)
}
} else {
Err(MalErr::unrecoverable("let* form, number of arguments must be even"))
}
}
@ -118,20 +104,13 @@ use crate::printer::print_malfun;
pub fn help_form(list: &[MalType], env: Env) -> MalRet {
let (sym, _) = car_cdr(list)?;
match car_cdr(list)?.0 {
Sym(sym_str) => {
match eval(sym, env.clone())? {
Fun(_, desc) => println!("{}\t[builtin]: {}", sym_str, desc),
MalFun { params, ast, .. } => print_malfun(sym_str, params, ast),
_ => println!("{}\t[symbol]: {}", sym_str, prt(&env_get(&env, sym_str)?)),
}
Ok(Bool(true))
}
_ => {
println!("{} is not a symbol", prt(sym));
Ok(Nil)
}
let sym_str = sym.if_symbol()?;
match eval(sym, env.clone())? {
Fun(_, desc) => println!("{}\t[builtin]: {}", sym_str, desc),
MalFun { params, ast, .. } => print_malfun(sym_str, params, ast),
_ => println!("{}\t[symbol]: {}", sym_str, prt(&env_get(&env, sym_str)?)),
}
Ok(Bool(true))
}
/// Intermediate function to discern special forms from defined symbols

View File

@ -49,7 +49,7 @@ pub fn prt(ast: &MalType) -> String {
pr_str(ast, true)
}
pub fn print_malfun(sym: &String, params: Rc<MalType>, ast: Rc<MalType>) {
pub fn print_malfun(sym: &str, params: Rc<MalType>, ast: Rc<MalType>) {
println!("{}\t[function]: {}", sym, prt(&params));
match ast.as_ref() {
List(list) => {

View File

@ -23,6 +23,31 @@ pub enum MalType {
Nil,
}
impl MalType {
pub fn if_number(&self) -> Result<isize, MalErr> {
match self {
Self::Int(val) => Ok(*val),
_ => Err(MalErr::unrecoverable(
format!("{:?} is not a number", prt(self)).as_str(),
)),
}
}
pub fn if_list(&self) -> Result<&[MalType], MalErr> {
match self {
Self::List(list) => Ok(list),
_ => Err(MalErr::unrecoverable(format!("{:?} is not a list", prt(self)).as_str()))
}
}
pub fn if_symbol(&self) -> Result<&str, MalErr> {
match self {
Self::Sym(sym) => Ok(sym),
_ => Err(MalErr::unrecoverable(format!("{:?} is not a symbol", prt(self)).as_str()))
}
}
}
#[derive(PartialEq, Clone, Copy)]
pub enum Severity {
Recoverable,