tenda_runtime/
function.rs

1use std::sync::atomic::{AtomicUsize, Ordering};
2use tenda_common::span::SourceSpan;
3use tenda_parser::ast;
4
5use crate::environment::Environment;
6use crate::runtime::Runtime;
7
8use super::runtime_error::Result;
9use super::value::Value;
10
11static FUNCTION_ID_COUNTER: AtomicUsize = AtomicUsize::new(1);
12
13#[derive(Debug, Clone)]
14pub struct Function {
15    pub id: usize,
16    pub object: FunctionObject,
17    pub metadata: Option<FunctionRuntimeMetadata>,
18}
19
20impl Function {
21    pub fn new(
22        params: Vec<FunctionParam>,
23        captured_env: Environment,
24        body: Box<ast::Stmt>,
25    ) -> Self {
26        let unique_id = FUNCTION_ID_COUNTER.fetch_add(1, Ordering::SeqCst);
27
28        Function {
29            id: unique_id,
30            object: FunctionObject::new(params, Box::new(captured_env), body),
31            metadata: None,
32        }
33    }
34
35    pub fn new_builtin(params: Vec<FunctionParam>, func_ptr: BuiltinFunctionPointer) -> Self {
36        let unique_id = FUNCTION_ID_COUNTER.fetch_add(1, Ordering::SeqCst);
37
38        Function {
39            id: unique_id,
40            object: FunctionObject::new_builtin(params, Box::default(), func_ptr),
41            metadata: None,
42        }
43    }
44
45    pub fn get_params(&self) -> Vec<FunctionParam> {
46        match &self.object {
47            FunctionObject::UserDefined { params, .. } => params.clone(),
48            FunctionObject::Builtin { params, .. } => params.clone(),
49        }
50    }
51
52    pub fn get_env(&self) -> &Environment {
53        match &self.object {
54            FunctionObject::UserDefined { env, .. } => env,
55            FunctionObject::Builtin { env, .. } => env,
56        }
57    }
58
59    pub fn get_env_mut(&mut self) -> &mut Box<Environment> {
60        match &mut self.object {
61            FunctionObject::UserDefined { env, .. } => env,
62            FunctionObject::Builtin { env, .. } => env,
63        }
64    }
65
66    pub fn set_metadata(&mut self, metadata: FunctionRuntimeMetadata) {
67        self.metadata = Some(metadata);
68    }
69}
70
71impl PartialEq for Function {
72    fn eq(&self, other: &Self) -> bool {
73        self.id == other.id
74    }
75}
76
77#[derive(Debug, Clone)]
78pub struct FunctionParam {
79    pub name: String,
80    pub is_captured: bool,
81}
82
83impl From<ast::FunctionParam> for FunctionParam {
84    fn from(param: ast::FunctionParam) -> Self {
85        FunctionParam {
86            name: param.name,
87            is_captured: param.captured,
88        }
89    }
90}
91
92type BuiltinFunctionPointer = fn(
93    params: Vec<(FunctionParam, Value)>,
94    runtime: &mut Runtime,
95    context: Box<Environment>,
96) -> Result<Value>;
97
98#[derive(Debug, Clone)]
99pub enum FunctionObject {
100    UserDefined {
101        params: Vec<FunctionParam>,
102        env: Box<Environment>,
103        body: Box<ast::Stmt>,
104    },
105    Builtin {
106        params: Vec<FunctionParam>,
107        env: Box<Environment>,
108        func_ptr: BuiltinFunctionPointer,
109    },
110}
111
112impl FunctionObject {
113    pub fn new(
114        params: Vec<FunctionParam>,
115        context: Box<Environment>,
116        body: Box<ast::Stmt>,
117    ) -> Self {
118        FunctionObject::UserDefined {
119            params,
120            body,
121            env: context,
122        }
123    }
124
125    pub fn new_builtin(
126        params: Vec<FunctionParam>,
127        env: Box<Environment>,
128        func_ptr: BuiltinFunctionPointer,
129    ) -> Self {
130        FunctionObject::Builtin {
131            params,
132            env,
133            func_ptr,
134        }
135    }
136}
137
138#[derive(Debug, Clone)]
139pub struct FunctionRuntimeMetadata {
140    span: Option<Box<SourceSpan>>,
141    name: Option<String>,
142}
143
144impl FunctionRuntimeMetadata {
145    pub fn new(span: Option<SourceSpan>, name: Option<String>) -> Self {
146        FunctionRuntimeMetadata {
147            span: span.map(Box::new),
148            name,
149        }
150    }
151}
152
153impl FunctionRuntimeMetadata {
154    pub fn get_span(&self) -> Option<Box<SourceSpan>> {
155        self.span.clone()
156    }
157
158    pub fn get_name(&self) -> Option<String> {
159        self.name.clone()
160    }
161}
162
163#[macro_export]
164macro_rules! params {
165    ($($kind:expr),*) => {
166        {
167            use $crate::FunctionParam;
168            vec![$($kind.to_string()),*].into_iter().map(|name| FunctionParam {
169                name,
170                is_captured: false,
171            }).collect()
172        }
173    };
174}