122 lines
3.0 KiB
Rust
122 lines
3.0 KiB
Rust
use std::{collections::HashMap, marker::PhantomData};
|
|
|
|
use crate::{
|
|
env::Env,
|
|
pest_parser::FuncHolder,
|
|
statement::Statement,
|
|
value::{FromValue, Value},
|
|
};
|
|
|
|
mod function_impl;
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
enum FunctionType {
|
|
Native,
|
|
Interpreter,
|
|
}
|
|
|
|
#[derive(Default)]
|
|
pub struct FunctionMap(HashMap<String, (Box<dyn Function>, FunctionType)>);
|
|
|
|
impl FunctionMap {
|
|
pub fn new() -> Self {
|
|
FunctionMap::default()
|
|
}
|
|
|
|
pub fn insert_native<S, P, F>(&mut self, name: S, f: F)
|
|
where
|
|
S: ToString,
|
|
P: 'static,
|
|
F: 'static + NativeFunction<P>,
|
|
{
|
|
self.0.insert(
|
|
name.to_string(),
|
|
(Box::new(f.into_function()), FunctionType::Native),
|
|
);
|
|
}
|
|
|
|
pub fn insert_interpreter(&mut self, name: &str, params: Vec<String>, body: Vec<Statement>) {
|
|
self.0.insert(
|
|
name.to_string(),
|
|
(
|
|
Box::new(InterpreterFunction::new(params, body)),
|
|
FunctionType::Interpreter,
|
|
),
|
|
);
|
|
}
|
|
|
|
pub fn insert_holder(&mut self, holder: FuncHolder) {
|
|
for f in holder {
|
|
self.insert_interpreter(&f.0, f.1, f.2);
|
|
}
|
|
}
|
|
|
|
pub fn call(&self, name: &str, env: &Env, args: &[Value]) -> Result<Value, String> {
|
|
let (f, t) = self
|
|
.0
|
|
.get(name)
|
|
.ok_or_else(|| format!("Function {} not found", name))?;
|
|
println!("Calling {:?} function {}", t, name);
|
|
|
|
f.execute(env, self, args)
|
|
}
|
|
}
|
|
|
|
pub trait NativeFunction<P>: Sized {
|
|
fn native_execute(&self, env: &Env, args: &[Value]) -> Result<Value, String>;
|
|
|
|
fn into_function(self) -> IntoFunction<Self, P> {
|
|
IntoFunction::new(self)
|
|
}
|
|
}
|
|
|
|
pub struct IntoFunction<F, P> {
|
|
func: F,
|
|
_phantom: PhantomData<P>,
|
|
}
|
|
|
|
impl<F, P> IntoFunction<F, P> {
|
|
fn new(func: F) -> Self {
|
|
IntoFunction {
|
|
func,
|
|
_phantom: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<F: NativeFunction<P>, P> Function for IntoFunction<F, P> {
|
|
fn execute(&self, env: &Env, _: &FunctionMap, args: &[Value]) -> Result<Value, String> {
|
|
self.func.native_execute(env, args)
|
|
}
|
|
}
|
|
|
|
struct InterpreterFunction {
|
|
parameters: Vec<String>,
|
|
body: Vec<Statement>,
|
|
}
|
|
|
|
impl InterpreterFunction {
|
|
fn new(parameters: Vec<String>, body: Vec<Statement>) -> Self {
|
|
InterpreterFunction { parameters, body }
|
|
}
|
|
}
|
|
|
|
impl Function for InterpreterFunction {
|
|
fn execute(&self, env: &Env, map: &FunctionMap, args: &[Value]) -> Result<Value, String> {
|
|
let sub_env = Env::new_with_parent(env);
|
|
for (name, value) in self.parameters.iter().zip(args) {
|
|
sub_env.set_here(name, value.clone());
|
|
}
|
|
for stmt in &self.body {
|
|
if let Some(v) = stmt.eval(&sub_env, map){
|
|
return Ok(v);
|
|
}
|
|
}
|
|
Ok(Value::Nothing)
|
|
}
|
|
}
|
|
|
|
pub trait Function {
|
|
fn execute(&self, env: &Env, map: &FunctionMap, args: &[Value]) -> Result<Value, String>;
|
|
}
|