#[doc(hidden)]
#[cfg(feature = "std")]
extern crate std;
use alloc::{collections::btree_map::BTreeMap, string::String};
use crate::{
Arc, Mutex,
compilation::Parser,
environment::Environment,
error::Error,
execution::{Chunk, VM},
scripting_value::ScriptingValue,
};
#[cfg(feature = "std")]
use std::vec::Vec;
pub type SharedRuntime = Arc<Mutex<Runtime>>;
#[derive(Debug, Default)]
pub struct Runtime {
parser: Parser,
vm: VM,
enums: BTreeMap<String, i8>,
#[cfg(feature = "std")]
stdout: Vec<u8>,
}
impl Clone for Runtime {
fn clone(&self) -> Self {
Self {
parser: Parser::default(),
vm: VM::default(),
enums: self.enums.clone(),
#[cfg(feature = "std")]
stdout: Vec::new(),
}
}
}
impl Runtime {
pub fn register_enum_tuple(&mut self, key: &str, value: i8) -> Result<(), Error> {
if let Some(old_value) = self.enums.get(key) {
return Err(Error::DuplicateVariant {
name: key.into(),
old: *old_value,
new: value,
});
}
self.enums.insert(key.into(), value);
Ok(())
}
#[must_use]
pub fn enum_discriminant(&self, name: &str) -> Option<i8> {
self.enums.get(name).copied()
}
pub fn parse(&mut self, script: &str) -> Result<Chunk, Error> {
let chunk = self.parser.parse(&self.enums, script)?;
Ok(chunk)
}
pub fn execute(&mut self, chunk: &Chunk, globals: &mut impl Environment) -> Result<ScriptingValue, Error> {
#[cfg(not(feature = "std"))]
let res = self.vm.run(chunk, globals)?;
#[cfg(feature = "std")]
let res = self.vm.run(chunk, globals, &mut self.stdout)?;
Ok(res)
}
pub fn continue_run(&mut self, script: &str, globals: &mut impl Environment) -> Result<ScriptingValue, Error> {
let chunk = self.parser.parse(&self.enums, script)?;
#[cfg(not(feature = "std"))]
let res = self.vm.run(&chunk, globals)?;
#[cfg(feature = "std")]
let res = self.vm.run(&chunk, globals, &mut self.stdout)?;
Ok(res)
}
pub fn run(&mut self, script: &str, globals: &mut impl Environment) -> Result<ScriptingValue, Error> {
#[cfg(feature = "std")]
self.stdout.clear();
self.continue_run(script, globals)
}
#[cfg(feature = "std")]
#[must_use]
pub const fn stdout(&self) -> &Vec<u8> {
&self.stdout
}
pub fn clear(&mut self) {
#[cfg(feature = "std")]
self.stdout.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
const fn is_normal<T: Sized + Send + Sync>() {}
#[test]
const fn normal_types() {
is_normal::<&Runtime>();
is_normal::<Runtime>();
is_normal::<&SharedRuntime>();
is_normal::<SharedRuntime>();
}
}