Refactor code base and split into more module files.
This commit is contained in:
parent
143861747d
commit
c03b162b7e
@ -1,6 +1,7 @@
|
||||
//! Helper module which defines the `Any` trait to to allow dynamic value handling.
|
||||
|
||||
use crate::engine::{Array, Map, Module};
|
||||
use crate::engine::{Array, Map};
|
||||
use crate::module::Module;
|
||||
use crate::parser::INT;
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
|
143
src/engine.rs
143
src/engine.rs
@ -3,19 +3,20 @@
|
||||
use crate::any::{Dynamic, Union};
|
||||
use crate::calc_fn_hash;
|
||||
use crate::error::ParseErrorType;
|
||||
use crate::module::Module;
|
||||
use crate::optimize::OptimizationLevel;
|
||||
use crate::packages::{CorePackage, Package, PackageLibrary, StandardPackage};
|
||||
use crate::parser::{Expr, FnDef, ModuleRef, ReturnType, Stmt};
|
||||
use crate::result::EvalAltResult;
|
||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||
use crate::token::Position;
|
||||
use crate::utils::{calc_fn_def, StaticVec};
|
||||
|
||||
use crate::stdlib::{
|
||||
any::TypeId,
|
||||
boxed::Box,
|
||||
collections::HashMap,
|
||||
format,
|
||||
hash::{Hash, Hasher},
|
||||
iter::once,
|
||||
mem,
|
||||
num::NonZeroUsize,
|
||||
@ -26,12 +27,6 @@ use crate::stdlib::{
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
use crate::stdlib::collections::hash_map::DefaultHasher;
|
||||
|
||||
#[cfg(feature = "no_std")]
|
||||
use ahash::AHasher;
|
||||
|
||||
/// An dynamic array of `Dynamic` values.
|
||||
///
|
||||
/// Not available under the `no_index` feature.
|
||||
@ -42,32 +37,6 @@ pub type Array = Vec<Dynamic>;
|
||||
/// Not available under the `no_object` feature.
|
||||
pub type Map = HashMap<String, Dynamic>;
|
||||
|
||||
/// An imported module.
|
||||
///
|
||||
/// Not available under the `no_module` feature.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Module(HashMap<String, Dynamic>);
|
||||
|
||||
impl Module {
|
||||
/// Create a new module.
|
||||
pub fn new() -> Self {
|
||||
Self(HashMap::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Module {
|
||||
type Target = HashMap<String, Dynamic>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Module {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub type FnCallArgs<'a> = [&'a mut Dynamic];
|
||||
|
||||
#[cfg(feature = "sync")]
|
||||
@ -166,78 +135,8 @@ impl<T: Into<Dynamic>> From<T> for Target<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A type to hold a number of values in static storage for speed,
|
||||
/// and any spill-overs in a `Vec`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StaticVec<T: Default + Clone> {
|
||||
/// Total number of values held.
|
||||
len: usize,
|
||||
/// Static storage. 4 slots should be enough for most cases - i.e. four levels of indirection.
|
||||
list: [T; 4],
|
||||
/// Dynamic storage. For spill-overs.
|
||||
more: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: Default + Clone> StaticVec<T> {
|
||||
/// Create a new `StaticVec`.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
len: 0,
|
||||
list: [
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
],
|
||||
more: Vec::new(),
|
||||
}
|
||||
}
|
||||
/// Push a new value to the end of this `StaticVec`.
|
||||
pub fn push<X: Into<T>>(&mut self, value: X) {
|
||||
if self.len >= self.list.len() {
|
||||
self.more.push(value.into());
|
||||
} else {
|
||||
self.list[self.len] = value.into();
|
||||
}
|
||||
self.len += 1;
|
||||
}
|
||||
/// Pop a value from the end of this `StaticVec`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the `StaticVec` is empty.
|
||||
pub fn pop(&mut self) -> T {
|
||||
let result = if self.len <= 0 {
|
||||
panic!("nothing to pop!")
|
||||
} else if self.len <= self.list.len() {
|
||||
mem::replace(self.list.get_mut(self.len - 1).unwrap(), Default::default())
|
||||
} else {
|
||||
self.more.pop().unwrap()
|
||||
};
|
||||
|
||||
self.len -= 1;
|
||||
|
||||
result
|
||||
}
|
||||
/// Get the number of items in this `StaticVec`.
|
||||
pub fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
pub fn get(&self, index: usize) -> &T {
|
||||
if index >= self.len {
|
||||
panic!("index OOB in StaticVec");
|
||||
}
|
||||
|
||||
if index < self.list.len() {
|
||||
self.list.get(index).unwrap()
|
||||
} else {
|
||||
self.more.get(index - self.list.len()).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A type that holds all the current states of the Engine.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct State {
|
||||
/// Normally, access to variables are parsed with a relative offset into the scope to avoid a lookup.
|
||||
/// In some situation, e.g. after running an `eval` statement, subsequent offsets may become mis-aligned.
|
||||
@ -466,33 +365,6 @@ fn extract_prop_from_setter(fn_name: &str) -> Option<&str> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate a `u64` hash key from a function name and parameter types.
|
||||
///
|
||||
/// Parameter types are passed in via `TypeId` values from an iterator
|
||||
/// which can come from any source.
|
||||
pub fn calc_fn_spec(fn_name: &str, params: impl Iterator<Item = TypeId>) -> u64 {
|
||||
#[cfg(feature = "no_std")]
|
||||
let mut s: AHasher = Default::default();
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
let mut s = DefaultHasher::new();
|
||||
|
||||
s.write(fn_name.as_bytes());
|
||||
params.for_each(|t| t.hash(&mut s));
|
||||
s.finish()
|
||||
}
|
||||
|
||||
/// Calculate a `u64` hash key from a function name and number of parameters (without regard to types).
|
||||
pub(crate) fn calc_fn_def(fn_name: &str, params: usize) -> u64 {
|
||||
#[cfg(feature = "no_std")]
|
||||
let mut s: AHasher = Default::default();
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
let mut s = DefaultHasher::new();
|
||||
|
||||
s.write(fn_name.as_bytes());
|
||||
s.write_usize(params);
|
||||
s.finish()
|
||||
}
|
||||
|
||||
/// Print/debug to stdout
|
||||
fn default_print(s: &str) {
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
@ -503,12 +375,13 @@ fn default_print(s: &str) {
|
||||
fn search_scope<'a>(
|
||||
scope: &'a mut Scope,
|
||||
name: &str,
|
||||
modules: &Option<Box<StaticVec<(String, Position)>>>,
|
||||
modules: &ModuleRef,
|
||||
index: Option<NonZeroUsize>,
|
||||
pos: Position,
|
||||
) -> Result<(&'a mut Dynamic, ScopeEntryType), Box<EvalAltResult>> {
|
||||
if let Some(modules) = modules {
|
||||
let (id, root_pos) = modules.get(0); // First module
|
||||
let mut drain = modules.iter();
|
||||
let (id, root_pos) = drain.next().unwrap(); // First module
|
||||
|
||||
let mut module = if let Some(index) = index {
|
||||
scope
|
||||
@ -522,9 +395,7 @@ fn search_scope<'a>(
|
||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorModuleNotFound(id.into(), *root_pos)))?
|
||||
};
|
||||
|
||||
for x in 1..modules.len() {
|
||||
let (id, id_pos) = modules.get(x);
|
||||
|
||||
for (id, id_pos) in drain {
|
||||
module = module
|
||||
.get_mut(id)
|
||||
.and_then(|v| v.downcast_mut::<Module>())
|
||||
|
@ -3,9 +3,10 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use crate::any::{Dynamic, Variant};
|
||||
use crate::engine::{calc_fn_spec, Engine, FnCallArgs};
|
||||
use crate::engine::{Engine, FnCallArgs};
|
||||
use crate::result::EvalAltResult;
|
||||
use crate::token::Position;
|
||||
use crate::utils::calc_fn_spec;
|
||||
|
||||
use crate::stdlib::{any::TypeId, boxed::Box, mem, string::ToString};
|
||||
|
||||
|
@ -76,6 +76,7 @@ mod error;
|
||||
mod fn_call;
|
||||
mod fn_func;
|
||||
mod fn_register;
|
||||
mod module;
|
||||
mod optimize;
|
||||
pub mod packages;
|
||||
mod parser;
|
||||
@ -83,9 +84,10 @@ mod result;
|
||||
mod scope;
|
||||
mod stdlib;
|
||||
mod token;
|
||||
mod utils;
|
||||
|
||||
pub use any::Dynamic;
|
||||
pub use engine::{calc_fn_spec as calc_fn_hash, Engine};
|
||||
pub use engine::Engine;
|
||||
pub use error::{ParseError, ParseErrorType};
|
||||
pub use fn_call::FuncArgs;
|
||||
pub use fn_register::{RegisterDynamicFn, RegisterFn, RegisterResultFn};
|
||||
@ -93,6 +95,7 @@ pub use parser::{AST, INT};
|
||||
pub use result::EvalAltResult;
|
||||
pub use scope::Scope;
|
||||
pub use token::Position;
|
||||
pub use utils::calc_fn_spec as calc_fn_hash;
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
pub use fn_func::Func;
|
||||
|
35
src/module.rs
Normal file
35
src/module.rs
Normal file
@ -0,0 +1,35 @@
|
||||
//! Module defining external-loaded modules for Rhai.
|
||||
|
||||
use crate::any::Dynamic;
|
||||
|
||||
use crate::stdlib::{
|
||||
collections::HashMap,
|
||||
ops::{Deref, DerefMut},
|
||||
string::String,
|
||||
};
|
||||
|
||||
/// An imported module.
|
||||
///
|
||||
/// Not available under the `no_module` feature.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Module(HashMap<String, Dynamic>);
|
||||
|
||||
impl Module {
|
||||
/// Create a new module.
|
||||
pub fn new() -> Self {
|
||||
Self(HashMap::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Module {
|
||||
type Target = HashMap<String, Dynamic>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Module {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
//! Main module defining the lexer and parser.
|
||||
|
||||
use crate::any::{Dynamic, Union};
|
||||
use crate::engine::{calc_fn_def, Engine, FunctionsLib, StaticVec};
|
||||
use crate::engine::{Engine, FunctionsLib};
|
||||
use crate::error::{LexError, ParseError, ParseErrorType};
|
||||
use crate::optimize::{optimize_into_ast, OptimizationLevel};
|
||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||
use crate::token::{Position, Token, TokenIterator};
|
||||
use crate::utils::{calc_fn_def, StaticVec};
|
||||
|
||||
use crate::stdlib::{
|
||||
borrow::Cow,
|
||||
@ -42,6 +43,9 @@ pub type FLOAT = f64;
|
||||
|
||||
type PERR = ParseErrorType;
|
||||
|
||||
/// A chain of module names to qualify a variable or function call.
|
||||
/// A `StaticVec` is used because most module-level access contains only one level,
|
||||
/// and it is wasteful to always allocate a `Vec` with one element.
|
||||
pub type ModuleRef = Option<Box<StaticVec<(String, Position)>>>;
|
||||
|
||||
/// Compiled AST (abstract syntax tree) of a Rhai script.
|
||||
@ -1079,7 +1083,7 @@ fn parse_primary<'a>(
|
||||
vec.push((*id, pos));
|
||||
modules = Some(Box::new(vec));
|
||||
|
||||
let root = modules.as_ref().unwrap().get(0);
|
||||
let root = modules.as_ref().unwrap().iter().next().unwrap();
|
||||
index = stack.find_sub_scope(&root.0);
|
||||
}
|
||||
|
||||
@ -1243,7 +1247,7 @@ fn make_dot_expr(
|
||||
}
|
||||
// lhs.module::id - syntax error
|
||||
(_, Expr::Variable(_, Some(modules), _, _)) => {
|
||||
return Err(PERR::PropertyExpected.into_err(modules.get(0).1))
|
||||
return Err(PERR::PropertyExpected.into_err(modules.iter().next().unwrap().1))
|
||||
}
|
||||
// lhs.dot_lhs.dot_rhs
|
||||
(lhs, Expr::Dot(dot_lhs, dot_rhs, dot_pos)) => Expr::Dot(
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Module that defines the `Scope` type representing a function call-stack scope.
|
||||
|
||||
use crate::any::{Dynamic, Union, Variant};
|
||||
use crate::engine::Module;
|
||||
use crate::module::Module;
|
||||
use crate::parser::{map_dynamic_to_expr, Expr};
|
||||
use crate::token::Position;
|
||||
|
||||
|
128
src/utils.rs
Normal file
128
src/utils.rs
Normal file
@ -0,0 +1,128 @@
|
||||
//! Module containing various utility types and functions.
|
||||
|
||||
use crate::stdlib::{
|
||||
any::TypeId,
|
||||
hash::{Hash, Hasher},
|
||||
mem,
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
use crate::stdlib::collections::hash_map::DefaultHasher;
|
||||
|
||||
#[cfg(feature = "no_std")]
|
||||
use ahash::AHasher;
|
||||
|
||||
/// Calculate a `u64` hash key from a function name and parameter types.
|
||||
///
|
||||
/// Parameter types are passed in via `TypeId` values from an iterator
|
||||
/// which can come from any source.
|
||||
pub fn calc_fn_spec(fn_name: &str, params: impl Iterator<Item = TypeId>) -> u64 {
|
||||
#[cfg(feature = "no_std")]
|
||||
let mut s: AHasher = Default::default();
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
let mut s = DefaultHasher::new();
|
||||
|
||||
s.write(fn_name.as_bytes());
|
||||
params.for_each(|t| t.hash(&mut s));
|
||||
s.finish()
|
||||
}
|
||||
|
||||
/// Calculate a `u64` hash key from a function name and number of parameters (without regard to types).
|
||||
pub(crate) fn calc_fn_def(fn_name: &str, num_params: usize) -> u64 {
|
||||
#[cfg(feature = "no_std")]
|
||||
let mut s: AHasher = Default::default();
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
let mut s = DefaultHasher::new();
|
||||
|
||||
s.write(fn_name.as_bytes());
|
||||
s.write_usize(num_params);
|
||||
s.finish()
|
||||
}
|
||||
|
||||
/// A type to hold a number of values in static storage for speed, and any spill-overs in a `Vec`.
|
||||
///
|
||||
/// This is essentially a knock-off of the [`staticvec`](https://crates.io/crates/staticvec) crate.
|
||||
/// This simplified implementation here is to avoid pulling in another crate.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StaticVec<T: Default + Clone> {
|
||||
/// Total number of values held.
|
||||
len: usize,
|
||||
/// Static storage. 4 slots should be enough for most cases - i.e. four levels of indirection.
|
||||
list: [T; 4],
|
||||
/// Dynamic storage. For spill-overs.
|
||||
more: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: Default + Clone> StaticVec<T> {
|
||||
/// Create a new `StaticVec`.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
len: 0,
|
||||
list: [
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
],
|
||||
more: Vec::new(),
|
||||
}
|
||||
}
|
||||
/// Push a new value to the end of this `StaticVec`.
|
||||
pub fn push<X: Into<T>>(&mut self, value: X) {
|
||||
if self.len >= self.list.len() {
|
||||
self.more.push(value.into());
|
||||
} else {
|
||||
self.list[self.len] = value.into();
|
||||
}
|
||||
self.len += 1;
|
||||
}
|
||||
/// Pop a value from the end of this `StaticVec`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the `StaticVec` is empty.
|
||||
pub fn pop(&mut self) -> T {
|
||||
let result = if self.len <= 0 {
|
||||
panic!("nothing to pop!")
|
||||
} else if self.len <= self.list.len() {
|
||||
mem::replace(self.list.get_mut(self.len - 1).unwrap(), Default::default())
|
||||
} else {
|
||||
self.more.pop().unwrap()
|
||||
};
|
||||
|
||||
self.len -= 1;
|
||||
|
||||
result
|
||||
}
|
||||
/// Get the number of items in this `StaticVec`.
|
||||
pub fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
/// Get an item at a particular index.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the index is out of bounds.
|
||||
pub fn get(&self, index: usize) -> &T {
|
||||
if index >= self.len {
|
||||
panic!("index OOB in StaticVec");
|
||||
}
|
||||
|
||||
if index < self.list.len() {
|
||||
self.list.get(index).unwrap()
|
||||
} else {
|
||||
self.more.get(index - self.list.len()).unwrap()
|
||||
}
|
||||
}
|
||||
/// Get an iterator to entries in the `StaticVec`.
|
||||
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
||||
let num = if self.len >= self.list.len() {
|
||||
self.list.len()
|
||||
} else {
|
||||
self.len
|
||||
};
|
||||
|
||||
self.list[..num].iter().chain(self.more.iter())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user