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 } => {
|
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(),
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
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;
|
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,
|
||||||
Ok(_) => None,
|
r => Some(r.map_err(|e| e.into())),
|
||||||
Err(Unwind::Return{ value: Value::Nil, .. }) => None,
|
},
|
||||||
Err(Unwind::Return{ value, .. }) => Some(Ok(value)),
|
Self::Func { func, env, .. } => {
|
||||||
Err(e) => Some(Err(e.as_error()))
|
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)]
|
#[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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue