commit
abb4884869
@ -98,10 +98,10 @@ features = ["maths"]
|
||||
optional = true
|
||||
|
||||
[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]
|
||||
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]
|
||||
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,
|
||||
}
|
||||
|
||||
/// _(INTERNALS)_ A type containing information on a scripted function.
|
||||
/// _(internals)_ A type containing information on a scripted function.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// # Volatile Data Structure
|
||||
@ -68,7 +68,7 @@ pub struct ScriptFnDef {
|
||||
/// Not available under `no_closure`.
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
pub externals: std::collections::BTreeSet<Identifier>,
|
||||
/// _(METADATA)_ Function doc-comments (if any).
|
||||
/// _(metadata)_ Function doc-comments (if any).
|
||||
/// Exported under the `metadata` feature only.
|
||||
///
|
||||
/// Not available under `no_function`.
|
||||
@ -104,7 +104,7 @@ impl fmt::Display for ScriptFnDef {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
|
||||
pub struct ScriptFnMetadata<'a> {
|
||||
/// _(METADATA)_ Function doc-comments (if any).
|
||||
/// _(metadata)_ Function doc-comments (if any).
|
||||
/// Exported under the `metadata` feature only.
|
||||
///
|
||||
/// Not available under `no_function`.
|
||||
@ -278,7 +278,7 @@ impl AST {
|
||||
pub(crate) fn statements(&self) -> &[Stmt] {
|
||||
&self.body.0
|
||||
}
|
||||
/// _(INTERNALS)_ Get the statements.
|
||||
/// _(internals)_ Get the statements.
|
||||
/// Exported under the `internals` feature only.
|
||||
#[cfg(feature = "internals")]
|
||||
#[deprecated = "this method is volatile and may change"]
|
||||
@ -303,7 +303,7 @@ impl AST {
|
||||
pub(crate) fn shared_lib(&self) -> Shared<Module> {
|
||||
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.
|
||||
///
|
||||
/// Not available under `no_function` or `no_module`.
|
||||
@ -323,7 +323,7 @@ impl AST {
|
||||
pub(crate) fn lib(&self) -> &Module {
|
||||
&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.
|
||||
///
|
||||
/// Not available under `no_function`.
|
||||
@ -344,7 +344,7 @@ impl AST {
|
||||
) -> Option<Shared<crate::module::resolvers::StaticModuleResolver>> {
|
||||
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.
|
||||
///
|
||||
/// Not available under `no_module`.
|
||||
@ -762,7 +762,7 @@ impl AST {
|
||||
|
||||
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.
|
||||
/// Exported under the `internals` feature only.
|
||||
#[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.
|
||||
///
|
||||
/// # 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.
|
||||
///
|
||||
/// # Volatile Data Structure
|
||||
@ -851,7 +851,7 @@ pub enum ReturnType {
|
||||
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.
|
||||
///
|
||||
/// # 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.
|
||||
///
|
||||
/// # 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.
|
||||
///
|
||||
/// # Volatile Data Structure
|
||||
@ -974,10 +986,8 @@ pub enum Stmt {
|
||||
Do(Box<StmtBlock>, Expr, bool, Position),
|
||||
/// `for` `(` id `,` counter `)` `in` expr `{` stmt `}`
|
||||
For(Expr, Box<(Ident, Option<Ident>, StmtBlock)>, Position),
|
||||
/// \[`export`\] `let` id `=` expr
|
||||
Let(Expr, Box<Ident>, bool, Position),
|
||||
/// \[`export`\] `const` id `=` expr
|
||||
Const(Expr, Box<Ident>, bool, Position),
|
||||
/// \[`export`\] `let`/`const` id `=` expr
|
||||
Var(Expr, Box<Ident>, VarDeclaration, bool, Position),
|
||||
/// expr op`=` expr
|
||||
Assignment(Box<(Expr, Option<OpAssignment<'static>>, Expr)>, Position),
|
||||
/// func `(` expr `,` ... `)`
|
||||
@ -1058,8 +1068,7 @@ impl Stmt {
|
||||
| Self::Do(_, _, _, pos)
|
||||
| Self::For(_, _, pos)
|
||||
| Self::Return(_, _, pos)
|
||||
| Self::Let(_, _, _, pos)
|
||||
| Self::Const(_, _, _, pos)
|
||||
| Self::Var(_, _, _, _, pos)
|
||||
| Self::TryCatch(_, pos) => *pos,
|
||||
|
||||
Self::Expr(x) => x.position(),
|
||||
@ -1088,8 +1097,7 @@ impl Stmt {
|
||||
| Self::Do(_, _, _, pos)
|
||||
| Self::For(_, _, pos)
|
||||
| Self::Return(_, _, pos)
|
||||
| Self::Let(_, _, _, pos)
|
||||
| Self::Const(_, _, _, pos)
|
||||
| Self::Var(_, _, _, _, pos)
|
||||
| Self::TryCatch(_, pos) => *pos = new_pos,
|
||||
|
||||
Self::Expr(x) => {
|
||||
@ -1123,8 +1131,7 @@ impl Stmt {
|
||||
| Self::For(_, _, _)
|
||||
| Self::TryCatch(_, _) => false,
|
||||
|
||||
Self::Let(_, _, _, _)
|
||||
| Self::Const(_, _, _, _)
|
||||
Self::Var(_, _, _, _, _)
|
||||
| Self::Assignment(_, _)
|
||||
| Self::Continue(_)
|
||||
| Self::Break(_)
|
||||
@ -1151,8 +1158,7 @@ impl Stmt {
|
||||
// A No-op requires a semicolon in order to know it is an empty statement!
|
||||
Self::Noop(_) => false,
|
||||
|
||||
Self::Let(_, _, _, _)
|
||||
| Self::Const(_, _, _, _)
|
||||
Self::Var(_, _, _, _, _)
|
||||
| Self::Assignment(_, _)
|
||||
| Self::FnCall(_, _)
|
||||
| Self::Expr(_)
|
||||
@ -1193,10 +1199,7 @@ impl Stmt {
|
||||
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::Let(_, _, _, _)
|
||||
| Self::Const(_, _, _, _)
|
||||
| Self::Assignment(_, _)
|
||||
| Self::FnCall(_, _) => false,
|
||||
Self::Var(_, _, _, _, _) | Self::Assignment(_, _) | Self::FnCall(_, _) => false,
|
||||
Self::Block(block, _) => block.iter().all(|stmt| stmt.is_pure()),
|
||||
Self::Continue(_) | Self::Break(_) | Self::Return(_, _, _) => false,
|
||||
Self::TryCatch(x, _) => {
|
||||
@ -1222,7 +1225,7 @@ impl Stmt {
|
||||
#[must_use]
|
||||
pub fn is_internally_pure(&self) -> bool {
|
||||
match self {
|
||||
Self::Let(expr, _, _, _) | Self::Const(expr, _, _, _) => expr.is_pure(),
|
||||
Self::Var(expr, _, _, _, _) => expr.is_pure(),
|
||||
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
Self::Import(expr, _, _) => expr.is_pure(),
|
||||
@ -1260,7 +1263,7 @@ impl Stmt {
|
||||
}
|
||||
|
||||
match self {
|
||||
Self::Let(e, _, _, _) | Self::Const(e, _, _, _) => {
|
||||
Self::Var(e, _, _, _, _) => {
|
||||
if !e.walk(path, on_node) {
|
||||
return false;
|
||||
}
|
||||
@ -1375,7 +1378,7 @@ impl Stmt {
|
||||
}
|
||||
}
|
||||
|
||||
/// _(INTERNALS)_ A custom syntax expression.
|
||||
/// _(internals)_ A custom syntax expression.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// # Volatile Data Structure
|
||||
@ -1391,7 +1394,7 @@ pub struct CustomExpr {
|
||||
pub tokens: StaticVec<Identifier>,
|
||||
}
|
||||
|
||||
/// _(INTERNALS)_ A binary expression.
|
||||
/// _(internals)_ A binary expression.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// # Volatile Data Structure
|
||||
@ -1405,7 +1408,7 @@ pub struct BinaryExpr {
|
||||
pub rhs: Expr,
|
||||
}
|
||||
|
||||
/// _(INTERNALS)_ An op-assignment operator.
|
||||
/// _(internals)_ An op-assignment operator.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// # 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.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// # 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.
|
||||
///
|
||||
/// # Volatile Data Structure
|
||||
|
@ -46,7 +46,7 @@ mod private {
|
||||
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.
|
||||
///
|
||||
/// This trait is sealed and cannot be implemented.
|
||||
@ -80,7 +80,7 @@ pub trait Variant: Any + private::Sealed {
|
||||
fn clone_into_dynamic(&self) -> Dynamic;
|
||||
}
|
||||
|
||||
/// _(INTERNALS)_ Trait to represent any type.
|
||||
/// _(internals)_ Trait to represent any type.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// This trait is sealed and cannot be implemented.
|
||||
@ -189,7 +189,7 @@ pub enum Union {
|
||||
/// Not available under `no_float`.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
Float(FloatWrapper<FLOAT>, Tag, AccessMode),
|
||||
/// _(DECIMAL)_ A fixed-precision decimal value.
|
||||
/// _(decimal)_ A fixed-precision decimal value.
|
||||
/// Exported under the `decimal` feature only.
|
||||
#[cfg(feature = "decimal")]
|
||||
Decimal(Box<Decimal>, Tag, AccessMode),
|
||||
@ -222,7 +222,7 @@ pub enum Union {
|
||||
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.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// This type provides transparent interoperability between normal [`Dynamic`] and shared
|
||||
@ -1762,7 +1762,7 @@ impl Dynamic {
|
||||
_ => 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.
|
||||
///
|
||||
/// Exported under the `decimal` feature only.
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! 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::dynamic::{map_std_type_name, AccessMode, Union, Variant};
|
||||
use crate::fn_hash::get_hasher;
|
||||
@ -40,7 +40,7 @@ use crate::ast::FnCallHashes;
|
||||
|
||||
pub type Precedence = NonZeroU8;
|
||||
|
||||
/// _(INTERNALS)_ A stack of imported [modules][Module].
|
||||
/// _(internals)_ A stack of imported [modules][Module].
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// # 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.
|
||||
///
|
||||
/// # Volatile Data Structure
|
||||
@ -634,7 +634,7 @@ pub struct FnResolutionCacheEntry {
|
||||
pub source: Option<Identifier>,
|
||||
}
|
||||
|
||||
/// _(INTERNALS)_ A function resolution cache.
|
||||
/// _(internals)_ A function resolution cache.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// # Volatile Data Structure
|
||||
@ -642,7 +642,7 @@ pub struct FnResolutionCacheEntry {
|
||||
/// This type is volatile and may change.
|
||||
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.
|
||||
///
|
||||
/// # Volatile Data Structure
|
||||
@ -653,19 +653,20 @@ pub struct EvalState {
|
||||
/// Source of the current context.
|
||||
pub source: Option<Identifier>,
|
||||
/// 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.
|
||||
pub always_search_scope: bool,
|
||||
/// Level of the current scope. The global (root) level is zero, a new block (or function call)
|
||||
/// is one level higher, and so on.
|
||||
pub scope_level: usize,
|
||||
/// Number of operations performed.
|
||||
pub operations: u64,
|
||||
pub num_operations: u64,
|
||||
/// Number of modules loaded.
|
||||
pub modules: usize,
|
||||
pub num_modules: usize,
|
||||
/// Embedded module resolver.
|
||||
#[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.
|
||||
fn_resolution_caches: Vec<FnResolutionCache>,
|
||||
}
|
||||
@ -679,10 +680,10 @@ impl EvalState {
|
||||
source: None,
|
||||
always_search_scope: false,
|
||||
scope_level: 0,
|
||||
operations: 0,
|
||||
modules: 0,
|
||||
num_operations: 0,
|
||||
num_modules: 0,
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
resolver: None,
|
||||
embedded_module_resolver: None,
|
||||
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.
|
||||
///
|
||||
/// # 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)> {
|
||||
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.
|
||||
#[cfg(feature = "internals")]
|
||||
#[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> {
|
||||
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.
|
||||
#[cfg(feature = "internals")]
|
||||
#[inline(always)]
|
||||
@ -2850,12 +2851,11 @@ impl Engine {
|
||||
}
|
||||
|
||||
// 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 entry_type = match stmt {
|
||||
Stmt::Let(_, _, _, _) => AccessMode::ReadWrite,
|
||||
Stmt::Const(_, _, _, _) => AccessMode::ReadOnly,
|
||||
_ => unreachable!("should be Stmt::Let or Stmt::Const, but gets {:?}", stmt),
|
||||
let entry_type = match var_type {
|
||||
VarDeclaration::Let => AccessMode::ReadWrite,
|
||||
VarDeclaration::Const => AccessMode::ReadOnly,
|
||||
};
|
||||
|
||||
let value = self
|
||||
@ -2914,7 +2914,7 @@ impl Engine {
|
||||
Stmt::Import(expr, export, _pos) => {
|
||||
// Guard against too many modules
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
if state.modules >= self.max_modules() {
|
||||
if state.num_modules >= self.max_modules() {
|
||||
return EvalAltResult::ErrorTooManyModules(*_pos).into();
|
||||
}
|
||||
|
||||
@ -2928,7 +2928,7 @@ impl Engine {
|
||||
let path_pos = expr.position();
|
||||
|
||||
let module = state
|
||||
.resolver
|
||||
.embedded_module_resolver
|
||||
.as_ref()
|
||||
.and_then(|r| match r.resolve(self, source, &path, path_pos) {
|
||||
Err(err)
|
||||
@ -2958,7 +2958,7 @@ impl Engine {
|
||||
}
|
||||
}
|
||||
|
||||
state.modules += 1;
|
||||
state.num_modules += 1;
|
||||
|
||||
Ok(Dynamic::UNIT)
|
||||
} else {
|
||||
@ -3130,16 +3130,16 @@ impl Engine {
|
||||
state: &mut EvalState,
|
||||
pos: Position,
|
||||
) -> Result<(), Box<EvalAltResult>> {
|
||||
state.operations += 1;
|
||||
state.num_operations += 1;
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
// Report progress - only in steps
|
||||
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
|
||||
return EvalAltResult::ErrorTerminated(token, pos).into();
|
||||
}
|
||||
|
@ -1729,7 +1729,7 @@ impl Engine {
|
||||
state.source = ast.source_raw().cloned();
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
{
|
||||
state.resolver = ast.resolver();
|
||||
state.embedded_module_resolver = ast.resolver();
|
||||
}
|
||||
|
||||
let statements = ast.statements();
|
||||
@ -1811,7 +1811,7 @@ impl Engine {
|
||||
state.source = ast.source_raw().cloned();
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
{
|
||||
state.resolver = ast.resolver();
|
||||
state.embedded_module_resolver = ast.resolver();
|
||||
}
|
||||
|
||||
let statements = ast.statements();
|
||||
@ -2052,7 +2052,7 @@ impl Engine {
|
||||
let stmt = std::mem::take(ast.statements_mut());
|
||||
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.
|
||||
///
|
||||
/// Functions from the following sources are included, in order:
|
||||
|
@ -9,7 +9,7 @@ use std::fmt;
|
||||
#[cfg(feature = "no_std")]
|
||||
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.
|
||||
///
|
||||
/// # Volatile Data Structure
|
||||
|
@ -840,12 +840,12 @@ impl Engine {
|
||||
// Evaluate the AST
|
||||
let mut new_state = EvalState::new();
|
||||
new_state.source = state.source.clone();
|
||||
new_state.operations = state.operations;
|
||||
new_state.num_operations = state.num_operations;
|
||||
|
||||
let result =
|
||||
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
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ impl<'a> NativeCallContext<'a> {
|
||||
lib,
|
||||
}
|
||||
}
|
||||
/// _(INTERNALS)_ Create a new [`NativeCallContext`].
|
||||
/// _(internals)_ Create a new [`NativeCallContext`].
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// Not available under `no_module`.
|
||||
@ -156,7 +156,7 @@ impl<'a> NativeCallContext<'a> {
|
||||
) -> impl Iterator<Item = (&crate::Identifier, &Shared<Module>)> {
|
||||
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.
|
||||
///
|
||||
/// Not available under `no_module`.
|
||||
@ -172,7 +172,7 @@ impl<'a> NativeCallContext<'a> {
|
||||
pub fn iter_namespaces(&self) -> impl Iterator<Item = &Module> {
|
||||
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.
|
||||
#[cfg(feature = "internals")]
|
||||
#[inline(always)]
|
||||
|
@ -71,17 +71,17 @@ pub trait RegisterNativeFunction<Args, Result> {
|
||||
/// Get the type ID's of this function's parameters.
|
||||
#[must_use]
|
||||
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.
|
||||
#[cfg(feature = "metadata")]
|
||||
#[must_use]
|
||||
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.
|
||||
#[cfg(feature = "metadata")]
|
||||
#[must_use]
|
||||
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.
|
||||
#[cfg(feature = "metadata")]
|
||||
#[must_use]
|
||||
|
@ -228,7 +228,7 @@ pub use token::{InputStream, Token, TokenizeState, TokenizerControl, TokenizerCo
|
||||
#[deprecated = "this type is volatile and may change"]
|
||||
pub use ast::{
|
||||
ASTNode, BinaryExpr, CustomExpr, Expr, FloatWrapper, FnCallExpr, FnCallHashes, Ident,
|
||||
OpAssignment, ReturnType, ScriptFnDef, Stmt, StmtBlock,
|
||||
OpAssignment, ReturnType, ScriptFnDef, Stmt, StmtBlock, VarDeclaration,
|
||||
};
|
||||
|
||||
#[cfg(feature = "internals")]
|
||||
@ -278,7 +278,7 @@ pub use module::NamespaceRef;
|
||||
#[cfg(not(feature = "internals"))]
|
||||
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.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
|
@ -81,18 +81,18 @@ impl FuncInfo {
|
||||
sig.push_str(") -> ");
|
||||
sig.push_str(&return_type);
|
||||
} else {
|
||||
sig.push_str(")");
|
||||
sig.push(')');
|
||||
}
|
||||
} else {
|
||||
for x in 0..self.params {
|
||||
sig.push_str("_");
|
||||
sig.push('_');
|
||||
if x < self.params - 1 {
|
||||
sig.push_str(", ");
|
||||
}
|
||||
}
|
||||
|
||||
if self.func.is_script() {
|
||||
sig.push_str(")");
|
||||
sig.push(')');
|
||||
} else {
|
||||
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.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
@ -366,7 +366,6 @@ impl Module {
|
||||
/// Exported under the `metadata` feature only.
|
||||
#[cfg(feature = "metadata")]
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn gen_fn_signatures(&self) -> impl Iterator<Item = String> + '_ {
|
||||
self.functions
|
||||
.values()
|
||||
@ -630,9 +629,9 @@ impl Module {
|
||||
.map(|&name| self.identifiers.get(name))
|
||||
.collect();
|
||||
|
||||
self.functions
|
||||
.get_mut(&hash_fn)
|
||||
.map(|f| f.param_names = param_names);
|
||||
if let Some(f) = self.functions.get_mut(&hash_fn) {
|
||||
f.param_names = param_names;
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
@ -1364,7 +1363,7 @@ impl Module {
|
||||
.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.
|
||||
///
|
||||
/// Function metadata includes:
|
||||
@ -1372,7 +1371,7 @@ impl Module {
|
||||
/// 2) Access mode ([`FnAccess::Public`] or [`FnAccess::Private`]).
|
||||
/// 3) Function name (as string slice).
|
||||
/// 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(feature = "internals")]
|
||||
#[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.
|
||||
///
|
||||
/// 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")]
|
||||
use std::prelude::v1::*;
|
||||
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>)> {
|
||||
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.
|
||||
#[inline(always)]
|
||||
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 {
|
||||
#[inline(always)]
|
||||
fn resolve(
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! Module implementing the [`AST`] optimizer.
|
||||
|
||||
use crate::ast::{Expr, OpAssignment, Stmt};
|
||||
use crate::ast::{Expr, OpAssignment, Stmt, VarDeclaration};
|
||||
use crate::dynamic::AccessMode;
|
||||
use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF};
|
||||
use crate::fn_builtin::get_builtin_binary_op_fn;
|
||||
@ -202,7 +202,7 @@ fn optimize_stmt_block(
|
||||
statements.iter_mut().for_each(|stmt| {
|
||||
match stmt {
|
||||
// Add constant literals into the state
|
||||
Stmt::Const(value_expr, x, _, _) => {
|
||||
Stmt::Var(value_expr, x, VarDeclaration::Const, _, _) => {
|
||||
optimize_expr(value_expr, state, false);
|
||||
|
||||
if value_expr.is_constant() {
|
||||
@ -214,7 +214,7 @@ fn optimize_stmt_block(
|
||||
}
|
||||
}
|
||||
// Add variables into the state
|
||||
Stmt::Let(value_expr, x, _, _) => {
|
||||
Stmt::Var(value_expr, x, VarDeclaration::Let, _, _) => {
|
||||
optimize_expr(value_expr, state, false);
|
||||
state.push_var(&x.name, AccessMode::ReadWrite, None);
|
||||
}
|
||||
@ -232,11 +232,7 @@ fn optimize_stmt_block(
|
||||
.find_map(|(i, stmt)| match stmt {
|
||||
stmt if !is_pure(stmt) => Some(i),
|
||||
|
||||
Stmt::Let(e, _, _, _) | Stmt::Const(e, _, _, _) | Stmt::Expr(e)
|
||||
if !e.is_constant() =>
|
||||
{
|
||||
Some(i)
|
||||
}
|
||||
Stmt::Var(e, _, _, _, _) | Stmt::Expr(e) if !e.is_constant() => Some(i),
|
||||
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
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();
|
||||
}
|
||||
// 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;
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
Stmt::Import(expr, _, _) => optimize_expr(expr, state, false),
|
||||
|
24
src/parse.rs
24
src/parse.rs
@ -2,7 +2,7 @@
|
||||
|
||||
use crate::ast::{
|
||||
BinaryExpr, CustomExpr, Expr, FnCallExpr, FnCallHashes, Ident, OpAssignment, ReturnType,
|
||||
ScriptFnDef, Stmt, StmtBlock,
|
||||
ScriptFnDef, Stmt, StmtBlock, VarDeclaration,
|
||||
};
|
||||
use crate::custom_syntax::{
|
||||
CustomSyntax, CUSTOM_SYNTAX_MARKER_BLOCK, CUSTOM_SYNTAX_MARKER_BOOL, CUSTOM_SYNTAX_MARKER_EXPR,
|
||||
@ -2115,15 +2115,13 @@ fn parse_expr(
|
||||
|
||||
match token {
|
||||
Token::Custom(key) | Token::Reserved(key) | Token::Identifier(key) => {
|
||||
match state.engine.custom_syntax.get_key_value(key.as_str()) {
|
||||
Some((key, syntax)) => {
|
||||
if let Some((key, syntax)) = state.engine.custom_syntax.get_key_value(key.as_str())
|
||||
{
|
||||
input.next().expect(NEVER_ENDS);
|
||||
return parse_custom_syntax(
|
||||
input, state, lib, settings, key, syntax, token_pos,
|
||||
);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
@ -2385,9 +2383,21 @@ fn parse_let(
|
||||
|
||||
match var_type {
|
||||
// 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 }
|
||||
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 }
|
||||
}
|
||||
/// Shortcut for a type conversion error.
|
||||
#[must_use]
|
||||
fn type_error<T>(&self) -> Result<T, Box<EvalAltResult>> {
|
||||
self.type_error_str(type_name::<T>())
|
||||
}
|
||||
/// Shortcut for a type conversion error.
|
||||
#[must_use]
|
||||
fn type_error_str<T>(&self, error: &str) -> Result<T, Box<EvalAltResult>> {
|
||||
EvalAltResult::ErrorMismatchOutputType(
|
||||
error.into(),
|
||||
@ -47,7 +45,6 @@ impl<'de> DynamicDeserializer<'de> {
|
||||
)
|
||||
.into()
|
||||
}
|
||||
#[must_use]
|
||||
fn deserialize_int<V: Visitor<'de>>(
|
||||
&mut self,
|
||||
v: crate::INT,
|
||||
@ -111,7 +108,6 @@ impl<'de> DynamicDeserializer<'de> {
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn from_dynamic<'de, T: Deserialize<'de>>(
|
||||
value: &'de Dynamic,
|
||||
) -> 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> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
return Ok(v.into());
|
||||
{
|
||||
Ok(v.into())
|
||||
}
|
||||
#[cfg(feature = "only_i32")]
|
||||
if v > i32::MAX as i64 {
|
||||
return Ok(Dynamic::from(v));
|
||||
Ok(Dynamic::from(v))
|
||||
} 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> {
|
||||
@ -56,26 +58,28 @@ impl<'d> Visitor<'d> for DynamicVisitor {
|
||||
}
|
||||
fn visit_u32<E: Error>(self, v: u32) -> Result<Self::Value, E> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
return Ok(INT::from(v).into());
|
||||
{
|
||||
Ok(INT::from(v).into())
|
||||
}
|
||||
#[cfg(feature = "only_i32")]
|
||||
if v > i32::MAX as u32 {
|
||||
return Ok(Dynamic::from(v));
|
||||
Ok(Dynamic::from(v))
|
||||
} 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> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
if v > i64::MAX as u64 {
|
||||
return Ok(Dynamic::from(v));
|
||||
Ok(Dynamic::from(v))
|
||||
} else {
|
||||
return self.visit_i64(v as i64);
|
||||
self.visit_i64(v as i64)
|
||||
}
|
||||
#[cfg(feature = "only_i32")]
|
||||
if v > i32::MAX as u64 {
|
||||
return Ok(Dynamic::from(v));
|
||||
Ok(Dynamic::from(v))
|
||||
} 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")]
|
||||
struct FnParam {
|
||||
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)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct FnMetadata {
|
||||
@ -128,7 +137,7 @@ impl From<&crate::module::FuncInfo> for FnMetadata {
|
||||
let name = seg
|
||||
.next()
|
||||
.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());
|
||||
FnParam { name, typ }
|
||||
})
|
||||
@ -209,7 +218,7 @@ impl From<&crate::Module> for ModuleMetadata {
|
||||
|
||||
#[cfg(feature = "metadata")]
|
||||
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.
|
||||
/// Exported under the `metadata` feature only.
|
||||
///
|
||||
@ -218,7 +227,6 @@ impl Engine {
|
||||
/// 2) Functions registered into the global namespace
|
||||
/// 3) Functions in static modules
|
||||
/// 4) Functions in global modules (optional)
|
||||
#[must_use]
|
||||
pub fn gen_fn_metadata_with_ast_to_json(
|
||||
&self,
|
||||
ast: &AST,
|
||||
@ -258,7 +266,6 @@ impl Engine {
|
||||
/// 1) Functions registered into the global namespace
|
||||
/// 2) Functions in static modules
|
||||
/// 3) Functions in global modules (optional)
|
||||
#[must_use]
|
||||
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)
|
||||
}
|
||||
|
@ -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.
|
||||
|
||||
mod de;
|
||||
|
@ -82,7 +82,6 @@ impl DynamicSerializer {
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn to_dynamic<T: Serialize>(value: T) -> RhaiResult {
|
||||
let mut s = DynamicSerializer::new(Default::default());
|
||||
value.serialize(&mut s)
|
||||
@ -138,27 +137,29 @@ impl Serializer for &mut DynamicSerializer {
|
||||
|
||||
fn serialize_i64(self, v: i64) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
return Ok(v.into());
|
||||
{
|
||||
Ok(v.into())
|
||||
}
|
||||
#[cfg(feature = "only_i32")]
|
||||
if v > i32::MAX as i64 {
|
||||
return Ok(Dynamic::from(v));
|
||||
Ok(Dynamic::from(v))
|
||||
} 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>> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
if v > i64::MAX as i128 {
|
||||
return Ok(Dynamic::from(v));
|
||||
Ok(Dynamic::from(v))
|
||||
} else {
|
||||
return self.serialize_i64(v as i64);
|
||||
self.serialize_i64(v as i64)
|
||||
}
|
||||
#[cfg(feature = "only_i32")]
|
||||
if v > i32::MAX as i128 {
|
||||
return Ok(Dynamic::from(v));
|
||||
Ok(Dynamic::from(v))
|
||||
} 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>> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
return self.serialize_i64(i64::from(v));
|
||||
{
|
||||
self.serialize_i64(i64::from(v))
|
||||
}
|
||||
#[cfg(feature = "only_i32")]
|
||||
if v > i32::MAX as u32 {
|
||||
return Ok(Dynamic::from(v));
|
||||
Ok(Dynamic::from(v))
|
||||
} 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>> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
if v > i64::MAX as u64 {
|
||||
return Ok(Dynamic::from(v));
|
||||
Ok(Dynamic::from(v))
|
||||
} else {
|
||||
return self.serialize_i64(v as i64);
|
||||
self.serialize_i64(v as i64)
|
||||
}
|
||||
#[cfg(feature = "only_i32")]
|
||||
if v > i32::MAX as u64 {
|
||||
return Ok(Dynamic::from(v));
|
||||
Ok(Dynamic::from(v))
|
||||
} 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>> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
if v > i64::MAX as u128 {
|
||||
return Ok(Dynamic::from(v));
|
||||
Ok(Dynamic::from(v))
|
||||
} else {
|
||||
return self.serialize_i64(v as i64);
|
||||
self.serialize_i64(v as i64)
|
||||
}
|
||||
#[cfg(feature = "only_i32")]
|
||||
if v > i32::MAX as u128 {
|
||||
return Ok(Dynamic::from(v));
|
||||
Ok(Dynamic::from(v))
|
||||
} else {
|
||||
return self.serialize_i32(v as i32);
|
||||
self.serialize_i32(v as i32)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,6 @@ impl<'a> StringSliceDeserializer<'a> {
|
||||
Self { value }
|
||||
}
|
||||
/// Shortcut for a type conversion error.
|
||||
#[must_use]
|
||||
fn type_error<T>(&self) -> Result<T, Box<EvalAltResult>> {
|
||||
EvalAltResult::ErrorMismatchOutputType(
|
||||
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"))]
|
||||
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)]
|
||||
pub struct TokenizerControlBlock {
|
||||
/// Is the current tokenizer position within an interpolated text string?
|
||||
@ -35,7 +35,7 @@ pub struct TokenizerControlBlock {
|
||||
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>>;
|
||||
|
||||
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.
|
||||
///
|
||||
/// # 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.
|
||||
///
|
||||
/// # Volatile Data Structure
|
||||
@ -1000,7 +1000,7 @@ pub struct TokenizeState {
|
||||
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.
|
||||
///
|
||||
/// # Volatile Data Structure
|
||||
@ -1018,7 +1018,7 @@ pub trait InputStream {
|
||||
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.
|
||||
///
|
||||
/// Returns the parsed string and a boolean indicating whether the string is
|
||||
@ -1281,22 +1281,22 @@ fn scan_block_comment(
|
||||
|
||||
match c {
|
||||
'/' => {
|
||||
stream.peek_next().filter(|&c2| c2 == '*').map(|c2| {
|
||||
if let Some(c2) = stream.peek_next().filter(|&c2| c2 == '*') {
|
||||
eat_next(stream, pos);
|
||||
if let Some(comment) = comment.as_mut() {
|
||||
comment.push(c2);
|
||||
}
|
||||
level += 1;
|
||||
});
|
||||
}
|
||||
}
|
||||
'*' => {
|
||||
stream.peek_next().filter(|&c2| c2 == '/').map(|c2| {
|
||||
if let Some(c2) = stream.peek_next().filter(|&c2| c2 == '/') {
|
||||
eat_next(stream, pos);
|
||||
if let Some(comment) = comment.as_mut() {
|
||||
comment.push(c2);
|
||||
}
|
||||
level -= 1;
|
||||
});
|
||||
}
|
||||
}
|
||||
'\n' => pos.new_line(),
|
||||
_ => (),
|
||||
@ -1310,7 +1310,7 @@ fn scan_block_comment(
|
||||
level
|
||||
}
|
||||
|
||||
/// _(INTERNALS)_ Get the next token from the `stream`.
|
||||
/// _(internals)_ Get the next token from the `stream`.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// # Volatile API
|
||||
@ -2234,7 +2234,7 @@ impl<'a> Iterator for TokenIterator<'a> {
|
||||
impl FusedIterator for TokenIterator<'_> {}
|
||||
|
||||
impl Engine {
|
||||
/// _(INTERNALS)_ Tokenize an input text stream.
|
||||
/// _(internals)_ Tokenize an input text stream.
|
||||
/// Exported under the `internals` feature only.
|
||||
#[cfg(feature = "internals")]
|
||||
#[inline(always)]
|
||||
@ -2245,7 +2245,7 @@ impl Engine {
|
||||
) -> (TokenIterator<'a>, TokenizerControl) {
|
||||
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.
|
||||
#[cfg(feature = "internals")]
|
||||
#[inline(always)]
|
||||
|
@ -86,7 +86,7 @@ fn test_optimizer_parse() -> Result<(), Box<EvalAltResult>> {
|
||||
|
||||
assert_eq!(
|
||||
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 }")?;
|
||||
|
Loading…
Reference in New Issue
Block a user