function refactoring
This commit is contained in:
parent
ef5124ba0f
commit
9c2a24c2d9
4 changed files with 147 additions and 112 deletions
|
@ -152,7 +152,7 @@ pub fn eval_stmt(stmt: &Stmt, env: EnvRef) -> Result<(), Unwind> {
|
|||
},
|
||||
Stmt::Fn { name, args, body } => {
|
||||
let name = name.ty.clone().as_ident().unwrap();
|
||||
let func = Func {
|
||||
let func = Func::Func {
|
||||
name: Some(name.clone()),
|
||||
args: args.into_iter().map(|a| a.ty.clone().as_ident().unwrap()).collect(),
|
||||
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()))
|
||||
},
|
||||
Expr::Fn { args, body } => {
|
||||
let func = Func {
|
||||
let func = Func::Func {
|
||||
name: None,
|
||||
args: args.into_iter().map(|a| a.ty.clone().as_ident().unwrap()).collect(),
|
||||
env: env.clone(),
|
||||
|
|
|
@ -69,6 +69,7 @@ impl RuntimeError {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl fmt::Display for ParserError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Error: {}\n In {} at {},{}\n",
|
||||
|
|
|
@ -2,32 +2,32 @@ use std::{rc::Rc, io::Write, cmp::Ordering};
|
|||
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
use crate::{value::{Value, BuiltinFunc}, eval::Environment};
|
||||
use crate::{value::{Value, Func}, eval::Environment};
|
||||
|
||||
pub fn load(env: &mut Environment) {
|
||||
let mut name: Rc<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");
|
||||
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");
|
||||
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");
|
||||
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");
|
||||
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");
|
||||
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");
|
||||
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");
|
||||
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");
|
||||
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");
|
||||
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");
|
||||
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> {
|
||||
|
|
230
src/value.rs
230
src/value.rs
|
@ -8,62 +8,134 @@ pub type Rational = num_rational::Ratio<i64>;
|
|||
pub type Complex = num_complex::Complex64;
|
||||
|
||||
#[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()
|
||||
pub enum Func {
|
||||
Func {
|
||||
name: Option<Rc<str>>,
|
||||
args: Vec<Rc<str>>,
|
||||
env: EnvRef,
|
||||
func: Stmt
|
||||
},
|
||||
Builtin {
|
||||
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 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Func")
|
||||
.field("name", &self.name)
|
||||
.field("args", &self.args)
|
||||
.field("func", &self.func)
|
||||
.finish_non_exhaustive()
|
||||
match self {
|
||||
Self::Func { name, args, .. }
|
||||
=> f.debug_struct("Func::Func")
|
||||
.field("name", name)
|
||||
.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 {
|
||||
type Item = Result<Value, RuntimeError>;
|
||||
|
||||
type Item = Result<Value, EitherRteOrString>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
// precondition: function takes zero arguments
|
||||
let env = Environment::extend(self.env.clone()).wrap();
|
||||
match eval_stmt(&self.func, env) {
|
||||
Ok(_) => None,
|
||||
Err(Unwind::Return{ value: Value::Nil, .. }) => None,
|
||||
Err(Unwind::Return{ value, .. }) => Some(Ok(value)),
|
||||
Err(e) => Some(Err(e.as_error()))
|
||||
match self {
|
||||
Self::Builtin { func, .. } => match (func)(vec![]) {
|
||||
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,
|
||||
Err(Unwind::Return{ value: Value::Nil, .. }) => None,
|
||||
Err(Unwind::Return{ value, .. }) => Some(Ok(value)),
|
||||
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)]
|
||||
pub struct Data {
|
||||
|
@ -87,7 +159,6 @@ pub enum Value {
|
|||
Char(char),
|
||||
String(Rc<str>),
|
||||
List(Rc<RefCell<Vec<Value>>>), Map(Rc<HashMap<Value,Value>>),
|
||||
BuiltinFunc(BuiltinFunc),
|
||||
Func(Func),
|
||||
Data(Data),
|
||||
}
|
||||
|
@ -113,16 +184,9 @@ impl Value {
|
|||
=> Ok(Box::new(s.chars()
|
||||
.map(Value::Char).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) => {
|
||||
if f.args.len() == 0 {
|
||||
Ok(Box::new(f.clone()))
|
||||
if f.arg_count() == 0 {
|
||||
Ok(Box::new(f.clone().map(|e| e.map_err(|e| e.to_rte(pos)))))
|
||||
} else {
|
||||
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> {
|
||||
match self {
|
||||
Value::BuiltinFunc(f) => {
|
||||
match args.len().cmp(&f.arg_count) {
|
||||
Ordering::Equal =>
|
||||
(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()))
|
||||
if let Value::Func(f) = self {
|
||||
f.call(args, pos)
|
||||
} else {
|
||||
Err(RuntimeError::new("Cannot call", pos.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,8 +216,8 @@ impl Value {
|
|||
Self::List(l) => Rc::from(format!("{:?}", l)), // TODO fix
|
||||
Self::Map(m) => Rc::from(format!("{:?}", m)), // TODO fix
|
||||
Self::Type(_) => todo!(),
|
||||
Self::BuiltinFunc(bf) => Rc::from(format!("<builtin fn {} at {:?}>", bf.name, bf.func as *const ())),
|
||||
Self::Func(f) => match &f.name {
|
||||
Self::Func(Func::Builtin { name, func, .. }) => Rc::from(format!("<builtin fn {} at {:?}>", name, *func as *const ())),
|
||||
Self::Func(Func::Func { name, .. }) => match name {
|
||||
Some(name) => Rc::from(format!("<fn {}>", name)),
|
||||
None => Rc::from("<anonymous fn>"),
|
||||
},
|
||||
|
@ -209,8 +238,8 @@ impl Value {
|
|||
Self::List(l) => Rc::from(format!("{:?}", l.borrow())), // TODO fix
|
||||
Self::Map(m) => Rc::from(format!("{:?}", m)), // TODO fix
|
||||
Self::Type(_) => todo!(),
|
||||
Self::BuiltinFunc(bf) => Rc::from(format!("<builtin fn {} at {:?}>", bf.name, bf.func as *const ())),
|
||||
Self::Func(f) => match &f.name {
|
||||
Self::Func(Func::Builtin { name, func, .. }) => Rc::from(format!("<builtin fn {} at {:?}>", name, *func as *const ())),
|
||||
Self::Func(Func::Func { name, .. }) => match name {
|
||||
Some(name) => Rc::from(format!("<fn {}>", name)),
|
||||
None => Rc::from("<anonymous fn>"),
|
||||
},
|
||||
|
@ -286,8 +315,13 @@ impl PartialEq for Value {
|
|||
(Self::String(a), Self::String(b)) => a == b,
|
||||
(Self::List(a), Self::List(b)) => a == b,
|
||||
(Self::Map(_), Self::Map(_)) => todo!("Can't test maps for equality yet"),
|
||||
(Self::BuiltinFunc(a), Self::BuiltinFunc(b))
|
||||
=> (a.func as *const ()) == (b.func as *const ()) && a.arg_count == b.arg_count,
|
||||
(Self::Func(f1), Self::Func(f2)) => match (f1, f2) {
|
||||
(
|
||||
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"),
|
||||
_ => false
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue