Skip to main content

mimium_lang/
plugin.rs

1//! # Plugin System for mimium
2//! In order to extend mimium's capability to communicate between host system, mimium has its own FFI system.
3//! The FFI is done through some traits in this plugin module in order to decouple dependencies(modules may depends on external crates).
4//! There are 3 types of interfaces you need to define depending on what you need.
5//!
6//! 1. **IO Plugins** Sets of instance-free external functions such as `print` and `println`. They are mostly for glue functions for host system's IO. `mimium-core` is an example of this type of module.
7//! 2. **External Unit Generator(UGen) Plugin.** If you need to define native Unit Generator, use `UGenPlugin` interface. In mimium code, you need to call higher-order function that returns instance of the UGen. You need to write small wrapper for this which simply calls object's constructor (In the future, this wrapper will be automatically implemented through proc-macro). Multiple instances may exist at the same time. `mimium-symphonia` is a example of this type of module.
8//! 3. **System Plugin**. If your plugin needs to mutate states of system-wide instance (1 plugin instance per 1 vm), you need to implement `SystemPlugin` traits. System plugin can have callbacks invoked at the important timings of the system like `on_init`, `before_on_sample` & so on. Internal synchronous event scheduler is implemented through this plugins system. `mimium-rand` is also an example of this type of module.
9
10mod builtin_functins;
11pub mod codegen_combinators;
12mod system_plugin;
13
14#[cfg(not(target_arch = "wasm32"))]
15pub mod loader;
16
17pub use builtin_functins::get_builtin_fns_as_plugins;
18use std::{cell::RefCell, rc::Rc};
19
20pub use system_plugin::{
21    DynSystemPlugin, SysPluginSignature, SystemPlugin, SystemPluginAudioWorker, SystemPluginFnType,
22    SystemPluginMacroType,
23};
24
25use crate::{
26    compiler::EvalStage,
27    interner::{Symbol, TypeNodeId},
28    interpreter::Value,
29    vm::{Machine, ReturnCode},
30};
31trait EvalStageT {
32    fn get_stage() -> EvalStage;
33}
34trait MacroStageT {}
35trait MachineStageT {}
36trait PersistentStageT: MacroStageT + MachineStageT {}
37trait ExternalFunction {
38    /// Declare the type signature of the external function.
39    fn get_type_info(&self) -> TypeNodeId;
40    fn get_name(&self) -> Symbol;
41    type Stage: EvalStageT;
42}
43struct MacroStage {}
44impl EvalStageT for MacroStage {
45    fn get_stage() -> EvalStage {
46        EvalStage::Stage(0)
47    }
48}
49impl MacroStageT for MacroStage {}
50struct MachineStage;
51impl EvalStageT for MachineStage {
52    fn get_stage() -> EvalStage {
53        EvalStage::Stage(1)
54    }
55}
56impl MachineStageT for MachineStage {}
57struct PersistentStage;
58impl EvalStageT for PersistentStage {
59    fn get_stage() -> EvalStage {
60        EvalStage::Persistent
61    }
62}
63impl MacroStageT for PersistentStage {}
64impl MachineStageT for PersistentStage {}
65impl PersistentStageT for PersistentStage {}
66pub type MacroFunType = Rc<RefCell<dyn Fn(&[(Value, TypeNodeId)]) -> Value>>;
67
68pub trait MacroFunction {
69    //name is still needed for linking program
70    fn get_name(&self) -> Symbol;
71    fn get_type(&self) -> TypeNodeId;
72    /// Main macro function. If you need to receive 2 or more arguments, you need to pass struct or tuple as the argument instead.
73    fn get_fn(&self) -> MacroFunType;
74}
75pub type ExtFunType = fn(&mut Machine) -> ReturnCode;
76pub type ExtClsType = Rc<RefCell<dyn FnMut(&mut Machine) -> ReturnCode>>;
77pub trait MachineFunction {
78    //name is still needed for linking program
79    fn get_name(&self) -> Symbol;
80    /// Main function that will be called by the machine.
81    fn get_fn(&self) -> ExtClsType;
82}
83#[derive(Clone)]
84pub struct MacroInfo {
85    pub name: Symbol,
86    pub ty: TypeNodeId,
87    pub fun: MacroFunType,
88}
89impl MacroInfo {
90    pub fn new(name: Symbol, ty: TypeNodeId, fun: MacroFunType) -> Self {
91        Self { name, ty, fun }
92    }
93}
94impl ExternalFunction for MacroInfo {
95    type Stage = MacroStage;
96    fn get_type_info(&self) -> TypeNodeId {
97        self.ty
98    }
99    fn get_name(&self) -> Symbol {
100        self.name
101    }
102}
103impl MacroFunction for MacroInfo {
104    fn get_name(&self) -> Symbol {
105        self.name
106    }
107    fn get_type(&self) -> TypeNodeId {
108        self.ty
109    }
110    fn get_fn(&self) -> MacroFunType {
111        self.fun.clone()
112    }
113}
114
115#[derive(Clone, Debug)]
116pub struct ExtFunInfo {
117    pub name: Symbol,
118    pub ty: TypeNodeId,
119    pub fun: ExtFunType,
120}
121impl ExtFunInfo {
122    pub fn new(name: Symbol, ty: TypeNodeId, fun: ExtFunType) -> Self {
123        Self { name, ty, fun }
124    }
125}
126impl ExternalFunction for ExtFunInfo {
127    type Stage = MachineStage;
128    fn get_type_info(&self) -> TypeNodeId {
129        self.ty
130    }
131    fn get_name(&self) -> Symbol {
132        self.name
133    }
134}
135impl MachineFunction for ExtFunInfo {
136    fn get_name(&self) -> Symbol {
137        self.name
138    }
139    fn get_fn(&self) -> ExtClsType {
140        Rc::new(RefCell::new(self.fun))
141    }
142}
143
144#[derive(Clone)]
145pub struct ExtClsInfo {
146    pub name: Symbol,
147    pub ty: TypeNodeId,
148    pub fun: ExtClsType,
149}
150impl ExtClsInfo {
151    pub fn new(name: Symbol, ty: TypeNodeId, fun: ExtClsType) -> Self {
152        Self { name, ty, fun }
153    }
154}
155impl From<ExtClsInfo> for ExtFunTypeInfo {
156    fn from(info: ExtClsInfo) -> Self {
157        ExtFunTypeInfo {
158            name: info.name,
159            ty: info.ty,
160            stage: MachineStage::get_stage(),
161        }
162    }
163}
164impl From<ExtFunInfo> for ExtFunTypeInfo {
165    fn from(info: ExtFunInfo) -> Self {
166        ExtFunTypeInfo {
167            name: info.name,
168            ty: info.ty,
169            stage: MachineStage::get_stage(),
170        }
171    }
172}
173impl ExternalFunction for ExtClsInfo {
174    type Stage = MachineStage;
175    fn get_type_info(&self) -> TypeNodeId {
176        self.ty
177    }
178    fn get_name(&self) -> Symbol {
179        self.name
180    }
181}
182impl MachineFunction for ExtClsInfo {
183    fn get_name(&self) -> Symbol {
184        self.name
185    }
186    fn get_fn(&self) -> ExtClsType {
187        self.fun.clone()
188    }
189}
190
191#[derive(Clone)]
192pub struct CommonFunction {
193    name: Symbol,
194    ty: TypeNodeId,
195    macro_fun: fn(&[(Value, TypeNodeId)]) -> Value,
196    fun: ExtFunType,
197}
198impl ExternalFunction for CommonFunction {
199    type Stage = PersistentStage;
200    fn get_type_info(&self) -> TypeNodeId {
201        self.ty
202    }
203    fn get_name(&self) -> Symbol {
204        self.name
205    }
206}
207impl MachineFunction for CommonFunction {
208    fn get_name(&self) -> Symbol {
209        self.name
210    }
211    fn get_fn(&self) -> ExtClsType {
212        Rc::new(RefCell::new(self.fun))
213    }
214}
215impl MacroFunction for CommonFunction {
216    fn get_name(&self) -> Symbol {
217        self.name
218    }
219    fn get_type(&self) -> TypeNodeId {
220        self.ty
221    }
222    fn get_fn(&self) -> MacroFunType {
223        Rc::new(RefCell::new(self.macro_fun))
224    }
225}
226#[derive(Clone, Copy)]
227pub struct ExtFunTypeInfo {
228    pub name: Symbol,
229    pub ty: TypeNodeId,
230    pub stage: EvalStage,
231}
232impl ExtFunTypeInfo {
233    pub fn new(name: Symbol, ty: TypeNodeId, stage: EvalStage) -> Self {
234        Self { name, ty, stage }
235    }
236}
237pub trait Plugin {
238    fn get_macro_functions(&self) -> Vec<Box<dyn MacroFunction>>;
239    fn get_ext_closures(&self) -> Vec<Box<dyn MachineFunction>>;
240
241    //limitation: if the functin contains persistent functions, you have to override this method.
242    fn get_type_infos(&self) -> Vec<ExtFunTypeInfo>;
243}
244
245#[derive(Clone)]
246pub struct InstantPlugin {
247    pub macros: Vec<MacroInfo>,
248    pub extcls: Vec<ExtClsInfo>,
249    pub commonfns: Vec<CommonFunction>,
250}
251impl Plugin for InstantPlugin {
252    // type MacroT = MacroInfo;
253    // type MachineT = ExtClsInfo;
254
255    fn get_macro_functions(&self) -> Vec<Box<dyn MacroFunction>> {
256        let macros = self
257            .macros
258            .clone()
259            .into_iter()
260            .map(|m| Box::new(m) as Box<dyn MacroFunction>);
261        let commons = self
262            .commonfns
263            .clone()
264            .into_iter()
265            .map(|c| Box::new(c) as Box<dyn MacroFunction>);
266        macros.chain(commons).collect()
267    }
268
269    fn get_ext_closures(&self) -> Vec<Box<dyn MachineFunction>> {
270        let extfns = self
271            .extcls
272            .clone()
273            .into_iter()
274            .map(|e| Box::new(e) as Box<dyn MachineFunction>);
275        let commons = self
276            .commonfns
277            .clone()
278            .into_iter()
279            .map(|c| Box::new(c) as Box<dyn MachineFunction>);
280        extfns.chain(commons).collect()
281    }
282
283    fn get_type_infos(&self) -> Vec<ExtFunTypeInfo> {
284        // Collect extcls and commons names to deduplicate against macros.
285        // When both a macro and an extcls share the same name (e.g. `lift_f`),
286        // the extcls (VM combinator) takes precedence.
287        let extcls_names: std::collections::HashSet<crate::interner::Symbol> =
288            self.extcls.iter().map(|e| e.name).collect();
289        let commons_names: std::collections::HashSet<crate::interner::Symbol> =
290            self.commonfns.iter().map(|c| c.name).collect();
291        let macros = self
292            .macros
293            .iter()
294            .filter(|m| !extcls_names.contains(&m.name) && !commons_names.contains(&m.name))
295            .map(|m| ExtFunTypeInfo::new(m.name, m.ty, MacroStage::get_stage()));
296        let extcls = self
297            .extcls
298            .iter()
299            .map(|e| ExtFunTypeInfo::new(e.name, e.ty, MachineStage::get_stage()));
300        let commons = self
301            .commonfns
302            .iter()
303            .map(|c| ExtFunTypeInfo::new(c.name, c.ty, PersistentStage::get_stage()));
304        macros.chain(extcls).chain(commons).collect()
305    }
306}
307
308/// Todo: Make wrapper macro for auto impl `Plugin`
309pub trait UGenPlugin {
310    type InitParam;
311    type Args;
312    type Ret;
313    fn new(param: Self::InitParam) -> Self;
314    fn on_sample(&mut self, arg: Self::Args) -> Self::Ret;
315}
316// type DynUgenPlugin{}
317// pub type UGenPluginCollection(Vec<DynUGenPlugin>);
318// impl Plugin for UGenPluginCollection{}
319
320pub fn get_extfun_types(plugins: &[Box<dyn Plugin>]) -> impl Iterator<Item = ExtFunTypeInfo> + '_ {
321    plugins
322        .iter()
323        .flat_map(|plugin| plugin.get_type_infos().into_iter())
324}
325
326pub fn get_macro_functions(
327    plugins: &[Box<dyn Plugin>],
328) -> impl Iterator<Item = Box<dyn MacroFunction>> + '_ {
329    plugins
330        .iter()
331        .flat_map(|plugin| plugin.get_macro_functions().into_iter())
332}
333pub fn get_ext_closures(
334    plugins: &[Box<dyn Plugin>],
335) -> impl Iterator<Item = Box<dyn MachineFunction>> + '_ {
336    plugins
337        .iter()
338        .flat_map(|plugin| plugin.get_ext_closures().into_iter())
339}
340
341pub(crate) type MonomorphizedExtFnNameResolver =
342    fn(Symbol, TypeNodeId, TypeNodeId) -> Option<Symbol>;
343
344const MONOMORPHIZED_EXT_FN_NAME_RESOLVERS: [MonomorphizedExtFnNameResolver; 1] =
345    [builtin_functins::try_get_monomorphized_ext_fn_name];
346
347pub(crate) fn resolve_monomorphized_ext_fn_name(
348    fn_name: Symbol,
349    concrete_arg_ty: TypeNodeId,
350    concrete_ret_ty: TypeNodeId,
351) -> Option<Symbol> {
352    MONOMORPHIZED_EXT_FN_NAME_RESOLVERS
353        .iter()
354        .find_map(|resolver| resolver(fn_name, concrete_arg_ty, concrete_ret_ty))
355}
356
357pub(crate) type SpecializedExtClsResolver = fn(Symbol, TypeNodeId) -> Option<ExtClsInfo>;
358
359const SPECIALIZED_EXTCLS_RESOLVERS: [SpecializedExtClsResolver; 1] =
360    [builtin_functins::try_make_specialized_extcls];
361
362pub(crate) fn try_make_specialized_extcls(name: Symbol, ty: TypeNodeId) -> Option<ExtClsInfo> {
363    SPECIALIZED_EXTCLS_RESOLVERS
364        .iter()
365        .find_map(|resolver| resolver(name, ty))
366}