commit
abb4884869
@ -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
|
||||||
|
@ -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"
|
|
@ -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.
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
77
src/ast.rs
77
src/ast.rs
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)]
|
||||||
|
@ -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]
|
||||||
|
@ -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.
|
||||||
///
|
///
|
||||||
|
@ -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.
|
||||||
|
@ -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(
|
||||||
|
@ -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),
|
||||||
|
24
src/parse.rs
24
src/parse.rs
@ -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,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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>> {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(),
|
||||||
|
26
src/token.rs
26
src/token.rs
@ -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)]
|
||||||
|
@ -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 }")?;
|
||||||
|
Loading…
Reference in New Issue
Block a user