rocks_lang/
function.rs

1use std::fmt::{Debug, Display};
2use std::cell::RefCell;
3use std::rc::Rc;
4
5use crate::environment::Environment;
6use crate::interpreter::Interpreter;
7use crate::object::{Object, Callable};
8use crate::error::{RuntimeError, ReturnType};
9use crate::stmt::Stmt;
10use crate::token::Token;
11use crate::literal::Literal;
12
13/// Represents a function.
14/// This is a struct that wraps the function's name, parameters, and body.
15/// It also contains a reference to the environment in which it was defined.
16#[derive(Debug, Clone)]
17pub struct Function {
18    pub name: Token,
19    params: Vec<Token>,
20    body: Vec<Stmt>,
21    closure: Rc<RefCell<Environment>>,
22    is_initializer: bool,
23}
24
25impl Function {
26    /// Creates a new function.
27    pub fn new(stmt: Stmt, closure: Rc<RefCell<Environment>>, is_initializer: bool) -> Self {
28        if let Stmt::Function(data) = stmt {
29            Function {
30                name: data.name,
31                params: data.params,
32                body: data.body,
33                closure,
34                is_initializer,
35            }
36        } else {
37            unreachable!("Expected function statement")
38        }
39    }
40
41    /// Binds the function to an instance by wrapping its environment.
42    /// This is used to allow the function to access the instance's fields.
43    pub fn bind(&mut self, instance: Object) -> Self {
44        let mut environment = Environment::new(Some(Rc::clone(&self.closure)));
45        environment.define("this", instance);
46
47        Function {
48            name: self.name.clone(),
49            params: self.params.clone(),
50            body: self.body.clone(),
51            closure: Rc::new(RefCell::new(environment)),
52            is_initializer: self.is_initializer,
53        }
54    }
55}
56
57impl Callable for Function {
58    /// Calls the function (or method) and returns its return value.
59    /// Function returns are handled by a special return type ([`ReturnError`](crate::error::ReturnError)).
60    /// A closure is created for the function's environment and arguments are bound to it.
61    ///
62    /// Note: Initializer methods will return the instance that they were called on.
63    fn call(&self, interpreter: &mut Interpreter, arguments: Vec<Object>) -> Result<Object, RuntimeError> {
64        let environment = Rc::new(RefCell::new(
65            Environment::new(Some(Rc::clone(&self.closure)))
66        ));
67
68        self.params.iter().zip(arguments.iter()).for_each(|(param, arg)| {
69            environment.borrow_mut().define(&param.lexeme, arg.to_owned());
70        });
71
72        match interpreter.execute_block(&self.body, environment) {
73            Ok(_) => {
74                if self.is_initializer {
75                    return self.closure.borrow().get_at(0, &Token::from("this"));
76                }
77
78                Ok(Object::from(Literal::Null))
79            },
80            Err(err) => {
81                if self.is_initializer {
82                    return self.closure.borrow().get_at(0, &Token::from("this"));
83                }
84
85                match err {
86                    ReturnType::Return(err) => {
87                        return Ok(err.value);
88                    },
89                    ReturnType::Error(err) => {
90                        return Err(err);
91                    },
92                    ReturnType::Break(_) => {
93                        unreachable!("function calls should not return break");
94                    } 
95                }
96            },
97        }
98    }
99
100    fn arity(&self) -> usize {
101        self.params.len()
102    }
103}
104
105impl Display for Function {
106    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107        write!(f, "<function {}>", self.name.lexeme)
108    }
109}
110
111impl PartialEq for Function {
112    fn eq(&self, other: &Self) -> bool {
113        return self.name == other.name;
114    }
115}
116
117/// Represents a native function.
118/// This is a special type of function that is used to implement built-in functions.
119/// These functions are external to the language and are implemented in Rust.
120/// They are used to provide access to the host environment.
121///
122/// Native functions are defined in the
123/// [`NativeFunction::get_globals`](NativeFunction::get_globals) method and used
124/// during the initialization of the [`Interpreter`](crate::interpreter::Interpreter::new).
125/// These functions will be available to the user in the global scope.
126///
127/// Current native functions:
128/// - `clock()` - Returns the current time in milliseconds.
129/// - `input()` - Reads a line of string from the standard input.
130#[derive(Clone)]
131pub struct NativeFunction {
132    pub name: Token,
133    function: fn(&mut Interpreter, Vec<Object>) -> Result<Object, RuntimeError>,
134}
135
136impl Callable for NativeFunction {
137    /// Calls the native function and returns its return value.
138    fn call(&self, interpreter: &mut Interpreter, arguments: Vec<Object>) -> Result<Object, RuntimeError> {
139        (self.function)(interpreter, arguments)
140    }
141
142    fn arity(&self) -> usize {
143        0
144    }
145}
146
147impl NativeFunction {
148    /// Returns a list of native functions with their implementations.
149    pub fn get_globals() -> Vec<NativeFunction> {
150        vec![
151            NativeFunction {
152                name: Token::from("clock"),
153                function: |_, _| {
154                    let now = std::time::SystemTime::now()
155                        .duration_since(std::time::UNIX_EPOCH)
156                        .unwrap()
157                        .as_millis();
158                    Ok(Object::from(now as f64))
159                },
160            },
161            NativeFunction {
162                name: Token::from("input"),
163                function: |_, _| {
164                    let mut input = String::new();
165                    std::io::stdin().read_line(&mut input).unwrap();
166                    input.pop();  // Remove newline
167                    Ok(Object::from(input))
168                },
169            },
170        ]
171    }
172}
173
174impl Display for NativeFunction {
175    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176        write!(f, "<native function {}>", self.name.lexeme)
177    }
178}
179
180impl Debug for NativeFunction {
181    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
182        write!(f, "<native function {}>", self.name.lexeme)
183    }
184}
185
186impl PartialEq for NativeFunction {
187    fn eq(&self, other: &Self) -> bool {
188        return self.name == other.name;
189    }
190}