Merge pull request #433 from schungx/master

Minor refinements.
This commit is contained in:
Stephen Chung 2021-08-01 22:12:13 +08:00 committed by GitHub
commit abb4884869
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 199 additions and 454 deletions

View File

@ -98,10 +98,10 @@ features = ["maths"]
optional = true optional = true
[target.'cfg(target_arch = "wasm32")'.dependencies] [target.'cfg(target_arch = "wasm32")'.dependencies]
instant = { version = "0.1" } # WASM implementation of std::time::Instant instant = { version = "0.1.10" } # WASM implementation of std::time::Instant
[target.'cfg(target_arch = "wasm64")'.dependencies] [target.'cfg(target_arch = "wasm64")'.dependencies]
instant = { version = "0.1" } # WASM implementation of std::time::Instant instant = { version = "0.1.10" } # WASM implementation of std::time::Instant
[package.metadata.docs.rs] [package.metadata.docs.rs]
features = ["metadata", "serde", "internals", "decimal"] # compiling for no-std features = ["metadata", "serde", "internals", "decimal"] # compiling for no-std

View File

@ -1,38 +0,0 @@
cargo-features = ["named-profiles"]
[workspace]
[package]
name = "no_std_repl"
version = "0.1.0"
edition = "2018"
authors = ["Stephen Chung"]
description = "no-std REPL application"
homepage = "https://github.com/rhaiscript/rhai/tree/no_std/no_std_repl"
repository = "https://github.com/rhaiscript/rhai"
[dependencies]
rhai = { path = "../../", default_features = false, features = [ "no_std", "decimal", "metadata" ] }
wee_alloc = { version = "0.4.5", default_features = false }
[profile.dev]
panic = "abort"
[profile.release]
opt-level = "z" # optimize for size
debug = false
rpath = false
debug-assertions = false
codegen-units = 1
panic = "abort"
[profile.unix]
inherits = "release"
lto = true
[profile.windows]
inherits = "release"
[profile.macos]
inherits = "release"
lto = "fat"

View File

@ -1,26 +0,0 @@
`no-std` REPL Sample
====================
This sample application is the same version as the `rhai-repl` tool, compiled for `no-std`.
[`wee_alloc`](https://crates.io/crates/wee_alloc) is used as the allocator.
To Build
--------
The nightly compiler is required:
```bash
cargo +nightly build --release
```
A specific profile can also be used:
```bash
cargo +nightly build --profile unix -Z unstable-options
```
Three profiles are defined: `unix`, `windows` and `macos`.
The release build is optimized for size. It can be changed to optimize on speed instead.

View File

@ -1,214 +0,0 @@
use rhai::{Dynamic, Engine, EvalAltResult, Scope, AST};
use std::{
env,
io::{stdin, stdout, Write},
};
/// Pretty-print error.
fn print_error(input: &str, mut err: EvalAltResult) {
let lines: Vec<_> = input.trim().split('\n').collect();
let pos = err.take_position();
let line_no = if lines.len() > 1 {
if pos.is_none() {
"".to_string()
} else {
format!("{}: ", pos.line().unwrap())
}
} else {
"".to_string()
};
// Print error position
if pos.is_none() {
// No position
println!("{}", err);
} else {
// Specific position - print line text
println!("{}{}", line_no, lines[pos.line().unwrap() - 1]);
// Display position marker
println!(
"{0:>1$} {2}",
"^",
line_no.len() + pos.position().unwrap(),
err
);
}
}
/// Print help text.
fn print_help() {
println!("help => print this help");
println!("quit, exit => quit");
println!("scope => print all variables in the scope");
println!("functions => print all functions defined");
println!("json => output all functions in JSON format");
println!("ast => print the last AST (optimized)");
println!("astu => print the last raw, un-optimized AST");
println!(r"end a line with '\' to continue to the next line.");
println!();
}
fn main() {
let title = format!("Rhai REPL tool (version {})", env!("CARGO_PKG_VERSION"));
println!("{}", title);
println!("{0:=<1$}", "", title.len());
print_help();
// Initialize scripting engine
let mut engine = Engine::new();
// Setup Engine
#[cfg(not(feature = "no_optimize"))]
engine.set_optimization_level(rhai::OptimizationLevel::None);
// Make Engine immutable
let engine = engine;
// Create scope
let mut scope = Scope::new();
// REPL loop
let mut input = String::new();
let mut main_ast: AST = Default::default();
let mut ast_u: AST = Default::default();
let mut ast: AST = Default::default();
'main_loop: loop {
print!("rhai-repl> ");
stdout().flush().expect("couldn't flush stdout");
input.clear();
loop {
match stdin().read_line(&mut input) {
Ok(0) => break 'main_loop,
Ok(_) => (),
Err(err) => panic!("input error: {}", err),
}
let line = input.as_str().trim_end();
// Allow line continuation
if line.ends_with('\\') {
let len = line.len();
input.truncate(len - 1);
input.push('\n');
} else {
break;
}
print!("> ");
stdout().flush().expect("couldn't flush stdout");
}
let script = input.trim();
if script.is_empty() {
continue;
}
// Implement standard commands
match script {
"help" => {
print_help();
continue;
}
"exit" | "quit" => break, // quit
"scope" => {
scope
.iter_raw()
.enumerate()
.for_each(|(i, (name, constant, value))| {
#[cfg(not(feature = "no_closure"))]
let value_is_shared = if value.is_shared() { " (shared" } else { "" };
#[cfg(feature = "no_closure")]
let value_is_shared = "";
println!(
"[{}] {}{}{} = {:?}",
i + 1,
if constant { "const " } else { "" },
name,
value_is_shared,
*value.read_lock::<Dynamic>().unwrap(),
)
});
println!();
continue;
}
"astu" => {
// print the last un-optimized AST
println!("{:#?}\n", ast_u);
continue;
}
"ast" => {
// print the last AST
println!("{:#?}\n", ast);
continue;
}
"functions" => {
// print a list of all registered functions
engine
.gen_fn_signatures(false)
.into_iter()
.for_each(|f| println!("{}", f));
#[cfg(not(feature = "no_function"))]
main_ast.iter_functions().for_each(|f| println!("{}", f));
println!();
continue;
}
"json" => {
println!(
"{}",
engine
.gen_fn_metadata_with_ast_to_json(&main_ast, true)
.unwrap()
);
continue;
}
_ => (),
}
match engine
.compile_with_scope(&scope, &script)
.map_err(Into::into)
.and_then(|r| {
ast_u = r.clone();
#[cfg(not(feature = "no_optimize"))]
{
ast = engine.optimize_ast(&scope, r, rhai::OptimizationLevel::Simple);
}
#[cfg(feature = "no_optimize")]
{
ast = r;
}
// Merge the AST into the main
main_ast += ast.clone();
// Evaluate
engine.eval_ast_with_scope::<Dynamic>(&mut scope, &main_ast)
}) {
Ok(result) if !result.is::<()>() => {
println!("=> {:?}", result);
println!();
}
Ok(_) => (),
Err(err) => {
println!();
print_error(&input, *err);
println!();
}
}
// Throw away all the statements, leaving only the functions
main_ast.clear_statements();
}
}

View File

