Minor refactors.

This commit is contained in:
Stephen Chung 2022-03-20 21:58:43 +08:00
parent 1b3d5aeb53
commit 99118fe2c3
14 changed files with 114 additions and 98 deletions

View File

@ -17,6 +17,11 @@ Bug fixes
* Exporting a variable that contains a local function pointer (including anonymous function or closure) now raises a runtime error. * Exporting a variable that contains a local function pointer (including anonymous function or closure) now raises a runtime error.
* Full optimization is now skipped for method calls. * Full optimization is now skipped for method calls.
New features
------------
* [Type aliases](https://doc.rust-lang.org/reference/items/type-aliases.html) in plugin modules are now used as friendly names for custom types. This makes plugin modules more self-contained when they are used to define a custom type's API.
Enhancements Enhancements
------------ ------------

View File

@ -269,7 +269,7 @@ pub fn exported_module(module_path: proc_macro::TokenStream) -> proc_macro::Toke
pub fn combine_with_exported_module(args: proc_macro::TokenStream) -> proc_macro::TokenStream { pub fn combine_with_exported_module(args: proc_macro::TokenStream) -> proc_macro::TokenStream {
match crate::register::parse_register_macro(args) { match crate::register::parse_register_macro(args) {
Ok((module_expr, _export_name, module_path)) => proc_macro::TokenStream::from(quote! { Ok((module_expr, _export_name, module_path)) => proc_macro::TokenStream::from(quote! {
#module_path::rhai_generate_into_module(#module_expr, true); #module_path::rhai_generate_into_module(#module_expr, true)
}), }),
Err(e) => e.to_compile_error().into(), Err(e) => e.to_compile_error().into(),
} }
@ -303,7 +303,7 @@ pub fn register_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenS
Ok((engine_expr, export_name, rust_mod_path)) => { Ok((engine_expr, export_name, rust_mod_path)) => {
let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);
proc_macro::TokenStream::from(quote! { proc_macro::TokenStream::from(quote! {
#engine_expr.register_result_fn(#export_name, #gen_mod_path::dynamic_result_fn); #engine_expr.register_result_fn(#export_name, #gen_mod_path::dynamic_result_fn)
}) })
} }
Err(e) => e.to_compile_error().into(), Err(e) => e.to_compile_error().into(),
@ -352,7 +352,7 @@ pub fn set_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream
#module_expr.set_fn(#export_name, FnNamespace::Internal, FnAccess::Public, #module_expr.set_fn(#export_name, FnNamespace::Internal, FnAccess::Public,
#param_names, #param_names,
&#gen_mod_path::Token::param_types(), &#gen_mod_path::Token::param_types(),
#gen_mod_path::Token().into()); #gen_mod_path::Token().into())
}) })
} }
Err(e) => e.to_compile_error().into(), Err(e) => e.to_compile_error().into(),
@ -401,7 +401,7 @@ pub fn set_exported_global_fn(args: proc_macro::TokenStream) -> proc_macro::Toke
#module_expr.set_fn(#export_name, FnNamespace::Global, FnAccess::Public, #module_expr.set_fn(#export_name, FnNamespace::Global, FnAccess::Public,
#param_names, #param_names,
&#gen_mod_path::Token::param_types(), &#gen_mod_path::Token::param_types(),
#gen_mod_path::Token().into()); #gen_mod_path::Token().into())
}) })
} }
Err(e) => e.to_compile_error().into(), Err(e) => e.to_compile_error().into(),

View File

