use std::fmt::{Debug, Display};
use std::cell::RefCell;
use std::rc::Rc;
use crate::environment::Environment;
use crate::interpreter::Interpreter;
use crate::object::{Object, Callable};
use crate::error::{RuntimeError, ReturnType};
use crate::stmt::Stmt;
use crate::token::Token;
use crate::literal::Literal;
#[derive(Debug, Clone)]
pub struct Function {
pub name: Token,
params: Vec<Token>,
body: Vec<Stmt>,
closure: Rc<RefCell<Environment>>,
is_initializer: bool,
}
impl Function {
pub fn new(stmt: Stmt, closure: Rc<RefCell<Environment>>, is_initializer: bool) -> Self {
if let Stmt::Function(data) = stmt {
Function {
name: data.name,
params: data.params,
body: data.body,
closure,
is_initializer,
}
} else {
unreachable!("Expected function statement")
}
}
pub fn bind(&mut self, instance: Object) -> Self {
let mut environment = Environment::new(Some(Rc::clone(&self.closure)));
environment.define("this", instance);
Function {
name: self.name.clone(),
params: self.params.clone(),
body: self.body.clone(),
closure: Rc::new(RefCell::new(environment)),
is_initializer: self.is_initializer,
}
}
}
impl Callable for Function {
fn call(&self, interpreter: &mut Interpreter, arguments: Vec<Object>) -> Result<Object, RuntimeError> {
let environment = Rc::new(RefCell::new(
Environment::new(Some(Rc::clone(&self.closure)))
));
self.params.iter().zip(arguments.iter()).for_each(|(param, arg)| {
environment.borrow_mut().define(¶m.lexeme, arg.to_owned());
});
match interpreter.execute_block(&self.body, environment) {
Ok(_) => {
if self.is_initializer {
return self.closure.borrow().get_at(0, &Token::from("this"));
}
Ok(Object::from(Literal::Null))
},
Err(err) => {
if self.is_initializer {
return self.closure.borrow().get_at(0, &Token::from("this"));
}
match err {
ReturnType::Return(err) => {
return Ok(err.value);
},
ReturnType::Error(err) => {
return Err(err);
},
ReturnType::Break(_) => {
unreachable!("function calls should not return break");
}
}
},
}
}
fn arity(&self) -> usize {
self.params.len()
}
}
impl Display for Function {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<function {}>", self.name.lexeme)
}
}
impl PartialEq for Function {
fn eq(&self, other: &Self) -> bool {
return self.name == other.name;
}
}
#[derive(Clone)]
pub struct NativeFunction {
pub name: Token,
function: fn(&mut Interpreter, Vec<Object>) -> Result<Object, RuntimeError>,
}
impl Callable for NativeFunction {
fn call(&self, interpreter: &mut Interpreter, arguments: Vec<Object>) -> Result<Object, RuntimeError> {
(self.function)(interpreter, arguments)
}
fn arity(&self) -> usize {
0
}
}
impl NativeFunction {
pub fn get_globals() -> Vec<NativeFunction> {
vec![
NativeFunction {
name: Token::from("clock"),
function: |_, _| {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_millis();
Ok(Object::from(now as f64))
},
},
NativeFunction {
name: Token::from("input"),
function: |_, _| {
let mut input = String::new();
std::io::stdin().read_line(&mut input).unwrap();
input.pop(); Ok(Object::from(input))
},
},
]
}
}
impl Display for NativeFunction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<native function {}>", self.name.lexeme)
}
}
impl Debug for NativeFunction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<native function {}>", self.name.lexeme)
}
}
impl PartialEq for NativeFunction {
fn eq(&self, other: &Self) -> bool {
return self.name == other.name;
}
}