@ -40,7 +40,7 @@ pub enum FnAccess {
Private, Private,
} }
/// _(INTERNALS)_ A type containing information on a scripted function. /// _(internals)_ A type containing information on a scripted function.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
@ -68,7 +68,7 @@ pub struct ScriptFnDef {
/// Not available under `no_closure`. /// Not available under `no_closure`.
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
pub externals: std::collections::BTreeSet<Identifier>, pub externals: std::collections::BTreeSet<Identifier>,
/// _(METADATA)_ Function doc-comments (if any). /// _(metadata)_ Function doc-comments (if any).
/// Exported under the `metadata` feature only. /// Exported under the `metadata` feature only.
/// ///
/// Not available under `no_function`. /// Not available under `no_function`.
@ -104,7 +104,7 @@ impl fmt::Display for ScriptFnDef {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[derive(Debug, Eq, PartialEq, Clone, Hash)] #[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub struct ScriptFnMetadata<'a> { pub struct ScriptFnMetadata<'a> {
/// _(METADATA)_ Function doc-comments (if any). /// _(metadata)_ Function doc-comments (if any).
/// Exported under the `metadata` feature only. /// Exported under the `metadata` feature only.
/// ///
/// Not available under `no_function`. /// Not available under `no_function`.
@ -278,7 +278,7 @@ impl AST {
pub(crate) fn statements(&self) -> &[Stmt] { pub(crate) fn statements(&self) -> &[Stmt] {
&self.body.0 &self.body.0
} }
/// _(INTERNALS)_ Get the statements. /// _(internals)_ Get the statements.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[deprecated = "this method is volatile and may change"] #[deprecated = "this method is volatile and may change"]
@ -303,7 +303,7 @@ impl AST {
pub(crate) fn shared_lib(&self) -> Shared<Module> { pub(crate) fn shared_lib(&self) -> Shared<Module> {
self.functions.clone() self.functions.clone()
} }
/// _(INTERNALS)_ Get the internal shared [`Module`] containing all script-defined functions. /// _(internals)_ Get the internal shared [`Module`] containing all script-defined functions.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// Not available under `no_function` or `no_module`. /// Not available under `no_function` or `no_module`.
@ -323,7 +323,7 @@ impl AST {
pub(crate) fn lib(&self) -> &Module { pub(crate) fn lib(&self) -> &Module {
&self.functions &self.functions
} }
/// _(INTERNALS)_ Get the internal [`Module`] containing all script-defined functions. /// _(internals)_ Get the internal [`Module`] containing all script-defined functions.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// Not available under `no_function`. /// Not available under `no_function`.
@ -344,7 +344,7 @@ impl AST {
) -> Option<Shared<crate::module::resolvers::StaticModuleResolver>> { ) -> Option<Shared<crate::module::resolvers::StaticModuleResolver>> {
self.resolver.clone() self.resolver.clone()
} }
/// _(INTERNALS)_ Get the embedded [module resolver][crate::ModuleResolver]. /// _(internals)_ Get the embedded [module resolver][crate::ModuleResolver].
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// Not available under `no_module`. /// Not available under `no_module`.
@ -762,7 +762,7 @@ impl AST {
true true
} }
/// _(INTERNALS)_ Recursively walk the [`AST`], including function bodies (if any). /// _(internals)_ Recursively walk the [`AST`], including function bodies (if any).
/// Return `false` from the callback to terminate the walk. /// Return `false` from the callback to terminate the walk.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
@ -816,7 +816,7 @@ impl AsRef<Module> for AST {
} }
} }
/// _(INTERNALS)_ An identifier containing a name and a [position][Position]. /// _(internals)_ An identifier containing a name and a [position][Position].
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
@ -837,7 +837,7 @@ impl fmt::Debug for Ident {
} }
} }
/// _(INTERNALS)_ A type encapsulating the mode of a `return`/`throw` statement. /// _(internals)_ A type encapsulating the mode of a `return`/`throw` statement.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
@ -851,7 +851,7 @@ pub enum ReturnType {
Exception, Exception,
} }
/// _(INTERNALS)_ An [`AST`] node, consisting of either an [`Expr`] or a [`Stmt`]. /// _(internals)_ An [`AST`] node, consisting of either an [`Expr`] or a [`Stmt`].
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
@ -875,7 +875,7 @@ impl<'a> From<&'a Expr> for ASTNode<'a> {
} }
} }
/// _(INTERNALS)_ A statements block. /// _(internals)_ A statements block.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
@ -950,7 +950,19 @@ impl From<StmtBlock> for Stmt {
} }
} }
/// _(INTERNALS)_ A statement. /// _(internals)_ Type of variable declaration.
/// Exported under the `internals` feature only.
///
/// # Volatile Data Structure
///
/// This type is volatile and may change.
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
pub enum VarDeclaration {
Let,
Const,
}
/// _(internals)_ A statement.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
@ -974,10 +986,8 @@ pub enum Stmt {
Do(Box<StmtBlock>, Expr, bool, Position), Do(Box<StmtBlock>, Expr, bool, Position),
/// `for` `(` id `,` counter `)` `in` expr `{` stmt `}` /// `for` `(` id `,` counter `)` `in` expr `{` stmt `}`
For(Expr, Box<(Ident, Option<Ident>, StmtBlock)>, Position), For(Expr, Box<(Ident, Option<Ident>, StmtBlock)>, Position),
/// \[`export`\] `let` id `=` expr /// \[`export`\] `let`/`const` id `=` expr
Let(Expr, Box<Ident>, bool, Position), Var(Expr, Box<Ident>, VarDeclaration, bool, Position),
/// \[`export`\] `const` id `=` expr
Const(Expr, Box<Ident>, bool, Position),
/// expr op`=` expr /// expr op`=` expr
Assignment(Box<(Expr, Option<OpAssignment<'static>>, Expr)>, Position), Assignment(Box<(Expr, Option<OpAssignment<'static>>, Expr)>, Position),
/// func `(` expr `,` ... `)` /// func `(` expr `,` ... `)`
@ -1058,8 +1068,7 @@ impl Stmt {
| Self::Do(_, _, _, pos) | Self::Do(_, _, _, pos)
| Self::For(_, _, pos) | Self::For(_, _, pos)
| Self::Return(_, _, pos) | Self::Return(_, _, pos)
| Self::Let(_, _, _, pos) | Self::Var(_, _, _, _, pos)
| Self::Const(_, _, _, pos)
| Self::TryCatch(_, pos) => *pos, | Self::TryCatch(_, pos) => *pos,
Self::Expr(x) => x.position(), Self::Expr(x) => x.position(),
@ -1088,8 +1097,7 @@ impl Stmt {
| Self::Do(_, _, _, pos) | Self::Do(_, _, _, pos)
| Self::For(_, _, pos) | Self::For(_, _, pos)
| Self::Return(_, _, pos) | Self::Return(_, _, pos)
| Self::Let(_, _, _, pos) | Self::Var(_, _, _, _, pos)
| Self::Const(_, _, _, pos)
| Self::TryCatch(_, pos) => *pos = new_pos, | Self::TryCatch(_, pos) => *pos = new_pos,
Self::Expr(x) => { Self::Expr(x) => {
@ -1123,8 +1131,7 @@ impl Stmt {
| Self::For(_, _, _) | Self::For(_, _, _)
| Self::TryCatch(_, _) => false, | Self::TryCatch(_, _) => false,
Self::Let(_, _, _, _) Self::Var(_, _, _, _, _)
| Self::Const(_, _, _, _)
| Self::Assignment(_, _) | Self::Assignment(_, _)
| Self::Continue(_) | Self::Continue(_)
| Self::Break(_) | Self::Break(_)
@ -1151,8 +1158,7 @@ impl Stmt {
// A No-op requires a semicolon in order to know it is an empty statement! // A No-op requires a semicolon in order to know it is an empty statement!
Self::Noop(_) => false, Self::Noop(_) => false,
Self::Let(_, _, _, _) Self::Var(_, _, _, _, _)
| Self::Const(_, _, _, _)
| Self::Assignment(_, _) | Self::Assignment(_, _)
| Self::FnCall(_, _) | Self::FnCall(_, _)
| Self::Expr(_) | Self::Expr(_)
@ -1193,10 +1199,7 @@ impl Stmt {
condition.is_pure() && block.0.iter().all(Stmt::is_pure) condition.is_pure() && block.0.iter().all(Stmt::is_pure)
} }
Self::For(iterable, x, _) => iterable.is_pure() && (x.2).0.iter().all(Stmt::is_pure), Self::For(iterable, x, _) => iterable.is_pure() && (x.2).0.iter().all(Stmt::is_pure),
Self::Let(_, _, _, _) Self::Var(_, _, _, _, _) | Self::Assignment(_, _) | Self::FnCall(_, _) => false,
| Self::Const(_, _, _, _)
| Self::Assignment(_, _)
| Self::FnCall(_, _) => false,
Self::Block(block, _) => block.iter().all(|stmt| stmt.is_pure()), Self::Block(block, _) => block.iter().all(|stmt| stmt.is_pure()),
Self::Continue(_) | Self::Break(_) | Self::Return(_, _, _) => false, Self::Continue(_) | Self::Break(_) | Self::Return(_, _, _) => false,
Self::TryCatch(x, _) => { Self::TryCatch(x, _) => {
@ -1222,7 +1225,7 @@ impl Stmt {
#[must_use] #[must_use]
pub fn is_internally_pure(&self) -> bool { pub fn is_internally_pure(&self) -> bool {
match self { match self {
Self::Let(expr, _, _, _) | Self::Const(expr, _, _, _) => expr.is_pure(), Self::Var(expr, _, _, _, _) => expr.is_pure(),
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
Self::Import(expr, _, _) => expr.is_pure(), Self::Import(expr, _, _) => expr.is_pure(),
@ -1260,7 +1263,7 @@ impl Stmt {
} }
match self { match self {
Self::Let(e, _, _, _) | Self::Const(e, _, _, _) => { Self::Var(e, _, _, _, _) => {
if !e.walk(path, on_node) { if !e.walk(path, on_node) {
return false; return false;
} }
@ -1375,7 +1378,7 @@ impl Stmt {
} }
} }
/// _(INTERNALS)_ A custom syntax expression. /// _(internals)_ A custom syntax expression.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
@ -1391,7 +1394,7 @@ pub struct CustomExpr {
pub tokens: StaticVec<Identifier>, pub tokens: StaticVec<Identifier>,
} }
/// _(INTERNALS)_ A binary expression. /// _(internals)_ A binary expression.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
@ -1405,7 +1408,7 @@ pub struct BinaryExpr {
pub rhs: Expr, pub rhs: Expr,
} }
/// _(INTERNALS)_ An op-assignment operator. /// _(internals)_ An op-assignment operator.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
@ -1443,7 +1446,7 @@ impl OpAssignment<'_> {
} }
} }
/// _(INTERNALS)_ An set of function call hashes. /// _(internals)_ An set of function call hashes.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// Two separate hashes are pre-calculated because of the following pattern: /// Two separate hashes are pre-calculated because of the following pattern:
@ -1530,7 +1533,7 @@ impl FnCallHashes {
} }
} }
/// _(INTERNALS)_ A function call. /// _(internals)_ A function call.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
@ -1686,7 +1689,7 @@ impl FloatWrapper<FLOAT> {
} }
} }
/// _(INTERNALS)_ An expression sub-tree. /// _(internals)_ An expression sub-tree.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure

View File

@ -46,7 +46,7 @@ mod private {
impl<T: Any + Clone + SendSync> Sealed for T {} impl<T: Any + Clone + SendSync> Sealed for T {}
} }
/// _(INTERNALS)_ Trait to represent any type. /// _(internals)_ Trait to represent any type.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// This trait is sealed and cannot be implemented. /// This trait is sealed and cannot be implemented.
@ -80,7 +80,7 @@ pub trait Variant: Any + private::Sealed {
fn clone_into_dynamic(&self) -> Dynamic; fn clone_into_dynamic(&self) -> Dynamic;
} }
/// _(INTERNALS)_ Trait to represent any type. /// _(internals)_ Trait to represent any type.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// This trait is sealed and cannot be implemented. /// This trait is sealed and cannot be implemented.
@ -189,7 +189,7 @@ pub enum Union {
/// Not available under `no_float`. /// Not available under `no_float`.
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
Float(FloatWrapper<FLOAT>, Tag, AccessMode), Float(FloatWrapper<FLOAT>, Tag, AccessMode),
/// _(DECIMAL)_ A fixed-precision decimal value. /// _(decimal)_ A fixed-precision decimal value.
/// Exported under the `decimal` feature only. /// Exported under the `decimal` feature only.
#[cfg(feature = "decimal")] #[cfg(feature = "decimal")]
Decimal(Box<Decimal>, Tag, AccessMode), Decimal(Box<Decimal>, Tag, AccessMode),
@ -222,7 +222,7 @@ pub enum Union {
Shared(crate::Shared<crate::Locked<Dynamic>>, Tag, AccessMode), Shared(crate::Shared<crate::Locked<Dynamic>>, Tag, AccessMode),
} }
/// _(INTERNALS)_ Lock guard for reading a [`Dynamic`]. /// _(internals)_ Lock guard for reading a [`Dynamic`].
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// This type provides transparent interoperability between normal [`Dynamic`] and shared /// This type provides transparent interoperability between normal [`Dynamic`] and shared
@ -265,7 +265,7 @@ impl<'d, T: Any + Clone> Deref for DynamicReadLock<'d, T> {
} }
} }
/// _(INTERNALS)_ Lock guard for writing a [`Dynamic`]. /// _(internals)_ Lock guard for writing a [`Dynamic`].
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// This type provides transparent interoperability between normal [`Dynamic`] and shared /// This type provides transparent interoperability between normal [`Dynamic`] and shared
@ -1762,7 +1762,7 @@ impl Dynamic {
_ => Err(self.type_name()), _ => Err(self.type_name()),
} }
} }
/// _(DECIMAL)_ Cast the [`Dynamic`] as a [`Decimal`] and return it. /// _(decimal)_ Cast the [`Dynamic`] as a [`Decimal`](https://docs.rs/rust_decimal) and return it.
/// Returns the name of the actual type if the cast fails. /// Returns the name of the actual type if the cast fails.
/// ///
/// Exported under the `decimal` feature only. /// Exported under the `decimal` feature only.