@ -140,20 +140,18 @@ impl Parse for Module {
for item in content.iter() { for item in content.iter() {
match item { match item {
syn::Item::Const(syn::ItemConst { syn::Item::Const(syn::ItemConst {
vis, vis: syn::Visibility::Public(..),
ref expr, ref expr,
ident, ident,
attrs, attrs,
ty, ty,
.. ..
}) if matches!(vis, syn::Visibility::Public(..)) => { }) => consts.push(ExportedConst {
consts.push(ExportedConst { name: ident.to_string(),
name: ident.to_string(), typ: ty.clone(),
typ: ty.clone(), expr: expr.as_ref().clone(),
expr: expr.as_ref().clone(), cfg_attrs: crate::attrs::collect_cfg_attr(&attrs),
cfg_attrs: crate::attrs::collect_cfg_attr(&attrs), }),
})
}
_ => {} _ => {}
} }
} }
@ -161,18 +159,16 @@ impl Parse for Module {
for item in content.iter() { for item in content.iter() {
match item { match item {
syn::Item::Type(syn::ItemType { syn::Item::Type(syn::ItemType {
vis, vis: syn::Visibility::Public(..),
ident, ident,
attrs, attrs,
ty, ty,
.. ..
}) if matches!(vis, syn::Visibility::Public(..)) => { }) => custom_types.push(ExportedType {
custom_types.push(ExportedType { name: ident.to_string(),
name: ident.to_string(), typ: ty.clone(),
typ: ty.clone(), cfg_attrs: crate::attrs::collect_cfg_attr(&attrs),
cfg_attrs: crate::attrs::collect_cfg_attr(&attrs), }),
})
}
_ => {} _ => {}
} }
} }

View File

@ -115,33 +115,34 @@ impl Engine {
let mut ast = self.compile_scripts_with_scope(scope, &[script])?; let mut ast = self.compile_scripts_with_scope(scope, &[script])?;
if let Some(ref module_resolver) = self.module_resolver { let mut resolver = StaticModuleResolver::new();
let mut resolver = StaticModuleResolver::new(); let mut imports = BTreeSet::new();
let mut imports = BTreeSet::new();
collect_imports(&ast, &resolver, &mut imports); collect_imports(&ast, &resolver, &mut imports);
if !imports.is_empty() { if !imports.is_empty() {
while let Some(path) = imports.iter().next() { while let Some(path) = imports.iter().next() {
let path = path.clone(); let path = path.clone();
match module_resolver.resolve_ast(self, None, &path, crate::Position::NONE) { match self
Some(Ok(module_ast)) => { .module_resolver
collect_imports(&module_ast, &resolver, &mut imports) .resolve_ast(self, None, &path, crate::Position::NONE)
} {
Some(err) => return err, Some(Ok(module_ast)) => collect_imports(&module_ast, &resolver, &mut imports),
None => (), Some(err) => return err,
} None => (),
let module =
module_resolver.resolve(self, None, &path, crate::Position::NONE)?;
let module = shared_take_or_clone(module);
imports.remove(&path);
resolver.insert(path, module);
} }
ast.set_resolver(resolver);
let module =
self.module_resolver
.resolve(self, None, &path, crate::Position::NONE)?;
let module = shared_take_or_clone(module);
imports.remove(&path);
resolver.insert(path, module);
} }
ast.set_resolver(resolver);
} }
Ok(ast) Ok(ast)

View File

@ -282,7 +282,7 @@ impl Engine {
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn on_print(&mut self, callback: impl Fn(&str) + SendSync + 'static) -> &mut Self { pub fn on_print(&mut self, callback: impl Fn(&str) + SendSync + 'static) -> &mut Self {
self.print = Some(Box::new(callback)); self.print = Box::new(callback);
self self
} }
/// Override default action of `debug` (print to stdout using [`println!`]) /// Override default action of `debug` (print to stdout using [`println!`])
@ -332,7 +332,7 @@ impl Engine {
&mut self, &mut self,
callback: impl Fn(&str, Option<&str>, Position) + SendSync + 'static, callback: impl Fn(&str, Option<&str>, Position) + SendSync + 'static,
) -> &mut Self { ) -> &mut Self {
self.debug = Some(Box::new(callback)); self.debug = Box::new(callback);
self self
} }
/// _(debugging)_ Register a callback for debugging. /// _(debugging)_ Register a callback for debugging.

View File

@ -71,7 +71,7 @@ impl Engine {
&mut self, &mut self,
resolver: impl crate::ModuleResolver + 'static, resolver: impl crate::ModuleResolver + 'static,
) -> &mut Self { ) -> &mut Self {
self.module_resolver = Some(Box::new(resolver)); self.module_resolver = Box::new(resolver);
self self
} }

View File

@ -150,9 +150,10 @@ impl AST {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn source(&self) -> Option<&str> { pub fn source(&self) -> Option<&str> {
match self.source.as_str() { if self.source.is_empty() {
"" => None, None
s => Some(s), } else {
Some(self.source.as_str())
} }
} }
/// Get a reference to the source. /// Get a reference to the source.

View File

@ -89,6 +89,26 @@ pub struct ConditionalStmtBlock {
pub statements: StmtBlock, pub statements: StmtBlock,
} }
impl<B: Into<StmtBlock>> From<B> for ConditionalStmtBlock {
#[inline(always)]
fn from(value: B) -> Self {
Self {
condition: None,
statements: value.into(),
}
}
}
impl<B: Into<StmtBlock>> From<(Expr, B)> for ConditionalStmtBlock {
#[inline(always)]
fn from(value: (Expr, B)) -> Self {
Self {
condition: Some(value.0),
statements: value.1.into(),
}
}
}
impl<B: Into<StmtBlock>> From<(Option<Expr>, B)> for ConditionalStmtBlock { impl<B: Into<StmtBlock>> From<(Option<Expr>, B)> for ConditionalStmtBlock {
#[inline(always)] #[inline(always)]
fn from(value: (Option<Expr>, B)) -> Self { fn from(value: (Option<Expr>, B)) -> Self {

View File

@ -1,6 +1,7 @@
//! Main module defining the script evaluation [`Engine`]. //! Main module defining the script evaluation [`Engine`].
use crate::api::custom_syntax::CustomSyntax; use crate::api::custom_syntax::CustomSyntax;
use crate::api::options::LanguageOptions;
use crate::func::native::{ use crate::func::native::{
OnDebugCallback, OnDefVarCallback, OnParseTokenCallback, OnPrintCallback, OnVarCallback, OnDebugCallback, OnDefVarCallback, OnParseTokenCallback, OnPrintCallback, OnVarCallback,
}; };
@ -102,7 +103,7 @@ pub struct Engine {
/// A module resolution service. /// A module resolution service.
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
pub(crate) module_resolver: Option<Box<dyn crate::ModuleResolver>>, pub(crate) module_resolver: Box<dyn crate::ModuleResolver>,
/// A map mapping type names to pretty-print names. /// A map mapping type names to pretty-print names.
pub(crate) custom_types: CustomTypesCollection, pub(crate) custom_types: CustomTypesCollection,
@ -124,9 +125,9 @@ pub struct Engine {
pub(crate) token_mapper: Option<Box<OnParseTokenCallback>>, pub(crate) token_mapper: Option<Box<OnParseTokenCallback>>,
/// Callback closure for implementing the `print` command. /// Callback closure for implementing the `print` command.
pub(crate) print: Option<Box<OnPrintCallback>>, pub(crate) print: Box<OnPrintCallback>,
/// Callback closure for implementing the `debug` command. /// Callback closure for implementing the `debug` command.
pub(crate) debug: Option<Box<OnDebugCallback>>, pub(crate) debug: Box<OnDebugCallback>,
/// Callback closure for progress reporting. /// Callback closure for progress reporting.
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
pub(crate) progress: Option<Box<crate::func::native::OnProgressCallback>>, pub(crate) progress: Option<Box<crate::func::native::OnProgressCallback>>,
@ -135,7 +136,7 @@ pub struct Engine {
pub(crate) optimization_level: OptimizationLevel, pub(crate) optimization_level: OptimizationLevel,
/// Language options. /// Language options.
pub(crate) options: crate::api::options::LanguageOptions, pub(crate) options: LanguageOptions,
/// Max limits. /// Max limits.
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
@ -157,8 +158,7 @@ impl fmt::Debug for Engine {
f.field("global_modules", &self.global_modules); f.field("global_modules", &self.global_modules);
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
f.field("global_sub_modules", &self.global_sub_modules) f.field("global_sub_modules", &self.global_sub_modules);
.field("module_resolver", &self.module_resolver.is_some());
f.field("type_names", &self.custom_types) f.field("type_names", &self.custom_types)
.field("disabled_symbols", &self.disabled_symbols) .field("disabled_symbols", &self.disabled_symbols)
@ -166,9 +166,7 @@ impl fmt::Debug for Engine {
.field("custom_syntax", &(!self.custom_syntax.is_empty())) .field("custom_syntax", &(!self.custom_syntax.is_empty()))
.field("def_var_filter", &self.def_var_filter.is_some()) .field("def_var_filter", &self.def_var_filter.is_some())
.field("resolve_var", &self.resolve_var.is_some()) .field("resolve_var", &self.resolve_var.is_some())
.field("token_mapper", &self.token_mapper.is_some()) .field("token_mapper", &self.token_mapper.is_some());
.field("print", &self.print.is_some())
.field("debug", &self.debug.is_some());
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
f.field("progress", &self.progress.is_some()); f.field("progress", &self.progress.is_some());
@ -226,16 +224,15 @@ impl Engine {
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
#[cfg(not(target_family = "wasm"))] #[cfg(not(target_family = "wasm"))]
{ {
engine.module_resolver = engine.module_resolver = Box::new(crate::module::resolvers::FileModuleResolver::new());
Some(Box::new(crate::module::resolvers::FileModuleResolver::new()));
} }
// default print/debug implementations // default print/debug implementations
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
#[cfg(not(target_family = "wasm"))] #[cfg(not(target_family = "wasm"))]
{ {
engine.print = Some(Box::new(|s| println!("{}", s))); engine.print = Box::new(|s| println!("{}", s));
engine.debug = Some(Box::new(|s, source, pos| { engine.debug = Box::new(|s, source, pos| {
if let Some(source) = source { if let Some(source) = source {
println!("{} @ {:?} | {}", source, pos, s); println!("{} @ {:?} | {}", source, pos, s);
} else if pos.is_none() { } else if pos.is_none() {
@ -243,7 +240,7 @@ impl Engine {
} else { } else {
println!("{:?} | {}", pos, s); println!("{:?} | {}", pos, s);
} }
})); });
} }
#[cfg(any(feature = "no_std", target_family = "wasm"))] #[cfg(any(feature = "no_std", target_family = "wasm"))]
{ {
@ -269,7 +266,7 @@ impl Engine {
global_sub_modules: BTreeMap::new(), global_sub_modules: BTreeMap::new(),
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
module_resolver: None, module_resolver: Box::new(crate::module::resolvers::DummyModuleResolver::new()),
custom_types: CustomTypesCollection::new(), custom_types: CustomTypesCollection::new(),
empty_string: ImmutableString::new(), empty_string: ImmutableString::new(),
@ -281,15 +278,15 @@ impl Engine {
resolve_var: None, resolve_var: None,
token_mapper: None, token_mapper: None,
print: None, print: Box::new(|_| {}),
debug: None, debug: Box::new(|_, _, _| {}),
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
progress: None, progress: None,
optimization_level: OptimizationLevel::default(), optimization_level: OptimizationLevel::default(),
options: crate::api::options::LanguageOptions::new(), options: LanguageOptions::new(),
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
limits: crate::api::limits::Limits::new(), limits: crate::api::limits::Limits::new(),

View File

@ -35,9 +35,10 @@ impl<'x, 'px, 'm, 'pm, 'pt> EvalContext<'_, 'x, 'px, 'm, 'pm, '_, '_, '_, '_, 'p
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn source(&self) -> Option<&str> { pub fn source(&self) -> Option<&str> {
match self.global.source.as_str() { if self.global.source.is_empty() {
"" => None, None
s => Some(s), } else {
Some(self.global.source.as_str())
} }
} }
/// The current [`Scope`]. /// The current [`Scope`].

View File

@ -28,7 +28,7 @@ pub struct EvalState<'a> {
/// Stack of function resolution caches. /// Stack of function resolution caches.
fn_resolution_caches: StaticVec<FnResolutionCache>, fn_resolution_caches: StaticVec<FnResolutionCache>,
/// Take care of the lifetime parameter /// Take care of the lifetime parameter
dummy: PhantomData<Option<&'a ()>>, dummy: PhantomData<&'a ()>,
} }
impl EvalState<'_> { impl EvalState<'_> {

View File

@ -244,9 +244,10 @@ impl GlobalRuntimeState<'_> {
#[inline] #[inline]
#[must_use] #[must_use]
pub fn source(&self) -> Option<&str> { pub fn source(&self) -> Option<&str> {
match self.source.as_str() { if self.source.is_empty() {
"" => None, None
s => Some(s), } else {
Some(self.source.as_str())
} }
} }
/// Get the pre-calculated index getter hash. /// Get the pre-calculated index getter hash.

View File

@ -952,9 +952,10 @@ impl Engine {
result => Some(result), result => Some(result),
}) })
.or_else(|| { .or_else(|| {
self.module_resolver Some(
.as_ref() self.module_resolver
.map(|r| r.resolve_raw(self, global, &path, path_pos)) .resolve_raw(self, global, &path, path_pos),
)
}) })
.unwrap_or_else(|| { .unwrap_or_else(|| {
Err(ERR::ErrorModuleNotFound(path.to_string(), path_pos).into()) Err(ERR::ErrorModuleNotFound(path.to_string(), path_pos).into())

View File

@ -464,30 +464,23 @@ impl Engine {
// See if the function match print/debug (which requires special processing) // See if the function match print/debug (which requires special processing)
return Ok(match name { return Ok(match name {
KEYWORD_PRINT => { KEYWORD_PRINT => {
if let Some(ref print) = self.print { let text = result.into_immutable_string().map_err(|typ| {
let text = result.into_immutable_string().map_err(|typ| { let t = self.map_type_name(type_name::<ImmutableString>()).into();
let t = self.map_type_name(type_name::<ImmutableString>()).into(); ERR::ErrorMismatchOutputType(t, typ.into(), pos)
ERR::ErrorMismatchOutputType(t, typ.into(), pos) })?;
})?; ((&*self.print)(&text).into(), false)
(print(&text).into(), false)
} else {
(Dynamic::UNIT, false)
}
} }
KEYWORD_DEBUG => { KEYWORD_DEBUG => {
if let Some(ref debug) = self.debug { let text = result.into_immutable_string().map_err(|typ| {
let text = result.into_immutable_string().map_err(|typ| { let t = self.map_type_name(type_name::<ImmutableString>()).into();
let t = self.map_type_name(type_name::<ImmutableString>()).into(); ERR::ErrorMismatchOutputType(t, typ.into(), pos)
ERR::ErrorMismatchOutputType(t, typ.into(), pos) })?;
})?; let source = if global.source.is_empty() {
let source = match global.source.as_str() { None
"" => None,
s => Some(s),
};
(debug(&text, source, pos).into(), false)
} else { } else {
(Dynamic::UNIT, false) Some(global.source.as_str())
} };
((&*self.debug)(&text, source, pos).into(), false)
} }
_ => (result, is_method), _ => (result, is_method),
}); });