function refactoring

This commit is contained in:
TriMill 2022-09-14 11:16:53 -04:00
parent ef5124ba0f
commit 9c2a24c2d9
4 changed files with 147 additions and 112 deletions

View file

@ -152,7 +152,7 @@ pub fn eval_stmt(stmt: &Stmt, env: EnvRef) -> Result<(), Unwind> {
}, },
Stmt::Fn { name, args, body } => { Stmt::Fn { name, args, body } => {
let name = name.ty.clone().as_ident().unwrap(); let name = name.ty.clone().as_ident().unwrap();
let func = Func { let func = Func::Func {
name: Some(name.clone()), name: Some(name.clone()),
args: args.into_iter().map(|a| a.ty.clone().as_ident().unwrap()).collect(), args: args.into_iter().map(|a| a.ty.clone().as_ident().unwrap()).collect(),
env: env.clone(), env: env.clone(),
@ -208,7 +208,7 @@ pub fn eval_expr(expr: &Expr, env: EnvRef) -> Result<Value, RuntimeError> {
l.index(&idx).map_err(|e| RuntimeError::new(e, pos.clone())) l.index(&idx).map_err(|e| RuntimeError::new(e, pos.clone()))
}, },
Expr::Fn { args, body } => { Expr::Fn { args, body } => {
let func = Func { let func = Func::Func {
name: None, name: None,
args: args.into_iter().map(|a| a.ty.clone().as_ident().unwrap()).collect(), args: args.into_iter().map(|a| a.ty.clone().as_ident().unwrap()).collect(),
env: env.clone(), env: env.clone(),

View file

@ -69,6 +69,7 @@ impl RuntimeError {
} }
} }
impl fmt::Display for ParserError { impl fmt::Display for ParserError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Error: {}\n In {} at {},{}\n", write!(f, "Error: {}\n In {} at {},{}\n",

View file

@ -2,32 +2,32 @@ use std::{rc::Rc, io::Write, cmp::Ordering};
use num_traits::ToPrimitive; use num_traits::ToPrimitive;
use crate::{value::{Value, BuiltinFunc}, eval::Environment}; use crate::{value::{Value, Func}, eval::Environment};
pub fn load(env: &mut Environment) { pub fn load(env: &mut Environment) {
let mut name: Rc<str>; let mut name: Rc<str>;
name = Rc::from("str"); name = Rc::from("str");
env.declare(name.clone(), Value::BuiltinFunc(BuiltinFunc { func: fn_str, arg_count: 1, name })); env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_str, arg_count: 1, name }));
name = Rc::from("repr"); name = Rc::from("repr");
env.declare(name.clone(), Value::BuiltinFunc(BuiltinFunc { func: fn_repr, arg_count: 1, name })); env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_repr, arg_count: 1, name }));
name = Rc::from("print"); name = Rc::from("print");
env.declare(name.clone(), Value::BuiltinFunc(BuiltinFunc { func: fn_print, arg_count: 1, name })); env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_print, arg_count: 1, name }));
name = Rc::from("println"); name = Rc::from("println");
env.declare(name.clone(), Value::BuiltinFunc(BuiltinFunc { func: fn_println, arg_count: 1, name })); env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_println, arg_count: 1, name }));
name = Rc::from("input"); name = Rc::from("input");
env.declare(name.clone(), Value::BuiltinFunc(BuiltinFunc { func: fn_input, arg_count: 0, name })); env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_input, arg_count: 0, name }));
name = Rc::from("ord"); name = Rc::from("ord");
env.declare(name.clone(), Value::BuiltinFunc(BuiltinFunc { func: fn_ord, arg_count: 1, name })); env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_ord, arg_count: 1, name }));
name = Rc::from("chr"); name = Rc::from("chr");
env.declare(name.clone(), Value::BuiltinFunc(BuiltinFunc { func: fn_chr, arg_count: 1, name })); env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_chr, arg_count: 1, name }));
name = Rc::from("range"); name = Rc::from("range");
env.declare(name.clone(), Value::BuiltinFunc(BuiltinFunc { func: fn_range, arg_count: 2, name })); env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_range, arg_count: 2, name }));
name = Rc::from("len"); name = Rc::from("len");
env.declare(name.clone(), Value::BuiltinFunc(BuiltinFunc { func: fn_len, arg_count: 1, name })); env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_len, arg_count: 1, name }));
name = Rc::from("re"); name = Rc::from("re");
env.declare(name.clone(), Value::BuiltinFunc(BuiltinFunc { func: fn_re, arg_count: 1, name })); env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_re, arg_count: 1, name }));
name = Rc::from("im"); name = Rc::from("im");
env.declare(name.clone(), Value::BuiltinFunc(BuiltinFunc { func: fn_im, arg_count: 1, name })); env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_im, arg_count: 1, name }));
} }
fn fn_str(args: Vec<Value>) -> Result<Value, String> { fn fn_str(args: Vec<Value>) -> Result<Value, String> {

View file

@ -8,62 +8,134 @@ pub type Rational = num_rational::Ratio<i64>;
pub type Complex = num_complex::Complex64; pub type Complex = num_complex::Complex64;
#[derive(Clone)] #[derive(Clone)]
pub struct BuiltinFunc { pub enum Func {
pub name: Rc<str>, Func {
pub func: fn(Vec<Value>) -> Result<Value, String>, name: Option<Rc<str>>,
pub arg_count: usize args: Vec<Rc<str>>,
} env: EnvRef,
func: Stmt
impl fmt::Debug for BuiltinFunc { },
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Builtin {
f.debug_struct("BuiltinFn").field("name", &self.name).field("arg_count", &self.arg_count).finish() name: Rc<str>,
func: fn(Vec<Value>) -> Result<Value, String>,
arg_count: usize
} }
} }
impl Iterator for BuiltinFunc {
type Item = Result<Value, String>;
fn next(&mut self) -> Option<Self::Item> {
// precondition: function takes zero arguments
match (self.func)(vec![]) {
Ok(Value::Nil) => None,
r => Some(r),
}
}
}
#[derive(Clone)]
pub struct Func {
pub name: Option<Rc<str>>,
pub args: Vec<Rc<str>>,
pub env: EnvRef,
pub func: Stmt
}
impl fmt::Debug for Func { impl fmt::Debug for Func {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Func") match self {
.field("name", &self.name) Self::Func { name, args, .. }
.field("args", &self.args) => f.debug_struct("Func::Func")
.field("func", &self.func) .field("name", name)
.finish_non_exhaustive() .field("args", args)
.finish_non_exhaustive(),
Self::Builtin { name, arg_count, .. }
=> f.debug_struct("Func::Builtin")
.field("name", name)
.field("arg_count", arg_count)
.finish_non_exhaustive(),
}
}
}
impl Func {
pub fn arg_count(&self) -> usize {
match self {
Self::Builtin { arg_count, .. } => *arg_count,
Self::Func { args, .. } => args.len()
}
}
pub fn call(&self, arg_values: Vec<Value>, pos: &Position) -> Result<Value, RuntimeError> {
match arg_values.len().cmp(&self.arg_count()) {
Ordering::Equal => match self {
Self::Builtin { func, .. }
=> func(arg_values).map_err(|e| RuntimeError::new(e, pos.clone())),
Self::Func { name, args, func, env } => {
let mut env = Environment::extend(env.clone());
for (k, v) in args.iter().zip(arg_values.iter()) {
env.declare(k.clone(), v.clone());
}
match eval_stmt(func, env.wrap()) {
Ok(()) => Ok(Value::Nil),
Err(Unwind::Return{ value, .. }) => Ok(value),
Err(e) => Err(e.as_error().exit_fn(name.clone(), pos.clone()))
}
}
}
Ordering::Less => Err(RuntimeError::new(
format!("Not enough arguments for function: expected {}, got {}", self.arg_count(), arg_values.len()),
pos.clone()
)),
Ordering::Greater => Err(RuntimeError::new(
format!("Too many arguments for function: expected {}, got {}", self.arg_count(), arg_values.len()),
pos.clone()
))
}
}
}
pub enum EitherRteOrString {
Rte(RuntimeError), String(String)
}
impl EitherRteOrString {
pub fn to_rte(self, pos: &Position) -> RuntimeError {
match self {
Self::Rte(e) => e,
Self::String(s) => RuntimeError::new(s, pos.clone())
}
}
}
impl From<String> for EitherRteOrString {
fn from(s: String) -> Self {
Self::String(s)
}
}
impl From<RuntimeError> for EitherRteOrString {
fn from(e: RuntimeError) -> Self {
Self::Rte(e)
} }
} }
impl Iterator for Func { impl Iterator for Func {
type Item = Result<Value, RuntimeError>; type Item = Result<Value, EitherRteOrString>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
// precondition: function takes zero arguments match self {
let env = Environment::extend(self.env.clone()).wrap(); Self::Builtin { func, .. } => match (func)(vec![]) {
match eval_stmt(&self.func, env) { Ok(Value::Nil) => None,
r => Some(r.map_err(|e| e.into())),
},
Self::Func { func, env, .. } => {
let env = Environment::extend(env.clone()).wrap();
match eval_stmt(&func, env) {
Ok(_) => None, Ok(_) => None,
Err(Unwind::Return{ value: Value::Nil, .. }) => None, Err(Unwind::Return{ value: Value::Nil, .. }) => None,
Err(Unwind::Return{ value, .. }) => Some(Ok(value)), Err(Unwind::Return{ value, .. }) => Some(Ok(value)),
Err(e) => Some(Err(e.as_error())) Err(e) => Some(Err(e.as_error().into()))
}
}
} }
} }
} }
//
//#[derive(Clone)]
//pub struct BuiltinFunc {
// pub name: Rc<str>,
// pub func: fn(Vec<Value>) -> Result<Value, String>,
// pub arg_count: usize
//}
//
//impl fmt::Debug for BuiltinFunc {
// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// f.debug_struct("BuiltinFn").field("name", &self.name).field("arg_count", &self.arg_count).finish()
// }
//}
//
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Data { pub struct Data {
@ -87,7 +159,6 @@ pub enum Value {
Char(char), Char(char),
String(Rc<str>), String(Rc<str>),
List(Rc<RefCell<Vec<Value>>>), Map(Rc<HashMap<Value,Value>>), List(Rc<RefCell<Vec<Value>>>), Map(Rc<HashMap<Value,Value>>),
BuiltinFunc(BuiltinFunc),
Func(Func), Func(Func),
Data(Data), Data(Data),
} }
@ -113,16 +184,9 @@ impl Value {
=> Ok(Box::new(s.chars() => Ok(Box::new(s.chars()
.map(Value::Char).map(Ok))), .map(Value::Char).map(Ok))),
Value::List(l) => Ok(Box::new(l.borrow().clone().into_iter().map(Ok))), Value::List(l) => Ok(Box::new(l.borrow().clone().into_iter().map(Ok))),
Value::BuiltinFunc(bf) => {
if bf.arg_count == 0 {
Ok(Box::new(bf.clone().map(|e| e.map_err(|e| RuntimeError::new(e, pos.clone())))))
} else {
Err("Only zero-argument functions can be used as iterators".into())
}
},
Value::Func(f) => { Value::Func(f) => {
if f.args.len() == 0 { if f.arg_count() == 0 {
Ok(Box::new(f.clone())) Ok(Box::new(f.clone().map(|e| e.map_err(|e| e.to_rte(pos)))))
} else { } else {
Err("Only zero-argument functions can be used as iterators".into()) Err("Only zero-argument functions can be used as iterators".into())
} }
@ -132,45 +196,10 @@ impl Value {
} }
pub fn call(&self, args: Vec<Value>, pos: &Position) -> Result<Value, RuntimeError> { pub fn call(&self, args: Vec<Value>, pos: &Position) -> Result<Value, RuntimeError> {
match self { if let Value::Func(f) = self {
Value::BuiltinFunc(f) => { f.call(args, pos)
match args.len().cmp(&f.arg_count) { } else {
Ordering::Equal => Err(RuntimeError::new("Cannot call", pos.clone()))
(f.func)(args).map_err(|e| RuntimeError::new(e, pos.clone())),
Ordering::Less => Err(RuntimeError::new(
format!("Not enough arguments for function: expected {}, got {}", f.arg_count, args.len()),
pos.clone()
)),
Ordering::Greater => Err(RuntimeError::new(
format!("Too many arguments for function: expected {}, got {}", f.arg_count, args.len()),
pos.clone()
))
}
},
Value::Func(f) => {
match args.len().cmp(&f.args.len()) {
Ordering::Equal => {
let mut env = Environment::extend(f.env.clone());
for (k, v) in f.args.iter().zip(args.iter()) {
env.declare(k.clone(), v.clone());
}
match eval_stmt(&f.func, env.wrap()) {
Ok(()) => Ok(Value::Nil),
Err(Unwind::Return{ value, .. }) => Ok(value),
Err(e) => Err(e.as_error().exit_fn(f.name.clone(), pos.clone()))
}
},
Ordering::Less => Err(RuntimeError::new(
format!("Not enough arguments for function: expected {}, got {}", f.args.len(), args.len()),
pos.clone()
)),
Ordering::Greater => Err(RuntimeError::new(
format!("Too many arguments for function: expected {}, got {}", f.args.len(), args.len()),
pos.clone()
))
}
},
_ => Err(RuntimeError::new("Cannot call", pos.clone()))
} }
} }
@ -187,8 +216,8 @@ impl Value {
Self::List(l) => Rc::from(format!("{:?}", l)), // TODO fix Self::List(l) => Rc::from(format!("{:?}", l)), // TODO fix
Self::Map(m) => Rc::from(format!("{:?}", m)), // TODO fix Self::Map(m) => Rc::from(format!("{:?}", m)), // TODO fix
Self::Type(_) => todo!(), Self::Type(_) => todo!(),
Self::BuiltinFunc(bf) => Rc::from(format!("<builtin fn {} at {:?}>", bf.name, bf.func as *const ())), Self::Func(Func::Builtin { name, func, .. }) => Rc::from(format!("<builtin fn {} at {:?}>", name, *func as *const ())),
Self::Func(f) => match &f.name { Self::Func(Func::Func { name, .. }) => match name {
Some(name) => Rc::from(format!("<fn {}>", name)), Some(name) => Rc::from(format!("<fn {}>", name)),
None => Rc::from("<anonymous fn>"), None => Rc::from("<anonymous fn>"),
}, },
@ -209,8 +238,8 @@ impl Value {
Self::List(l) => Rc::from(format!("{:?}", l.borrow())), // TODO fix Self::List(l) => Rc::from(format!("{:?}", l.borrow())), // TODO fix
Self::Map(m) => Rc::from(format!("{:?}", m)), // TODO fix Self::Map(m) => Rc::from(format!("{:?}", m)), // TODO fix
Self::Type(_) => todo!(), Self::Type(_) => todo!(),
Self::BuiltinFunc(bf) => Rc::from(format!("<builtin fn {} at {:?}>", bf.name, bf.func as *const ())), Self::Func(Func::Builtin { name, func, .. }) => Rc::from(format!("<builtin fn {} at {:?}>", name, *func as *const ())),
Self::Func(f) => match &f.name { Self::Func(Func::Func { name, .. }) => match name {
Some(name) => Rc::from(format!("<fn {}>", name)), Some(name) => Rc::from(format!("<fn {}>", name)),
None => Rc::from("<anonymous fn>"), None => Rc::from("<anonymous fn>"),
}, },
@ -286,8 +315,13 @@ impl PartialEq for Value {
(Self::String(a), Self::String(b)) => a == b, (Self::String(a), Self::String(b)) => a == b,
(Self::List(a), Self::List(b)) => a == b, (Self::List(a), Self::List(b)) => a == b,
(Self::Map(_), Self::Map(_)) => todo!("Can't test maps for equality yet"), (Self::Map(_), Self::Map(_)) => todo!("Can't test maps for equality yet"),
(Self::BuiltinFunc(a), Self::BuiltinFunc(b)) (Self::Func(f1), Self::Func(f2)) => match (f1, f2) {
=> (a.func as *const ()) == (b.func as *const ()) && a.arg_count == b.arg_count, (
Func::Builtin { func: f1, arg_count: c1, .. },
Func::Builtin { func: f2, arg_count: c2, .. }
) => (*f1 as *const ()) == (*f2 as *const ()) && c1 == c2,
_ => false
}
(Self::Data(_), Self::Data(_)) => todo!("Can't compare data yet"), (Self::Data(_), Self::Data(_)) => todo!("Can't compare data yet"),
_ => false _ => false
} }