mimium_lang/
lib.rs

1//! Main module of compiler and runtime for **mimium**, an infrastructural programming language for sound and music.
2
3pub mod ast;
4pub mod interner;
5pub mod interpreter;
6pub mod mir;
7pub mod pattern;
8pub mod types;
9pub mod utils;
10
11pub mod compiler;
12pub mod runtime;
13
14pub mod plugin;
15
16use std::path::PathBuf;
17
18use crate::plugin::{MachineFunction, MacroFunction};
19use compiler::IoChannelInfo;
20pub use log;
21use plugin::{DynSystemPlugin, ExtFunTypeInfo, Plugin, SystemPlugin};
22use runtime::vm::{self, Program, ReturnCode};
23use utils::error::ReportableError;
24
25// #[cfg(not(target_arch = "wasm32"))]
26// use mimalloc::MiMalloc;
27
28// #[cfg(not(target_arch = "wasm32"))]
29// #[global_allocator]
30// static GLOBAL: MiMalloc = MiMalloc;
31
32/// Configuration for the compiler and runtime.
33#[derive(Debug, Clone, Copy, Default)]
34pub struct Config {
35    pub compiler: compiler::Config,
36    // pub runtime: runtime::Config,
37}
38
39/// Container for compiler context, virtual machine and plugins.
40///
41/// [`ExecContext`] is used as a high level API when running mimium from other
42/// Rust programs.  After adding desired plugins, call
43/// [`prepare_machine`](ExecContext::prepare_machine) to compile the source and
44/// create a [`vm::Machine`].
45pub struct ExecContext {
46    compiler: Option<compiler::Context>,
47    vm: Option<runtime::vm::Machine>,
48    plugins: Vec<Box<dyn Plugin>>,
49    sys_plugins: Vec<DynSystemPlugin>,
50    path: Option<PathBuf>,
51    config: Config,
52}
53
54impl ExecContext {
55    //The Argument will be changed to the plugins, when the plugin system is introduced
56    /// Create a new execution context with the given plugins and configuration.
57    pub fn new(
58        plugins: impl Iterator<Item = Box<dyn Plugin>>,
59        path: Option<PathBuf>,
60        config: Config,
61    ) -> Self {
62        let plugins = plugins
63            .chain([plugin::get_builtin_fns_as_plugins()])
64            .collect::<Vec<_>>();
65
66        let sys_plugins = vec![];
67        Self {
68            compiler: None,
69            vm: None,
70            plugins,
71            sys_plugins,
72            path,
73            config,
74        }
75    }
76    pub fn add_plugin<T: Plugin + 'static>(&mut self, plug: T) {
77        self.plugins.push(Box::new(plug))
78    }
79    pub fn get_plugins(&self) -> impl ExactSizeIterator<Item = &Box<dyn Plugin>> {
80        self.plugins.iter()
81    }
82    pub fn get_system_plugins(&self) -> impl ExactSizeIterator<Item = &DynSystemPlugin> {
83        self.sys_plugins.iter()
84    }
85    pub fn get_system_plugins_mut(&mut self) -> impl ExactSizeIterator<Item = &mut DynSystemPlugin> {
86        self.sys_plugins.iter_mut()
87    }
88    //todo: make it to builder pattern
89    pub fn add_system_plugin<T: SystemPlugin + 'static>(&mut self, plug: T) {
90        let plugin_dyn = DynSystemPlugin::from(plug);
91
92        self.sys_plugins.push(plugin_dyn)
93    }
94    pub fn get_compiler(&self) -> Option<&compiler::Context> {
95        self.compiler.as_ref()
96    }
97    pub fn take_compiler(&mut self) -> Option<compiler::Context> {
98        self.compiler.take()
99    }
100    pub fn take_vm(&mut self) -> Option<runtime::vm::Machine> {
101        self.vm.take()
102    }
103    pub fn get_vm(&self) -> Option<&runtime::vm::Machine> {
104        self.vm.as_ref()
105    }
106    pub fn get_compiler_mut(&mut self) -> Option<&mut compiler::Context> {
107        self.compiler.as_mut()
108    }
109    pub fn get_vm_mut(&mut self) -> Option<&mut runtime::vm::Machine> {
110        self.vm.as_mut()
111    }
112    fn get_extfun_types(&self) -> Vec<ExtFunTypeInfo> {
113        plugin::get_extfun_types(&self.plugins)
114            .chain(
115                self.sys_plugins
116                    .iter()
117                    .flat_map(|p| p.clsinfos.clone().into_iter().map(ExtFunTypeInfo::from)),
118            )
119            .collect()
120    }
121    fn get_macro_types(&self) -> Vec<Box<dyn MacroFunction>> {
122        plugin::get_macro_functions(&self.plugins)
123            .chain(self.sys_plugins.iter().flat_map(|p| {
124                p.macroinfos
125                    .iter()
126                    .map(|i| Box::new(i.clone()) as Box<dyn MacroFunction>)
127            }))
128            .collect()
129    }
130    pub fn prepare_compiler(&mut self) {
131        let macroinfos = plugin::get_macro_functions(&self.plugins).chain(
132            self.sys_plugins.iter().flat_map(|p| {
133                p.macroinfos
134                    .iter()
135                    .map(|i| Box::new(i.clone()) as Box<dyn MacroFunction>)
136            }),
137        );
138        self.compiler = Some(compiler::Context::new(
139            self.get_extfun_types(),
140            macroinfos,
141            self.path.clone(),
142            self.config.compiler,
143        ));
144    }
145    /// Compile `src` and prepare an executable VM.
146    pub fn prepare_machine(&mut self, src: &str) -> Result<(), Vec<Box<dyn ReportableError>>> {
147        if self.compiler.is_none() {
148            self.prepare_compiler();
149        }
150
151        let prog = self.compiler.as_ref().unwrap().emit_bytecode(src)?;
152        self.prepare_machine_with_bytecode(prog);
153        Ok(())
154    }
155
156    /// Build a VM from the given bytecode [`Program`].
157    pub fn prepare_machine_with_bytecode(&mut self, prog: Program) {
158        let cls =
159            plugin::get_ext_closures(&self.plugins).chain(self.sys_plugins.iter().flat_map(|p| {
160                p.clsinfos
161                    .clone()
162                    .into_iter()
163                    .map(|c| Box::new(c) as Box<dyn MachineFunction>)
164            }));
165        let vm = vm::Machine::new(prog, [].into_iter(), cls);
166        self.vm = Some(vm);
167    }
168
169    pub fn get_iochannel_count(&self) -> Option<IoChannelInfo> {
170        self.vm.as_ref().and_then(|vm| vm.prog.iochannels)
171    }
172    /// Execute the `main` function in the loaded program.
173    pub fn run_main(&mut self) -> ReturnCode {
174        if let Some(vm) = self.vm.as_mut() {
175            self.sys_plugins.iter().for_each(|plug: &DynSystemPlugin| {
176                //todo: encapsulate unsafety within SystemPlugin functionality
177                let p = unsafe { plug.inner.get().as_mut().unwrap_unchecked() };
178                let _ = p.on_init(vm);
179            });
180            let res = vm.execute_main();
181            self.sys_plugins.iter().for_each(|plug: &DynSystemPlugin| {
182                //todo: encapsulate unsafety within SystemPlugin functionality
183                let p = unsafe { plug.inner.get().as_mut().unwrap_unchecked() };
184                let _ = p.after_main(vm);
185            });
186            res
187        } else {
188            0
189        }
190    }
191    pub fn try_get_main_loop(&mut self) -> Option<Box<dyn FnOnce()>> {
192        let mut mainloops = self.sys_plugins.iter_mut().filter_map(|p| {
193            let p = unsafe { p.inner.get().as_mut().unwrap_unchecked() };
194            p.try_get_main_loop()
195        });
196        let res = mainloops.next();
197        if mainloops.next().is_some() {
198            log::warn!("more than 2 main loops in system plugins found")
199        }
200        res
201    }
202}
203//todo: remove
204// pub mod ast_interpreter;
205// pub mod repl;