View File

@ -1,6 +1,6 @@
//! Main module defining the script evaluation [`Engine`]. //! Main module defining the script evaluation [`Engine`].
use crate::ast::{Expr, FnCallExpr, Ident, OpAssignment, ReturnType, Stmt}; use crate::ast::{Expr, FnCallExpr, Ident, OpAssignment, ReturnType, Stmt, VarDeclaration};
use crate::custom_syntax::CustomSyntax; use crate::custom_syntax::CustomSyntax;
use crate::dynamic::{map_std_type_name, AccessMode, Union, Variant}; use crate::dynamic::{map_std_type_name, AccessMode, Union, Variant};
use crate::fn_hash::get_hasher; use crate::fn_hash::get_hasher;
@ -40,7 +40,7 @@ use crate::ast::FnCallHashes;
pub type Precedence = NonZeroU8; pub type Precedence = NonZeroU8;
/// _(INTERNALS)_ A stack of imported [modules][Module]. /// _(internals)_ A stack of imported [modules][Module].
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
@ -620,7 +620,7 @@ impl<T: Into<Dynamic>> From<T> for Target<'_> {
} }
} }
/// _(INTERNALS)_ An entry in a function resolution cache. /// _(internals)_ An entry in a function resolution cache.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
@ -634,7 +634,7 @@ pub struct FnResolutionCacheEntry {
pub source: Option<Identifier>, pub source: Option<Identifier>,
} }
/// _(INTERNALS)_ A function resolution cache. /// _(internals)_ A function resolution cache.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
@ -642,7 +642,7 @@ pub struct FnResolutionCacheEntry {
/// This type is volatile and may change. /// This type is volatile and may change.
pub type FnResolutionCache = BTreeMap<u64, Option<Box<FnResolutionCacheEntry>>>; pub type FnResolutionCache = BTreeMap<u64, Option<Box<FnResolutionCacheEntry>>>;
/// _(INTERNALS)_ A type that holds all the current states of the [`Engine`]. /// _(internals)_ A type that holds all the current states of the [`Engine`].
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
@ -653,19 +653,20 @@ pub struct EvalState {
/// Source of the current context. /// Source of the current context.
pub source: Option<Identifier>, pub source: Option<Identifier>,
/// Normally, access to variables are parsed with a relative offset into the [`Scope`] to avoid a lookup. /// 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. /// In some situation, e.g. after running an `eval` statement, or after a custom syntax statement,
/// subsequent offsets may become mis-aligned.
/// When that happens, this flag is turned on to force a [`Scope`] search by name. /// When that happens, this flag is turned on to force a [`Scope`] search by name.
pub always_search_scope: bool, pub always_search_scope: bool,
/// Level of the current scope. The global (root) level is zero, a new block (or function call) /// Level of the current scope. The global (root) level is zero, a new block (or function call)
/// is one level higher, and so on. /// is one level higher, and so on.
pub scope_level: usize, pub scope_level: usize,
/// Number of operations performed. /// Number of operations performed.
pub operations: u64, pub num_operations: u64,
/// Number of modules loaded. /// Number of modules loaded.
pub modules: usize, pub num_modules: usize,
/// Embedded module resolver. /// Embedded module resolver.
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
pub resolver: Option<Shared<crate::module::resolvers::StaticModuleResolver>>, pub embedded_module_resolver: Option<Shared<crate::module::resolvers::StaticModuleResolver>>,
/// Stack of function resolution caches. /// Stack of function resolution caches.
fn_resolution_caches: Vec<FnResolutionCache>, fn_resolution_caches: Vec<FnResolutionCache>,
} }
@ -679,10 +680,10 @@ impl EvalState {
source: None, source: None,
always_search_scope: false, always_search_scope: false,
scope_level: 0, scope_level: 0,
operations: 0, num_operations: 0,
modules: 0, num_modules: 0,
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
resolver: None, embedded_module_resolver: None,
fn_resolution_caches: Vec::new(), fn_resolution_caches: Vec::new(),
} }
} }
@ -723,7 +724,7 @@ impl EvalState {
} }
} }
/// _(INTERNALS)_ A type containing all the limits imposed by the [`Engine`]. /// _(internals)_ A type containing all the limits imposed by the [`Engine`].
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
@ -833,7 +834,7 @@ impl<'x, 'px, 'pt> EvalContext<'_, 'x, 'px, '_, '_, '_, '_, 'pt> {
pub fn iter_imports(&self) -> impl Iterator<Item = (&str, &Module)> { pub fn iter_imports(&self) -> impl Iterator<Item = (&str, &Module)> {
self.mods.iter() self.mods.iter()
} }
/// _(INTERNALS)_ The current set of modules imported via `import` statements. /// _(internals)_ The current set of modules imported via `import` statements.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
@ -847,7 +848,7 @@ impl<'x, 'px, 'pt> EvalContext<'_, 'x, 'px, '_, '_, '_, '_, 'pt> {
pub fn iter_namespaces(&self) -> impl Iterator<Item = &Module> { pub fn iter_namespaces(&self) -> impl Iterator<Item = &Module> {
self.lib.iter().cloned() self.lib.iter().cloned()
} }
/// _(INTERNALS)_ The current set of namespaces containing definitions of all script-defined functions. /// _(internals)_ The current set of namespaces containing definitions of all script-defined functions.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[inline(always)] #[inline(always)]
@ -2850,12 +2851,11 @@ impl Engine {
} }
// Let/const statement // Let/const statement
Stmt::Let(expr, x, export, _) | Stmt::Const(expr, x, export, _) => { Stmt::Var(expr, x, var_type, export, _) => {
let name = &x.name; let name = &x.name;
let entry_type = match stmt { let entry_type = match var_type {
Stmt::Let(_, _, _, _) => AccessMode::ReadWrite, VarDeclaration::Let => AccessMode::ReadWrite,
Stmt::Const(_, _, _, _) => AccessMode::ReadOnly, VarDeclaration::Const => AccessMode::ReadOnly,
_ => unreachable!("should be Stmt::Let or Stmt::Const, but gets {:?}", stmt),
}; };
let value = self let value = self
@ -2914,7 +2914,7 @@ impl Engine {
Stmt::Import(expr, export, _pos) => { Stmt::Import(expr, export, _pos) => {
// Guard against too many modules // Guard against too many modules
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if state.modules >= self.max_modules() { if state.num_modules >= self.max_modules() {
return EvalAltResult::ErrorTooManyModules(*_pos).into(); return EvalAltResult::ErrorTooManyModules(*_pos).into();
} }
@ -2928,7 +2928,7 @@ impl Engine {
let path_pos = expr.position(); let path_pos = expr.position();
let module = state let module = state
.resolver .embedded_module_resolver
.as_ref() .as_ref()
.and_then(|r| match r.resolve(self, source, &path, path_pos) { .and_then(|r| match r.resolve(self, source, &path, path_pos) {
Err(err) Err(err)
@ -2958,7 +2958,7 @@ impl Engine {
} }
} }
state.modules += 1; state.num_modules += 1;
Ok(Dynamic::UNIT) Ok(Dynamic::UNIT)
} else { } else {
@ -3130,16 +3130,16 @@ impl Engine {
state: &mut EvalState, state: &mut EvalState,
pos: Position, pos: Position,
) -> Result<(), Box<EvalAltResult>> { ) -> Result<(), Box<EvalAltResult>> {
state.operations += 1; state.num_operations += 1;
// Guard against too many operations // Guard against too many operations
if self.max_operations() > 0 && state.operations > self.max_operations() { if self.max_operations() > 0 && state.num_operations > self.max_operations() {
return EvalAltResult::ErrorTooManyOperations(pos).into(); return EvalAltResult::ErrorTooManyOperations(pos).into();
} }
// Report progress - only in steps // Report progress - only in steps
if let Some(ref progress) = self.progress { if let Some(ref progress) = self.progress {
if let Some(token) = progress(state.operations) { if let Some(token) = progress(state.num_operations) {
// Terminate script if progress returns a termination token // Terminate script if progress returns a termination token
return EvalAltResult::ErrorTerminated(token, pos).into(); return EvalAltResult::ErrorTerminated(token, pos).into();
} }

View File

@ -1729,7 +1729,7 @@ impl Engine {
state.source = ast.source_raw().cloned(); state.source = ast.source_raw().cloned();
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
{ {
state.resolver = ast.resolver(); state.embedded_module_resolver = ast.resolver();
} }
let statements = ast.statements(); let statements = ast.statements();
@ -1811,7 +1811,7 @@ impl Engine {
state.source = ast.source_raw().cloned(); state.source = ast.source_raw().cloned();
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
{ {
state.resolver = ast.resolver(); state.embedded_module_resolver = ast.resolver();
} }
let statements = ast.statements(); let statements = ast.statements();
@ -2052,7 +2052,7 @@ impl Engine {
let stmt = std::mem::take(ast.statements_mut()); let stmt = std::mem::take(ast.statements_mut());
crate::optimize::optimize_into_ast(self, scope, stmt.into_vec(), lib, optimization_level) crate::optimize::optimize_into_ast(self, scope, stmt.into_vec(), lib, optimization_level)
} }
/// _(METADATA)_ Generate a list of all registered functions. /// _(metadata)_ Generate a list of all registered functions.
/// Exported under the `metadata` feature only. /// Exported under the `metadata` feature only.
/// ///
/// Functions from the following sources are included, in order: /// Functions from the following sources are included, in order:

View File

@ -9,7 +9,7 @@ use std::fmt;
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
/// _(INTERNALS)_ Error encountered when tokenizing the script text. /// _(internals)_ Error encountered when tokenizing the script text.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure

View File

@ -840,12 +840,12 @@ impl Engine {
// Evaluate the AST // Evaluate the AST
let mut new_state = EvalState::new(); let mut new_state = EvalState::new();
new_state.source = state.source.clone(); new_state.source = state.source.clone();
new_state.operations = state.operations; new_state.num_operations = state.num_operations;
let result = let result =
self.eval_global_statements(scope, mods, &mut new_state, statements, lib, level); self.eval_global_statements(scope, mods, &mut new_state, statements, lib, level);
state.operations = new_state.operations; state.num_operations = new_state.num_operations;
result result
} }

View File

@ -98,7 +98,7 @@ impl<'a> NativeCallContext<'a> {
lib, lib,
} }
} }
/// _(INTERNALS)_ Create a new [`NativeCallContext`]. /// _(internals)_ Create a new [`NativeCallContext`].
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// Not available under `no_module`. /// Not available under `no_module`.
@ -156,7 +156,7 @@ impl<'a> NativeCallContext<'a> {
) -> impl Iterator<Item = (&crate::Identifier, &Shared<Module>)> { ) -> impl Iterator<Item = (&crate::Identifier, &Shared<Module>)> {
self.mods.iter().flat_map(|&m| m.iter_raw()) self.mods.iter().flat_map(|&m| m.iter_raw())
} }
/// _(INTERNALS)_ The current set of modules imported via `import` statements. /// _(internals)_ The current set of modules imported via `import` statements.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// Not available under `no_module`. /// Not available under `no_module`.
@ -172,7 +172,7 @@ impl<'a> NativeCallContext<'a> {
pub fn iter_namespaces(&self) -> impl Iterator<Item = &Module> { pub fn iter_namespaces(&self) -> impl Iterator<Item = &Module> {
self.lib.iter().cloned() self.lib.iter().cloned()
} }
/// _(INTERNALS)_ The current set of namespaces containing definitions of all script-defined functions. /// _(internals)_ The current set of namespaces containing definitions of all script-defined functions.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[inline(always)] #[inline(always)]

View File

@ -71,17 +71,17 @@ pub trait RegisterNativeFunction<Args, Result> {
/// Get the type ID's of this function's parameters. /// Get the type ID's of this function's parameters.
#[must_use] #[must_use]
fn param_types() -> Box<[TypeId]>; fn param_types() -> Box<[TypeId]>;
/// _(METADATA)_ Get the type names of this function's parameters. /// _(metadata)_ Get the type names of this function's parameters.
/// Exported under the `metadata` feature only. /// Exported under the `metadata` feature only.
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
#[must_use] #[must_use]
fn param_names() -> Box<[&'static str]>; fn param_names() -> Box<[&'static str]>;
/// _(METADATA)_ Get the type ID of this function's return value. /// _(metadata)_ Get the type ID of this function's return value.
/// Exported under the `metadata` feature only. /// Exported under the `metadata` feature only.
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
#[must_use] #[must_use]
fn return_type() -> TypeId; fn return_type() -> TypeId;
/// _(METADATA)_ Get the type name of this function's return value. /// _(metadata)_ Get the type name of this function's return value.
/// Exported under the `metadata` feature only. /// Exported under the `metadata` feature only.
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
#[must_use] #[must_use]

View File

@ -228,7 +228,7 @@ pub use token::{InputStream, Token, TokenizeState, TokenizerControl, TokenizerCo
#[deprecated = "this type is volatile and may change"] #[deprecated = "this type is volatile and may change"]
pub use ast::{ pub use ast::{
ASTNode, BinaryExpr, CustomExpr, Expr, FloatWrapper, FnCallExpr, FnCallHashes, Ident, ASTNode, BinaryExpr, CustomExpr, Expr, FloatWrapper, FnCallExpr, FnCallHashes, Ident,
OpAssignment, ReturnType, ScriptFnDef, Stmt, StmtBlock, OpAssignment, ReturnType, ScriptFnDef, Stmt, StmtBlock, VarDeclaration,
}; };
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
@ -278,7 +278,7 @@ pub use module::NamespaceRef;
#[cfg(not(feature = "internals"))] #[cfg(not(feature = "internals"))]
type StaticVec<T> = smallvec::SmallVec<[T; 4]>; type StaticVec<T> = smallvec::SmallVec<[T; 4]>;
/// _(INTERNALS)_ Alias to [`smallvec`](https://crates.io/crates/smallvec), which is a specialized /// _(internals)_ Alias to [`smallvec`](https://crates.io/crates/smallvec), which is a specialized
/// [`Vec`] backed by a small, inline, fixed-size array when there are ≤ 4 items stored. /// [`Vec`] backed by a small, inline, fixed-size array when there are ≤ 4 items stored.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///

View File

@ -81,18 +81,18 @@ impl FuncInfo {
sig.push_str(") -> "); sig.push_str(") -> ");
sig.push_str(&return_type); sig.push_str(&return_type);
} else { } else {
sig.push_str(")"); sig.push(')');
} }
} else { } else {
for x in 0..self.params { for x in 0..self.params {
sig.push_str("_"); sig.push('_');
if x < self.params - 1 { if x < self.params - 1 {
sig.push_str(", "); sig.push_str(", ");
} }
} }
if self.func.is_script() { if self.func.is_script() {
sig.push_str(")"); sig.push(')');
} else { } else {
sig.push_str(") -> ?"); sig.push_str(") -> ?");
} }
@ -102,7 +102,7 @@ impl FuncInfo {
} }
} }
/// _(INTERNALS)_ Calculate a [`u64`] hash key from a namespace-qualified function name and /// _(internals)_ Calculate a [`u64`] hash key from a namespace-qualified function name and
/// parameter types. /// parameter types.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
@ -366,7 +366,6 @@ impl Module {
/// Exported under the `metadata` feature only. /// Exported under the `metadata` feature only.
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
#[inline(always)] #[inline(always)]
#[must_use]
pub fn gen_fn_signatures(&self) -> impl Iterator<Item = String> + '_ { pub fn gen_fn_signatures(&self) -> impl Iterator<Item = String> + '_ {
self.functions self.functions
.values() .values()
@ -630,9 +629,9 @@ impl Module {
.map(|&name| self.identifiers.get(name)) .map(|&name| self.identifiers.get(name))
.collect(); .collect();
self.functions if let Some(f) = self.functions.get_mut(&hash_fn) {
.get_mut(&hash_fn) f.param_names = param_names;
.map(|f| f.param_names = param_names); }
self self
} }
@ -1364,7 +1363,7 @@ impl Module {
.map(|f| (f.namespace, f.access, f.name.as_str(), f.params)) .map(|f| (f.namespace, f.access, f.name.as_str(), f.params))
} }
/// _(INTERNALS)_ Get an iterator over all script-defined functions in the [`Module`]. /// _(internals)_ Get an iterator over all script-defined functions in the [`Module`].
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// Function metadata includes: /// Function metadata includes:
@ -1372,7 +1371,7 @@ impl Module {
/// 2) Access mode ([`FnAccess::Public`] or [`FnAccess::Private`]). /// 2) Access mode ([`FnAccess::Public`] or [`FnAccess::Private`]).
/// 3) Function name (as string slice). /// 3) Function name (as string slice).
/// 4) Number of parameters. /// 4) Number of parameters.
/// 5) _(INTERNALS)_ Shared reference to function definition [`ScriptFnDef`][crate::ast::ScriptFnDef]. /// 5) _(internals)_ Shared reference to function definition [`ScriptFnDef`][crate::ast::ScriptFnDef].
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[inline(always)] #[inline(always)]
@ -1653,7 +1652,7 @@ impl Module {
} }
} }
/// _(INTERNALS)_ A chain of [module][Module] names to namespace-qualify a variable or function call. /// _(internals)_ A chain of [module][Module] names to namespace-qualify a variable or function call.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// A [`u64`] offset to the current [`Scope`][crate::Scope] is cached for quick search purposes. /// A [`u64`] offset to the current [`Scope`][crate::Scope] is cached for quick search purposes.

View File

@ -1,4 +1,6 @@
use crate::{Engine, EvalAltResult, Identifier, Module, ModuleResolver, Position, Shared}; use crate::{
Engine, EvalAltResult, Identifier, Module, ModuleResolver, Position, Shared, SmartString,
};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
use std::{collections::BTreeMap, ops::AddAssign}; use std::{collections::BTreeMap, ops::AddAssign};
@ -72,11 +74,6 @@ impl StaticModuleResolver {
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&str, &mut Shared<Module>)> { pub fn iter_mut(&mut self) -> impl Iterator<Item = (&str, &mut Shared<Module>)> {
self.0.iter_mut().map(|(k, v)| (k.as_str(), v)) self.0.iter_mut().map(|(k, v)| (k.as_str(), v))
} }
/// Get a mutable iterator of all the modules.
#[inline(always)]
pub fn into_iter(self) -> impl Iterator<Item = (Identifier, Shared<Module>)> {
self.0.into_iter()
}
/// Get an iterator of all the [module][Module] paths. /// Get an iterator of all the [module][Module] paths.
#[inline(always)] #[inline(always)]
pub fn paths(&self) -> impl Iterator<Item = &str> { pub fn paths(&self) -> impl Iterator<Item = &str> {
@ -117,6 +114,15 @@ impl StaticModuleResolver {
} }
} }
impl IntoIterator for StaticModuleResolver {
type Item = (Identifier, Shared<Module>);
type IntoIter = std::collections::btree_map::IntoIter<SmartString, Shared<Module>>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl ModuleResolver for StaticModuleResolver { impl ModuleResolver for StaticModuleResolver {
#[inline(always)] #[inline(always)]
fn resolve( fn resolve(

View File

@ -1,6 +1,6 @@
//! Module implementing the [`AST`] optimizer. //! Module implementing the [`AST`] optimizer.
use crate::ast::{Expr, OpAssignment, Stmt}; use crate::ast::{Expr, OpAssignment, Stmt, VarDeclaration};
use crate::dynamic::AccessMode; use crate::dynamic::AccessMode;
use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF}; use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF};
use crate::fn_builtin::get_builtin_binary_op_fn; use crate::fn_builtin::get_builtin_binary_op_fn;
@ -202,7 +202,7 @@ fn optimize_stmt_block(
statements.iter_mut().for_each(|stmt| { statements.iter_mut().for_each(|stmt| {
match stmt { match stmt {
// Add constant literals into the state // Add constant literals into the state
Stmt::Const(value_expr, x, _, _) => { Stmt::Var(value_expr, x, VarDeclaration::Const, _, _) => {
optimize_expr(value_expr, state, false); optimize_expr(value_expr, state, false);
if value_expr.is_constant() { if value_expr.is_constant() {
@ -214,7 +214,7 @@ fn optimize_stmt_block(
} }
} }
// Add variables into the state // Add variables into the state
Stmt::Let(value_expr, x, _, _) => { Stmt::Var(value_expr, x, VarDeclaration::Let, _, _) => {
optimize_expr(value_expr, state, false); optimize_expr(value_expr, state, false);
state.push_var(&x.name, AccessMode::ReadWrite, None); state.push_var(&x.name, AccessMode::ReadWrite, None);
} }
@ -232,11 +232,7 @@ fn optimize_stmt_block(
.find_map(|(i, stmt)| match stmt { .find_map(|(i, stmt)| match stmt {
stmt if !is_pure(stmt) => Some(i), stmt if !is_pure(stmt) => Some(i),
Stmt::Let(e, _, _, _) | Stmt::Const(e, _, _, _) | Stmt::Expr(e) Stmt::Var(e, _, _, _, _) | Stmt::Expr(e) if !e.is_constant() => Some(i),
if !e.is_constant() =>
{
Some(i)
}
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
Stmt::Import(e, _, _) if !e.is_constant() => Some(i), Stmt::Import(e, _, _) if !e.is_constant() => Some(i),
@ -609,7 +605,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
*x.2.statements_mut() = optimize_stmt_block(body, state, false, true, false).into(); *x.2.statements_mut() = optimize_stmt_block(body, state, false, true, false).into();
} }
// let id = expr; // let id = expr;
Stmt::Let(expr, _, _, _) => optimize_expr(expr, state, false), Stmt::Var(expr, _, VarDeclaration::Let, _, _) => optimize_expr(expr, state, false),
// import expr as var; // import expr as var;
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
Stmt::Import(expr, _, _) => optimize_expr(expr, state, false), Stmt::Import(expr, _, _) => optimize_expr(expr, state, false),

View File

@ -2,7 +2,7 @@
use crate::ast::{ use crate::ast::{
BinaryExpr, CustomExpr, Expr, FnCallExpr, FnCallHashes, Ident, OpAssignment, ReturnType, BinaryExpr, CustomExpr, Expr, FnCallExpr, FnCallHashes, Ident, OpAssignment, ReturnType,
ScriptFnDef, Stmt, StmtBlock, ScriptFnDef, Stmt, StmtBlock, VarDeclaration,
}; };
use crate::custom_syntax::{ use crate::custom_syntax::{
CustomSyntax, CUSTOM_SYNTAX_MARKER_BLOCK, CUSTOM_SYNTAX_MARKER_BOOL, CUSTOM_SYNTAX_MARKER_EXPR, CustomSyntax, CUSTOM_SYNTAX_MARKER_BLOCK, CUSTOM_SYNTAX_MARKER_BOOL, CUSTOM_SYNTAX_MARKER_EXPR,
@ -2115,15 +2115,13 @@ fn parse_expr(
match token { match token {
Token::Custom(key) | Token::Reserved(key) | Token::Identifier(key) => { Token::Custom(key) | Token::Reserved(key) | Token::Identifier(key) => {
match state.engine.custom_syntax.get_key_value(key.as_str()) { if let Some((key, syntax)) = state.engine.custom_syntax.get_key_value(key.as_str())
Some((key, syntax)) => { {
input.next().expect(NEVER_ENDS); input.next().expect(NEVER_ENDS);
return parse_custom_syntax( return parse_custom_syntax(
input, state, lib, settings, key, syntax, token_pos, input, state, lib, settings, key, syntax, token_pos,
); );
} }
_ => (),
}
} }
_ => (), _ => (),
} }
@ -2385,9 +2383,21 @@ fn parse_let(
match var_type { match var_type {
// let name = expr // let name = expr
AccessMode::ReadWrite => Ok(Stmt::Let(expr, var_def.into(), export, settings.pos)), AccessMode::ReadWrite => Ok(Stmt::Var(
expr,
var_def.into(),
VarDeclaration::Let,
export,
settings.pos,
)),
// const name = { expr:constant } // const name = { expr:constant }
AccessMode::ReadOnly => Ok(Stmt::Const(expr, var_def.into(), export, settings.pos)), AccessMode::ReadOnly => Ok(Stmt::Var(
expr,
var_def.into(),
VarDeclaration::Const,
export,
settings.pos,
)),
} }
} }

View File

@ -33,12 +33,10 @@ impl<'de> DynamicDeserializer<'de> {
Self { value } Self { value }
} }
/// Shortcut for a type conversion error. /// Shortcut for a type conversion error.
#[must_use]
fn type_error<T>(&self) -> Result<T, Box<EvalAltResult>> { fn type_error<T>(&self) -> Result<T, Box<EvalAltResult>> {
self.type_error_str(type_name::<T>()) self.type_error_str(type_name::<T>())
} }
/// Shortcut for a type conversion error. /// Shortcut for a type conversion error.
#[must_use]
fn type_error_str<T>(&self, error: &str) -> Result<T, Box<EvalAltResult>> { fn type_error_str<T>(&self, error: &str) -> Result<T, Box<EvalAltResult>> {
EvalAltResult::ErrorMismatchOutputType( EvalAltResult::ErrorMismatchOutputType(
error.into(), error.into(),
@ -47,7 +45,6 @@ impl<'de> DynamicDeserializer<'de> {
) )
.into() .into()
} }
#[must_use]
fn deserialize_int<V: Visitor<'de>>( fn deserialize_int<V: Visitor<'de>>(
&mut self, &mut self,
v: crate::INT, v: crate::INT,
@ -111,7 +108,6 @@ impl<'de> DynamicDeserializer<'de> {
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
#[must_use]
pub fn from_dynamic<'de, T: Deserialize<'de>>( pub fn from_dynamic<'de, T: Deserialize<'de>>(
value: &'de Dynamic, value: &'de Dynamic,
) -> Result<T, Box<EvalAltResult>> { ) -> Result<T, Box<EvalAltResult>> {

View File

@ -40,12 +40,14 @@ impl<'d> Visitor<'d> for DynamicVisitor {
} }
fn visit_i64<E: Error>(self, v: i64) -> Result<Self::Value, E> { fn visit_i64<E: Error>(self, v: i64) -> Result<Self::Value, E> {
#[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i32"))]
return Ok(v.into()); {
Ok(v.into())
}
#[cfg(feature = "only_i32")] #[cfg(feature = "only_i32")]
if v > i32::MAX as i64 { if v > i32::MAX as i64 {
return Ok(Dynamic::from(v)); Ok(Dynamic::from(v))
} else { } else {
return self.visit_i32(v as i32); self.visit_i32(v as i32)
} }
} }
fn visit_u8<E: Error>(self, v: u8) -> Result<Self::Value, E> { fn visit_u8<E: Error>(self, v: u8) -> Result<Self::Value, E> {
@ -56,26 +58,28 @@ impl<'d> Visitor<'d> for DynamicVisitor {
} }
fn visit_u32<E: Error>(self, v: u32) -> Result<Self::Value, E> { fn visit_u32<E: Error>(self, v: u32) -> Result<Self::Value, E> {
#[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i32"))]
return Ok(INT::from(v).into()); {
Ok(INT::from(v).into())
}
#[cfg(feature = "only_i32")] #[cfg(feature = "only_i32")]
if v > i32::MAX as u32 { if v > i32::MAX as u32 {
return Ok(Dynamic::from(v)); Ok(Dynamic::from(v))
} else { } else {
return self.visit_i32(v as i32); self.visit_i32(v as i32)
} }
} }
fn visit_u64<E: Error>(self, v: u64) -> Result<Self::Value, E> { fn visit_u64<E: Error>(self, v: u64) -> Result<Self::Value, E> {
#[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i32"))]
if v > i64::MAX as u64 { if v > i64::MAX as u64 {
return Ok(Dynamic::from(v)); Ok(Dynamic::from(v))
} else { } else {
return self.visit_i64(v as i64); self.visit_i64(v as i64)
} }
#[cfg(feature = "only_i32")] #[cfg(feature = "only_i32")]
if v > i32::MAX as u64 { if v > i32::MAX as u64 {
return Ok(Dynamic::from(v)); Ok(Dynamic::from(v))
} else { } else {
return self.visit_i32(v as i32); self.visit_i32(v as i32)
} }
} }

View File

@ -43,7 +43,7 @@ impl From<crate::FnAccess> for FnAccess {
} }
} }
#[derive(Debug, Clone, Eq, PartialEq, Ord, Hash, Serialize, Deserialize)] #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
struct FnParam { struct FnParam {
pub name: String, pub name: String,
@ -71,6 +71,15 @@ impl PartialOrd for FnParam {
} }
} }
impl Ord for FnParam {
fn cmp(&self, other: &Self) -> Ordering {
match self.name.cmp(&other.name) {
Ordering::Equal => self.typ.cmp(&other.typ),
cmp => cmp,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
struct FnMetadata { struct FnMetadata {
@ -128,7 +137,7 @@ impl From<&crate::module::FuncInfo> for FnMetadata {
let name = seg let name = seg
.next() .next()
.map(|s| s.trim().to_string()) .map(|s| s.trim().to_string())
.unwrap_or("_".to_string()); .unwrap_or_else(|| "_".to_string());
let typ = seg.next().map(|s| s.trim().to_string()); let typ = seg.next().map(|s| s.trim().to_string());
FnParam { name, typ } FnParam { name, typ }
}) })
@ -209,7 +218,7 @@ impl From<&crate::Module> for ModuleMetadata {
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
impl Engine { impl Engine {
/// _(METADATA)_ Generate a list of all functions (including those defined in an /// _(metadata)_ Generate a list of all functions (including those defined in an
/// [`AST`][crate::AST]) in JSON format. /// [`AST`][crate::AST]) in JSON format.
/// Exported under the `metadata` feature only. /// Exported under the `metadata` feature only.
/// ///
@ -218,7 +227,6 @@ impl Engine {
/// 2) Functions registered into the global namespace /// 2) Functions registered into the global namespace
/// 3) Functions in static modules /// 3) Functions in static modules
/// 4) Functions in global modules (optional) /// 4) Functions in global modules (optional)
#[must_use]
pub fn gen_fn_metadata_with_ast_to_json( pub fn gen_fn_metadata_with_ast_to_json(
&self, &self,
ast: &AST, ast: &AST,
@ -258,7 +266,6 @@ impl Engine {
/// 1) Functions registered into the global namespace /// 1) Functions registered into the global namespace
/// 2) Functions in static modules /// 2) Functions in static modules
/// 3) Functions in global modules (optional) /// 3) Functions in global modules (optional)
#[must_use]
pub fn gen_fn_metadata_to_json(&self, include_global: bool) -> serde_json::Result<String> { pub fn gen_fn_metadata_to_json(&self, include_global: bool) -> serde_json::Result<String> {
self.gen_fn_metadata_with_ast_to_json(&Default::default(), include_global) self.gen_fn_metadata_with_ast_to_json(&Default::default(), include_global)
} }

View File

@ -1,4 +1,4 @@
//! _(SERDE)_ Serialization and deserialization support for [`serde`](https://crates.io/crates/serde). //! _(serde)_ Serialization and deserialization support for [`serde`](https://crates.io/crates/serde).
//! Exported under the `serde` feature only. //! Exported under the `serde` feature only.
mod de; mod de;

View File

@ -82,7 +82,6 @@ impl DynamicSerializer {
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
#[must_use]
pub fn to_dynamic<T: Serialize>(value: T) -> RhaiResult { pub fn to_dynamic<T: Serialize>(value: T) -> RhaiResult {
let mut s = DynamicSerializer::new(Default::default()); let mut s = DynamicSerializer::new(Default::default());
value.serialize(&mut s) value.serialize(&mut s)
@ -138,27 +137,29 @@ impl Serializer for &mut DynamicSerializer {
fn serialize_i64(self, v: i64) -> Result<Self::Ok, Box<EvalAltResult>> { fn serialize_i64(self, v: i64) -> Result<Self::Ok, Box<EvalAltResult>> {
#[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i32"))]
return Ok(v.into()); {
Ok(v.into())
}
#[cfg(feature = "only_i32")] #[cfg(feature = "only_i32")]
if v > i32::MAX as i64 { if v > i32::MAX as i64 {
return Ok(Dynamic::from(v)); Ok(Dynamic::from(v))
} else { } else {
return self.serialize_i32(v as i32); self.serialize_i32(v as i32)
} }
} }
fn serialize_i128(self, v: i128) -> Result<Self::Ok, Box<EvalAltResult>> { fn serialize_i128(self, v: i128) -> Result<Self::Ok, Box<EvalAltResult>> {
#[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i32"))]
if v > i64::MAX as i128 { if v > i64::MAX as i128 {
return Ok(Dynamic::from(v)); Ok(Dynamic::from(v))
} else { } else {
return self.serialize_i64(v as i64); self.serialize_i64(v as i64)
} }
#[cfg(feature = "only_i32")] #[cfg(feature = "only_i32")]
if v > i32::MAX as i128 { if v > i32::MAX as i128 {
return Ok(Dynamic::from(v)); Ok(Dynamic::from(v))
} else { } else {
return self.serialize_i32(v as i32); self.serialize_i32(v as i32)
} }
} }
@ -178,42 +179,44 @@ impl Serializer for &mut DynamicSerializer {
fn serialize_u32(self, v: u32) -> Result<Self::Ok, Box<EvalAltResult>> { fn serialize_u32(self, v: u32) -> Result<Self::Ok, Box<EvalAltResult>> {
#[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i32"))]
return self.serialize_i64(i64::from(v)); {
self.serialize_i64(i64::from(v))
}
#[cfg(feature = "only_i32")] #[cfg(feature = "only_i32")]
if v > i32::MAX as u32 { if v > i32::MAX as u32 {
return Ok(Dynamic::from(v)); Ok(Dynamic::from(v))
} else { } else {
return self.serialize_i32(v as i32); self.serialize_i32(v as i32)
} }
} }
fn serialize_u64(self, v: u64) -> Result<Self::Ok, Box<EvalAltResult>> { fn serialize_u64(self, v: u64) -> Result<Self::Ok, Box<EvalAltResult>> {
#[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i32"))]
if v > i64::MAX as u64 { if v > i64::MAX as u64 {
return Ok(Dynamic::from(v)); Ok(Dynamic::from(v))
} else { } else {
return self.serialize_i64(v as i64); self.serialize_i64(v as i64)
} }
#[cfg(feature = "only_i32")] #[cfg(feature = "only_i32")]
if v > i32::MAX as u64 { if v > i32::MAX as u64 {
return Ok(Dynamic::from(v)); Ok(Dynamic::from(v))
} else { } else {
return self.serialize_i32(v as i32); self.serialize_i32(v as i32)
} }
} }
fn serialize_u128(self, v: u128) -> Result<Self::Ok, Box<EvalAltResult>> { fn serialize_u128(self, v: u128) -> Result<Self::Ok, Box<EvalAltResult>> {
#[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i32"))]
if v > i64::MAX as u128 { if v > i64::MAX as u128 {
return Ok(Dynamic::from(v)); Ok(Dynamic::from(v))
} else { } else {
return self.serialize_i64(v as i64); self.serialize_i64(v as i64)
} }
#[cfg(feature = "only_i32")] #[cfg(feature = "only_i32")]
if v > i32::MAX as u128 { if v > i32::MAX as u128 {
return Ok(Dynamic::from(v)); Ok(Dynamic::from(v))
} else { } else {
return self.serialize_i32(v as i32); self.serialize_i32(v as i32)
} }
} }

View File

@ -18,7 +18,6 @@ impl<'a> StringSliceDeserializer<'a> {
Self { value } Self { value }
} }
/// Shortcut for a type conversion error. /// Shortcut for a type conversion error.
#[must_use]
fn type_error<T>(&self) -> Result<T, Box<EvalAltResult>> { fn type_error<T>(&self) -> Result<T, Box<EvalAltResult>> {
EvalAltResult::ErrorMismatchOutputType( EvalAltResult::ErrorMismatchOutputType(
type_name::<T>().into(), type_name::<T>().into(),

View File

@ -27,7 +27,7 @@ use rust_decimal::Decimal;
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
use crate::engine::KEYWORD_IS_DEF_FN; use crate::engine::KEYWORD_IS_DEF_FN;
/// _(INTERNALS)_ A type containing commands to control the tokenizer. /// _(internals)_ A type containing commands to control the tokenizer.
#[derive(Debug, Clone, Eq, PartialEq, Hash, Copy, Default)] #[derive(Debug, Clone, Eq, PartialEq, Hash, Copy, Default)]
pub struct TokenizerControlBlock { pub struct TokenizerControlBlock {
/// Is the current tokenizer position within an interpolated text string? /// Is the current tokenizer position within an interpolated text string?
@ -35,7 +35,7 @@ pub struct TokenizerControlBlock {
pub is_within_text: bool, pub is_within_text: bool,
} }
/// _(INTERNALS)_ A shared object that allows control of the tokenizer from outside. /// _(internals)_ A shared object that allows control of the tokenizer from outside.
pub type TokenizerControl = Rc<Cell<TokenizerControlBlock>>; pub type TokenizerControl = Rc<Cell<TokenizerControlBlock>>;
type LERR = LexError; type LERR = LexError;
@ -283,7 +283,7 @@ impl AddAssign for Position {
} }
} }
/// _(INTERNALS)_ A Rhai language token. /// _(internals)_ A Rhai language token.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
@ -980,7 +980,7 @@ impl From<Token> for String {
} }
} }
/// _(INTERNALS)_ State of the tokenizer. /// _(internals)_ State of the tokenizer.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
@ -1000,7 +1000,7 @@ pub struct TokenizeState {
pub is_within_text_terminated_by: Option<char>, pub is_within_text_terminated_by: Option<char>,
} }
/// _(INTERNALS)_ Trait that encapsulates a peekable character input stream. /// _(internals)_ Trait that encapsulates a peekable character input stream.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
@ -1018,7 +1018,7 @@ pub trait InputStream {
fn peek_next(&mut self) -> Option<char>; fn peek_next(&mut self) -> Option<char>;
} }
/// _(INTERNALS)_ Parse a string literal ended by `termination_char`. /// _(internals)_ Parse a string literal ended by `termination_char`.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// Returns the parsed string and a boolean indicating whether the string is /// Returns the parsed string and a boolean indicating whether the string is
@ -1281,22 +1281,22 @@ fn scan_block_comment(
match c { match c {
'/' => { '/' => {
stream.peek_next().filter(|&c2| c2 == '*').map(|c2| { if let Some(c2) = stream.peek_next().filter(|&c2| c2 == '*') {
eat_next(stream, pos); eat_next(stream, pos);
if let Some(comment) = comment.as_mut() { if let Some(comment) = comment.as_mut() {
comment.push(c2); comment.push(c2);
} }
level += 1; level += 1;
}); }
} }
'*' => { '*' => {
stream.peek_next().filter(|&c2| c2 == '/').map(|c2| { if let Some(c2) = stream.peek_next().filter(|&c2| c2 == '/') {
eat_next(stream, pos); eat_next(stream, pos);
if let Some(comment) = comment.as_mut() { if let Some(comment) = comment.as_mut() {
comment.push(c2); comment.push(c2);
} }
level -= 1; level -= 1;
}); }
} }
'\n' => pos.new_line(), '\n' => pos.new_line(),
_ => (), _ => (),
@ -1310,7 +1310,7 @@ fn scan_block_comment(
level level
} }
/// _(INTERNALS)_ Get the next token from the `stream`. /// _(internals)_ Get the next token from the `stream`.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
/// # Volatile API /// # Volatile API
@ -2234,7 +2234,7 @@ impl<'a> Iterator for TokenIterator<'a> {
impl FusedIterator for TokenIterator<'_> {} impl FusedIterator for TokenIterator<'_> {}
impl Engine { impl Engine {
/// _(INTERNALS)_ Tokenize an input text stream. /// _(internals)_ Tokenize an input text stream.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[inline(always)] #[inline(always)]
@ -2245,7 +2245,7 @@ impl Engine {
) -> (TokenIterator<'a>, TokenizerControl) { ) -> (TokenIterator<'a>, TokenizerControl) {
self.lex_raw(input, None) self.lex_raw(input, None)
} }
/// _(INTERNALS)_ Tokenize an input text stream with a mapping function. /// _(internals)_ Tokenize an input text stream with a mapping function.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[inline(always)] #[inline(always)]

View File

@ -86,7 +86,7 @@ fn test_optimizer_parse() -> Result<(), Box<EvalAltResult>> {
assert_eq!( assert_eq!(
format!("{:?}", ast), format!("{:?}", ast),
r#"AST { source: None, body: Block[Const(false @ 1:18, "DECISION" @ 1:7, false, 1:1), Expr(123 @ 1:51)], functions: Module, resolver: None }"# r#"AST { source: None, body: Block[Var(false @ 1:18, "DECISION" @ 1:7, Const, false, 1:1), Expr(123 @ 1:51)], functions: Module, resolver: None }"#
); );
let ast = engine.compile("if 1 == 2 { 42 }")?; let ast = engine.compile("if 1 == 2 { 42 }")?;