Merge pull request #519 from schungx/master
Consolidate most unsafe casts.
This commit is contained in:
commit
ea9b6b0e22
@ -14,6 +14,7 @@ Bug fixes
|
|||||||
* Off-by-one error in character positions after a comment line is now fixed.
|
* Off-by-one error in character positions after a comment line is now fixed.
|
||||||
* Globally-defined constants are now encapsulated correctly inside a loaded module and no longer spill across call boundaries.
|
* Globally-defined constants are now encapsulated correctly inside a loaded module and no longer spill across call boundaries.
|
||||||
* Type names display is fixed.
|
* Type names display is fixed.
|
||||||
|
* Exceptions thrown inside function calls now unwrap correctly when `catch`-ed.
|
||||||
|
|
||||||
Script-breaking changes
|
Script-breaking changes
|
||||||
-----------------------
|
-----------------------
|
||||||
@ -40,6 +41,7 @@ Enhancements
|
|||||||
* `AST` position display is improved:
|
* `AST` position display is improved:
|
||||||
* `Expr::start_position` is added to give the beginning of the expression (not the operator's position).
|
* `Expr::start_position` is added to give the beginning of the expression (not the operator's position).
|
||||||
* `StmtBlock` and `Stmt::Block` now keep the position of the closing `}` as well.
|
* `StmtBlock` and `Stmt::Block` now keep the position of the closing `}` as well.
|
||||||
|
* `EvalAltResult::unwrap_inner` is added to access the base error inside multiple layers of wrappings (e.g. `EvalAltResult::ErrorInFunction`).
|
||||||
|
|
||||||
REPL tool changes
|
REPL tool changes
|
||||||
-----------------
|
-----------------
|
||||||
@ -53,15 +55,16 @@ The REPL bin tool, `rhai-rpl`, has been enhanced.
|
|||||||
|
|
||||||
### Line editor
|
### Line editor
|
||||||
|
|
||||||
* `rhai-repl` now uses [`rustyline`](https://crates.io/crates/rustyline) as a line editor with history.
|
* `rhai-repl` now uses a modified version of [`rustyline`](https://crates.io/crates/rustyline) as a line editor with history.
|
||||||
* Shift-Enter can now be used to enter multiple lines without having to attach the `\` continuation character the end of each line.
|
* Ctrl-Enter can now be used to enter multiple lines without having to attach the `\` continuation character the end of each line.
|
||||||
|
* Bracketed paste is supported, even on Windows (version 10 or above), so pasting code directly into `rhai-repl` is made much more convenient.
|
||||||
|
|
||||||
### New commands
|
### New commands
|
||||||
|
|
||||||
* `strict` to turn on/off _Strict Variables Mode_.
|
* `strict` to turn on/off _Strict Variables Mode_.
|
||||||
* `optimize` to turn on/off script optimization.
|
* `optimize` to turn on/off script optimization.
|
||||||
* `history` to print lines history.
|
* `history` to print lines history.
|
||||||
* `!!`, `!`_num_ and `!`_text_ to recall a history line.
|
* `!!`, `!`_num_, `!`_text_ and `!?`_text_ to recall a history line.
|
||||||
* `keys` to print all key bindings.
|
* `keys` to print all key bindings.
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,7 +29,9 @@ serde = { version = "1.0", default-features = false, features = ["derive", "allo
|
|||||||
serde_json = { version = "1.0", default-features = false, features = ["alloc"], optional = true }
|
serde_json = { version = "1.0", default-features = false, features = ["alloc"], optional = true }
|
||||||
unicode-xid = { version = "0.2", default-features = false, optional = true }
|
unicode-xid = { version = "0.2", default-features = false, optional = true }
|
||||||
rust_decimal = { version = "1.16", default-features = false, features = ["maths"], optional = true }
|
rust_decimal = { version = "1.16", default-features = false, features = ["maths"], optional = true }
|
||||||
rustyline = { version = "9", optional = true }
|
# notice that a custom modified version of `rustyline` is used which supports bracketed paste on Windows
|
||||||
|
# this can be moved to the official version when bracketed paste is added
|
||||||
|
rustyline = { version = "9", optional = true, git = "https://github.com/schungx/rustyline", branch = "bracketed_paste" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_bytes = "0.11"
|
serde_bytes = "0.11"
|
||||||
@ -50,9 +52,9 @@ no_object = [] # no custom objects
|
|||||||
no_function = ["no_closure"] # no script-defined functions (meaning no closures)
|
no_function = ["no_closure"] # no script-defined functions (meaning no closures)
|
||||||
no_closure = [] # no automatic sharing and capture of anonymous functions to external variables
|
no_closure = [] # no automatic sharing and capture of anonymous functions to external variables
|
||||||
no_module = [] # no modules
|
no_module = [] # no modules
|
||||||
internals = [] # expose internal data structures
|
|
||||||
unicode-xid-ident = ["unicode-xid"] # allow Unicode Standard Annex #31 for identifiers.
|
unicode-xid-ident = ["unicode-xid"] # allow Unicode Standard Annex #31 for identifiers.
|
||||||
metadata = ["serde", "serde_json", "rhai_codegen/metadata", "smartstring/serde"] # enable exporting functions metadata
|
metadata = ["serde", "serde_json", "rhai_codegen/metadata", "smartstring/serde"] # enable exporting functions metadata
|
||||||
|
internals = [] # expose internal data structures
|
||||||
debugging = ["internals"] # enable debugging
|
debugging = ["internals"] # enable debugging
|
||||||
|
|
||||||
# compiling for no-std
|
# compiling for no-std
|
||||||
|
@ -252,7 +252,7 @@ impl ExportedParams for ExportedFnParams {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(attr, _) => {
|
(attr, ..) => {
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(
|
||||||
key.span(),
|
key.span(),
|
||||||
format!("unknown attribute '{}'", attr),
|
format!("unknown attribute '{}'", attr),
|
||||||
@ -366,7 +366,7 @@ impl Parse for ExportedFn {
|
|||||||
}) => {
|
}) => {
|
||||||
matches!(flatten_type_groups(elem.as_ref()), syn::Type::Path(ref p) if p.path == str_type_path)
|
matches!(flatten_type_groups(elem.as_ref()), syn::Type::Path(ref p) if p.path == str_type_path)
|
||||||
}
|
}
|
||||||
syn::Type::Verbatim(_) => false,
|
syn::Type::Verbatim(..) => false,
|
||||||
_ => true,
|
_ => true,
|
||||||
};
|
};
|
||||||
if !is_ok {
|
if !is_ok {
|
||||||
@ -379,15 +379,15 @@ impl Parse for ExportedFn {
|
|||||||
|
|
||||||
// Check return type.
|
// Check return type.
|
||||||
match fn_all.sig.output {
|
match fn_all.sig.output {
|
||||||
syn::ReturnType::Type(_, ref ret_type) => {
|
syn::ReturnType::Type(.., ref ret_type) => {
|
||||||
match flatten_type_groups(ret_type.as_ref()) {
|
match flatten_type_groups(ret_type.as_ref()) {
|
||||||
syn::Type::Ptr(_) => {
|
syn::Type::Ptr(..) => {
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(
|
||||||
fn_all.sig.output.span(),
|
fn_all.sig.output.span(),
|
||||||
"Rhai functions cannot return pointers",
|
"Rhai functions cannot return pointers",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
syn::Type::Reference(_) => {
|
syn::Type::Reference(..) => {
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(
|
||||||
fn_all.sig.output.span(),
|
fn_all.sig.output.span(),
|
||||||
"Rhai functions cannot return references",
|
"Rhai functions cannot return references",
|
||||||
@ -425,10 +425,10 @@ impl ExportedFn {
|
|||||||
|
|
||||||
pub fn update_scope(&mut self, parent_scope: &ExportScope) {
|
pub fn update_scope(&mut self, parent_scope: &ExportScope) {
|
||||||
let keep = match (self.params.skip, parent_scope) {
|
let keep = match (self.params.skip, parent_scope) {
|
||||||
(true, _) => false,
|
(true, ..) => false,
|
||||||
(_, ExportScope::PubOnly) => self.is_public(),
|
(.., ExportScope::PubOnly) => self.is_public(),
|
||||||
(_, ExportScope::Prefix(s)) => self.name().to_string().starts_with(s),
|
(.., ExportScope::Prefix(s)) => self.name().to_string().starts_with(s),
|
||||||
(_, ExportScope::All) => true,
|
(.., ExportScope::All) => true,
|
||||||
};
|
};
|
||||||
self.params.skip = !keep;
|
self.params.skip = !keep;
|
||||||
}
|
}
|
||||||
@ -502,7 +502,7 @@ impl ExportedFn {
|
|||||||
|
|
||||||
pub fn return_type(&self) -> Option<&syn::Type> {
|
pub fn return_type(&self) -> Option<&syn::Type> {
|
||||||
match self.signature.output {
|
match self.signature.output {
|
||||||
syn::ReturnType::Type(_, ref ret_type) => Some(flatten_type_groups(ret_type)),
|
syn::ReturnType::Type(.., ref ret_type) => Some(flatten_type_groups(ret_type)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -544,28 +544,28 @@ impl ExportedFn {
|
|||||||
|
|
||||||
match params.special {
|
match params.special {
|
||||||
// 2a. Property getters must take only the subject as an argument.
|
// 2a. Property getters must take only the subject as an argument.
|
||||||
FnSpecialAccess::Property(Property::Get(_)) if self.arg_count() != 1 => {
|
FnSpecialAccess::Property(Property::Get(..)) if self.arg_count() != 1 => {
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(
|
||||||
self.signature.inputs.span(),
|
self.signature.inputs.span(),
|
||||||
"property getter requires exactly 1 parameter",
|
"property getter requires exactly 1 parameter",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
// 2b. Property getters must return a value.
|
// 2b. Property getters must return a value.
|
||||||
FnSpecialAccess::Property(Property::Get(_)) if self.return_type().is_none() => {
|
FnSpecialAccess::Property(Property::Get(..)) if self.return_type().is_none() => {
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(
|
||||||
self.signature.span(),
|
self.signature.span(),
|
||||||
"property getter must return a value",
|
"property getter must return a value",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
// 3a. Property setters must take the subject and a new value as arguments.
|
// 3a. Property setters must take the subject and a new value as arguments.
|
||||||
FnSpecialAccess::Property(Property::Set(_)) if self.arg_count() != 2 => {
|
FnSpecialAccess::Property(Property::Set(..)) if self.arg_count() != 2 => {
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(
|
||||||
self.signature.inputs.span(),
|
self.signature.inputs.span(),
|
||||||
"property setter requires exactly 2 parameters",
|
"property setter requires exactly 2 parameters",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
// 3b. Non-raw property setters must return nothing.
|
// 3b. Non-raw property setters must return nothing.
|
||||||
FnSpecialAccess::Property(Property::Set(_))
|
FnSpecialAccess::Property(Property::Set(..))
|
||||||
if params.return_raw.is_none() && self.return_type().is_some() =>
|
if params.return_raw.is_none() && self.return_type().is_some() =>
|
||||||
{
|
{
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(
|
||||||
@ -734,7 +734,7 @@ impl ExportedFn {
|
|||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
syn::FnArg::Receiver(_) => todo!("true self parameters not implemented yet"),
|
syn::FnArg::Receiver(..) => todo!("true self parameters not implemented yet"),
|
||||||
}
|
}
|
||||||
unpack_exprs.push(syn::parse2::<syn::Expr>(quote! { #var }).unwrap());
|
unpack_exprs.push(syn::parse2::<syn::Expr>(quote! { #var }).unwrap());
|
||||||
} else {
|
} else {
|
||||||
@ -811,7 +811,7 @@ impl ExportedFn {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
syn::FnArg::Receiver(_) => panic!("internal error: how did this happen!?"),
|
syn::FnArg::Receiver(..) => panic!("internal error: how did this happen!?"),
|
||||||
}
|
}
|
||||||
if !is_ref {
|
if !is_ref {
|
||||||
unpack_exprs.push(syn::parse2::<syn::Expr>(quote! { #var }).unwrap());
|
unpack_exprs.push(syn::parse2::<syn::Expr>(quote! { #var }).unwrap());
|
||||||
|
@ -69,7 +69,7 @@ impl ExportedParams for ExportedModParams {
|
|||||||
("export_all", Some(s)) => {
|
("export_all", Some(s)) => {
|
||||||
return Err(syn::Error::new(s.span(), "extraneous value"))
|
return Err(syn::Error::new(s.span(), "extraneous value"))
|
||||||
}
|
}
|
||||||
(attr, _) => {
|
(attr, ..) => {
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(
|
||||||
key.span(),
|
key.span(),
|
||||||
format!("unknown attribute '{}'", attr),
|
format!("unknown attribute '{}'", attr),
|
||||||
@ -109,7 +109,7 @@ impl Parse for Module {
|
|||||||
let mut consts = Vec::new();
|
let mut consts = Vec::new();
|
||||||
let mut sub_modules = Vec::new();
|
let mut sub_modules = Vec::new();
|
||||||
|
|
||||||
if let Some((_, ref mut content)) = mod_all.content {
|
if let Some((.., ref mut content)) = mod_all.content {
|
||||||
// Gather and parse functions.
|
// Gather and parse functions.
|
||||||
fns = content
|
fns = content
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
@ -144,12 +144,14 @@ impl Parse for Module {
|
|||||||
attrs,
|
attrs,
|
||||||
ty,
|
ty,
|
||||||
..
|
..
|
||||||
}) if matches!(vis, syn::Visibility::Public(_)) => consts.push(ExportedConst {
|
}) if matches!(vis, syn::Visibility::Public(..)) => {
|
||||||
name: ident.to_string(),
|
consts.push(ExportedConst {
|
||||||
typ: ty.clone(),
|
name: ident.to_string(),
|
||||||
expr: expr.as_ref().clone(),
|
typ: ty.clone(),
|
||||||
cfg_attrs: crate::attrs::collect_cfg_attr(&attrs),
|
expr: expr.as_ref().clone(),
|
||||||
}),
|
cfg_attrs: crate::attrs::collect_cfg_attr(&attrs),
|
||||||
|
})
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -161,7 +163,7 @@ impl Parse for Module {
|
|||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < content.len() {
|
while i < content.len() {
|
||||||
match content[i] {
|
match content[i] {
|
||||||
syn::Item::Mod(_) => {
|
syn::Item::Mod(..) => {
|
||||||
let mut item_mod = match content.remove(i) {
|
let mut item_mod = match content.remove(i) {
|
||||||
syn::Item::Mod(m) => m,
|
syn::Item::Mod(m) => m,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
@ -211,10 +213,10 @@ impl Module {
|
|||||||
|
|
||||||
pub fn update_scope(&mut self, parent_scope: &ExportScope) {
|
pub fn update_scope(&mut self, parent_scope: &ExportScope) {
|
||||||
let keep = match (self.params.skip, parent_scope) {
|
let keep = match (self.params.skip, parent_scope) {
|
||||||
(true, _) => false,
|
(true, ..) => false,
|
||||||
(_, ExportScope::PubOnly) => matches!(self.mod_all.vis, syn::Visibility::Public(_)),
|
(.., ExportScope::PubOnly) => matches!(self.mod_all.vis, syn::Visibility::Public(..)),
|
||||||
(_, ExportScope::Prefix(s)) => self.mod_all.ident.to_string().starts_with(s),
|
(.., ExportScope::Prefix(s)) => self.mod_all.ident.to_string().starts_with(s),
|
||||||
(_, ExportScope::All) => true,
|
(.., ExportScope::All) => true,
|
||||||
};
|
};
|
||||||
self.params.skip = !keep;
|
self.params.skip = !keep;
|
||||||
}
|
}
|
||||||
@ -245,7 +247,7 @@ impl Module {
|
|||||||
} = self;
|
} = self;
|
||||||
let mod_vis = mod_all.vis;
|
let mod_vis = mod_all.vis;
|
||||||
let mod_name = mod_all.ident.clone();
|
let mod_name = mod_all.ident.clone();
|
||||||
let (_, orig_content) = mod_all.content.take().unwrap();
|
let (.., orig_content) = mod_all.content.take().unwrap();
|
||||||
let mod_attrs = mem::take(&mut mod_all.attrs);
|
let mod_attrs = mem::take(&mut mod_all.attrs);
|
||||||
|
|
||||||
if !params.skip {
|
if !params.skip {
|
||||||
@ -312,7 +314,7 @@ impl Module {
|
|||||||
pub fn content(&self) -> Option<&[syn::Item]> {
|
pub fn content(&self) -> Option<&[syn::Item]> {
|
||||||
match self.mod_all {
|
match self.mod_all {
|
||||||
syn::ItemMod {
|
syn::ItemMod {
|
||||||
content: Some((_, ref vec)),
|
content: Some((.., ref vec)),
|
||||||
..
|
..
|
||||||
} => Some(vec),
|
} => Some(vec),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -99,7 +99,7 @@ pub fn generate_body(
|
|||||||
let fn_input_types: Vec<_> = function
|
let fn_input_types: Vec<_> = function
|
||||||
.arg_list()
|
.arg_list()
|
||||||
.map(|fn_arg| match fn_arg {
|
.map(|fn_arg| match fn_arg {
|
||||||
syn::FnArg::Receiver(_) => panic!("internal error: receiver fn outside impl!?"),
|
syn::FnArg::Receiver(..) => panic!("internal error: receiver fn outside impl!?"),
|
||||||
syn::FnArg::Typed(syn::PatType { ref ty, .. }) => {
|
syn::FnArg::Typed(syn::PatType { ref ty, .. }) => {
|
||||||
let arg_type = match flatten_type_groups(ty.as_ref()) {
|
let arg_type = match flatten_type_groups(ty.as_ref()) {
|
||||||
syn::Type::Reference(syn::TypeReference {
|
syn::Type::Reference(syn::TypeReference {
|
||||||
@ -150,7 +150,7 @@ pub fn generate_body(
|
|||||||
|
|
||||||
match function.params().special {
|
match function.params().special {
|
||||||
FnSpecialAccess::None => (),
|
FnSpecialAccess::None => (),
|
||||||
FnSpecialAccess::Index(_) | FnSpecialAccess::Property(_) => {
|
FnSpecialAccess::Index(..) | FnSpecialAccess::Property(..) => {
|
||||||
let reg_name = fn_literal.value();
|
let reg_name = fn_literal.value();
|
||||||
if reg_name.starts_with(FN_GET)
|
if reg_name.starts_with(FN_GET)
|
||||||
|| reg_name.starts_with(FN_SET)
|
|| reg_name.starts_with(FN_SET)
|
||||||
@ -240,7 +240,7 @@ pub fn generate_body(
|
|||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let (_, generate_call_content) = generate_fn_call.content.take().unwrap();
|
let (.., generate_call_content) = generate_fn_call.content.take().unwrap();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#(#generate_call_content)*
|
#(#generate_call_content)*
|
||||||
@ -254,7 +254,7 @@ pub fn check_rename_collisions(fns: &[ExportedFn]) -> Result<(), syn::Error> {
|
|||||||
.arg_list()
|
.arg_list()
|
||||||
.fold(name.to_string(), |mut arg_str, fn_arg| {
|
.fold(name.to_string(), |mut arg_str, fn_arg| {
|
||||||
let type_string: String = match fn_arg {
|
let type_string: String = match fn_arg {
|
||||||
syn::FnArg::Receiver(_) => unimplemented!("receiver rhai_fns not implemented"),
|
syn::FnArg::Receiver(..) => unimplemented!("receiver rhai_fns not implemented"),
|
||||||
syn::FnArg::Typed(syn::PatType { ref ty, .. }) => print_type(ty),
|
syn::FnArg::Typed(syn::PatType { ref ty, .. }) => print_type(ty),
|
||||||
};
|
};
|
||||||
arg_str.push('.');
|
arg_str.push('.');
|
||||||
@ -275,7 +275,7 @@ pub fn check_rename_collisions(fns: &[ExportedFn]) -> Result<(), syn::Error> {
|
|||||||
.map(|n| (n.clone(), n.clone()))
|
.map(|n| (n.clone(), n.clone()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if let Some((s, n, _)) = item_fn.params().special.get_fn_name() {
|
if let Some((s, n, ..)) = item_fn.params().special.get_fn_name() {
|
||||||
names.push((s, n));
|
names.push((s, n));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ Root Sources
|
|||||||
| `tokenizer.rs` | Script tokenizer/lexer |
|
| `tokenizer.rs` | Script tokenizer/lexer |
|
||||||
| `parser.rs` | Script parser |
|
| `parser.rs` | Script parser |
|
||||||
| `optimizer.rs` | Script optimizer |
|
| `optimizer.rs` | Script optimizer |
|
||||||
| `unsafe.rs` | `unsafe` functions |
|
| `reify.rs` | Utilities for making generic types concrete |
|
||||||
| `tests.rs` | Unit tests (not integration tests, which are in the `rhai/tests` sub-directory) |
|
| `tests.rs` | Unit tests (not integration tests, which are in the `rhai/tests` sub-directory) |
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Module that defines the public compilation API of [`Engine`].
|
//! Module that defines the public compilation API of [`Engine`].
|
||||||
|
|
||||||
use crate::parser::{ParseResult, ParseState};
|
use crate::parser::{ParseResult, ParseState};
|
||||||
use crate::{Engine, Scope, AST};
|
use crate::{Engine, OptimizationLevel, Scope, AST};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
@ -99,7 +99,7 @@ impl Engine {
|
|||||||
) {
|
) {
|
||||||
ast.walk(&mut |path| match path.last().unwrap() {
|
ast.walk(&mut |path| match path.last().unwrap() {
|
||||||
// Collect all `import` statements with a string constant path
|
// Collect all `import` statements with a string constant path
|
||||||
ASTNode::Stmt(Stmt::Import(Expr::StringConstant(s, _), _, _))
|
ASTNode::Stmt(Stmt::Import(Expr::StringConstant(s, ..), ..))
|
||||||
if !resolver.contains_path(s) && !imports.contains(s.as_str()) =>
|
if !resolver.contains_path(s) && !imports.contains(s.as_str()) =>
|
||||||
{
|
{
|
||||||
imports.insert(s.clone().into());
|
imports.insert(s.clone().into());
|
||||||
@ -196,12 +196,7 @@ impl Engine {
|
|||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
scripts: impl AsRef<[S]>,
|
scripts: impl AsRef<[S]>,
|
||||||
) -> ParseResult<AST> {
|
) -> ParseResult<AST> {
|
||||||
self.compile_with_scope_and_optimization_level(
|
self.compile_with_scope_and_optimization_level(scope, scripts, self.optimization_level)
|
||||||
scope,
|
|
||||||
scripts,
|
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
|
||||||
self.optimization_level,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// Join a list of strings and compile into an [`AST`] using own scope at a specific optimization level.
|
/// Join a list of strings and compile into an [`AST`] using own scope at a specific optimization level.
|
||||||
///
|
///
|
||||||
@ -215,7 +210,7 @@ impl Engine {
|
|||||||
&self,
|
&self,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
scripts: impl AsRef<[S]>,
|
scripts: impl AsRef<[S]>,
|
||||||
#[cfg(not(feature = "no_optimize"))] optimization_level: crate::OptimizationLevel,
|
optimization_level: OptimizationLevel,
|
||||||
) -> ParseResult<AST> {
|
) -> ParseResult<AST> {
|
||||||
let (stream, tokenizer_control) = self.lex_raw(
|
let (stream, tokenizer_control) = self.lex_raw(
|
||||||
scripts.as_ref(),
|
scripts.as_ref(),
|
||||||
@ -226,7 +221,6 @@ impl Engine {
|
|||||||
&mut stream.peekable(),
|
&mut stream.peekable(),
|
||||||
&mut state,
|
&mut state,
|
||||||
scope,
|
scope,
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
|
||||||
optimization_level,
|
optimization_level,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -298,13 +292,7 @@ impl Engine {
|
|||||||
|
|
||||||
let mut peekable = stream.peekable();
|
let mut peekable = stream.peekable();
|
||||||
let mut state = ParseState::new(self, tokenizer_control);
|
let mut state = ParseState::new(self, tokenizer_control);
|
||||||
self.parse_global_expr(
|
self.parse_global_expr(&mut peekable, &mut state, scope, self.optimization_level)
|
||||||
&mut peekable,
|
|
||||||
&mut state,
|
|
||||||
scope,
|
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
|
||||||
self.optimization_level,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/// Parse a JSON string into an [object map][crate::Map].
|
/// Parse a JSON string into an [object map][crate::Map].
|
||||||
/// This is a light-weight alternative to using, say,
|
/// This is a light-weight alternative to using, say,
|
||||||
@ -400,7 +388,9 @@ impl Engine {
|
|||||||
&mut state,
|
&mut state,
|
||||||
&scope,
|
&scope,
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
crate::OptimizationLevel::None,
|
OptimizationLevel::None,
|
||||||
|
#[cfg(feature = "no_optimize")]
|
||||||
|
OptimizationLevel::default(),
|
||||||
)?;
|
)?;
|
||||||
if has_null {
|
if has_null {
|
||||||
scope.push_constant("null", ());
|
scope.push_constant("null", ());
|
||||||
|
@ -3,16 +3,15 @@
|
|||||||
use crate::ast::Expr;
|
use crate::ast::Expr;
|
||||||
use crate::func::native::SendSync;
|
use crate::func::native::SendSync;
|
||||||
use crate::parser::ParseResult;
|
use crate::parser::ParseResult;
|
||||||
use crate::r#unsafe::unsafe_try_cast;
|
|
||||||
use crate::tokenizer::{is_valid_identifier, Token};
|
use crate::tokenizer::{is_valid_identifier, Token};
|
||||||
use crate::types::dynamic::Variant;
|
use crate::types::dynamic::Variant;
|
||||||
use crate::{
|
use crate::{
|
||||||
Engine, EvalContext, Identifier, ImmutableString, LexError, Position, RhaiResult, Shared,
|
reify, Engine, EvalContext, Identifier, ImmutableString, LexError, Position, RhaiResult,
|
||||||
StaticVec, INT,
|
Shared, StaticVec,
|
||||||
};
|
};
|
||||||
|
use std::ops::Deref;
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
use std::{any::TypeId, ops::Deref};
|
|
||||||
|
|
||||||
/// Collection of special markers for custom syntax definition.
|
/// Collection of special markers for custom syntax definition.
|
||||||
pub mod markers {
|
pub mod markers {
|
||||||
@ -73,9 +72,9 @@ impl Expression<'_> {
|
|||||||
pub fn get_string_value(&self) -> Option<&str> {
|
pub fn get_string_value(&self) -> Option<&str> {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Expr::Variable(_, _, x) if x.1.is_some() => None,
|
Expr::Variable(.., x) if x.1.is_some() => None,
|
||||||
Expr::Variable(_, _, x) => Some(x.2.as_str()),
|
Expr::Variable(.., x) => Some(x.2.as_str()),
|
||||||
Expr::StringConstant(x, _) => Some(x.as_str()),
|
Expr::StringConstant(x, ..) => Some(x.as_str()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,46 +93,23 @@ impl Expression<'_> {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_literal_value<T: Variant>(&self) -> Option<T> {
|
pub fn get_literal_value<T: Variant>(&self) -> Option<T> {
|
||||||
// Coded this way in order to maximally leverage potentials for dead-code removal.
|
// Coded this way in order to maximally leverage potentials for dead-code removal.
|
||||||
|
match self.0 {
|
||||||
|
Expr::IntegerConstant(x, ..) => reify!(*x => Option<T>),
|
||||||
|
|
||||||
if TypeId::of::<T>() == TypeId::of::<INT>() {
|
#[cfg(not(feature = "no_float"))]
|
||||||
return match self.0 {
|
Expr::FloatConstant(x, ..) => reify!(*x => Option<T>),
|
||||||
Expr::IntegerConstant(x, _) => unsafe_try_cast(*x),
|
|
||||||
_ => None,
|
Expr::CharConstant(x, ..) => reify!(*x => Option<T>),
|
||||||
};
|
Expr::StringConstant(x, ..) => reify!(x.clone() => Option<T>),
|
||||||
|
Expr::Variable(.., x) => {
|
||||||
|
let x: ImmutableString = x.2.clone().into();
|
||||||
|
reify!(x => Option<T>)
|
||||||
|
}
|
||||||
|
Expr::BoolConstant(x, ..) => reify!(*x => Option<T>),
|
||||||
|
Expr::Unit(..) => reify!(() => Option<T>),
|
||||||
|
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
if TypeId::of::<T>() == TypeId::of::<crate::FLOAT>() {
|
|
||||||
return match self.0 {
|
|
||||||
Expr::FloatConstant(x, _) => unsafe_try_cast(*x),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if TypeId::of::<T>() == TypeId::of::<char>() {
|
|
||||||
return match self.0 {
|
|
||||||
Expr::CharConstant(x, _) => unsafe_try_cast(*x),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
|
|
||||||
return match self.0 {
|
|
||||||
Expr::StringConstant(x, _) => unsafe_try_cast(x.clone()),
|
|
||||||
Expr::Variable(_, _, x) => unsafe_try_cast(Into::<ImmutableString>::into(&x.2)),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if TypeId::of::<T>() == TypeId::of::<bool>() {
|
|
||||||
return match self.0 {
|
|
||||||
Expr::BoolConstant(x, _) => unsafe_try_cast(*x),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if TypeId::of::<T>() == TypeId::of::<()>() {
|
|
||||||
return match self.0 {
|
|
||||||
Expr::Unit(_) => unsafe_try_cast(()),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
use crate::eval::{EvalState, GlobalRuntimeState};
|
use crate::eval::{EvalState, GlobalRuntimeState};
|
||||||
use crate::parser::ParseState;
|
use crate::parser::ParseState;
|
||||||
use crate::types::dynamic::Variant;
|
use crate::types::dynamic::Variant;
|
||||||
use crate::{Dynamic, Engine, Module, Position, RhaiResult, RhaiResultOf, Scope, AST, ERR};
|
use crate::{
|
||||||
|
Dynamic, Engine, Module, OptimizationLevel, Position, RhaiResult, RhaiResultOf, Scope, AST, ERR,
|
||||||
|
};
|
||||||
use std::any::type_name;
|
use std::any::type_name;
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -64,7 +66,6 @@ impl Engine {
|
|||||||
let ast = self.compile_with_scope_and_optimization_level(
|
let ast = self.compile_with_scope_and_optimization_level(
|
||||||
scope,
|
scope,
|
||||||
&[script],
|
&[script],
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
|
||||||
self.optimization_level,
|
self.optimization_level,
|
||||||
)?;
|
)?;
|
||||||
self.eval_ast_with_scope(scope, &ast)
|
self.eval_ast_with_scope(scope, &ast)
|
||||||
@ -122,7 +123,9 @@ impl Engine {
|
|||||||
&mut state,
|
&mut state,
|
||||||
scope,
|
scope,
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
crate::OptimizationLevel::None,
|
OptimizationLevel::None,
|
||||||
|
#[cfg(feature = "no_optimize")]
|
||||||
|
OptimizationLevel::default(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.eval_ast_with_scope(scope, &ast)
|
self.eval_ast_with_scope(scope, &ast)
|
||||||
|
@ -226,7 +226,7 @@ impl Engine {
|
|||||||
|
|
||||||
match Token::lookup_from_syntax(keyword.as_ref()) {
|
match Token::lookup_from_syntax(keyword.as_ref()) {
|
||||||
// Standard identifiers, reserved keywords and custom keywords are OK
|
// Standard identifiers, reserved keywords and custom keywords are OK
|
||||||
None | Some(Token::Reserved(_)) | Some(Token::Custom(_)) => (),
|
None | Some(Token::Reserved(..)) | Some(Token::Custom(..)) => (),
|
||||||
// Active standard keywords cannot be made custom
|
// Active standard keywords cannot be made custom
|
||||||
// Disabled keywords are OK
|
// Disabled keywords are OK
|
||||||
Some(token) if token.is_standard_keyword() => {
|
Some(token) if token.is_standard_keyword() => {
|
||||||
|
@ -30,7 +30,6 @@ impl Engine {
|
|||||||
&mut stream.peekable(),
|
&mut stream.peekable(),
|
||||||
&mut state,
|
&mut state,
|
||||||
scope,
|
scope,
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
|
||||||
self.optimization_level,
|
self.optimization_level,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ impl fmt::Debug for AST {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
if !self.lib.is_empty() {
|
if !self.lib.is_empty() {
|
||||||
for (_, _, _, _, ref fn_def) in self.lib.iter_script_fn() {
|
for (.., ref fn_def) in self.lib.iter_script_fn() {
|
||||||
let sig = fn_def.to_string();
|
let sig = fn_def.to_string();
|
||||||
fp.field(&sig, &fn_def.body.as_slice());
|
fp.field(&sig, &fn_def.body.as_slice());
|
||||||
}
|
}
|
||||||
@ -449,7 +449,7 @@ impl AST {
|
|||||||
/// foo("!")
|
/// foo("!")
|
||||||
/// "#)?;
|
/// "#)?;
|
||||||
///
|
///
|
||||||
/// // Merge 'ast2', picking only 'error()' but not 'foo(_)', into 'ast1'
|
/// // Merge 'ast2', picking only 'error()' but not 'foo(..)', into 'ast1'
|
||||||
/// let ast = ast1.merge_filtered(&ast2, |_, _, script, name, params|
|
/// let ast = ast1.merge_filtered(&ast2, |_, _, script, name, params|
|
||||||
/// script && name == "error" && params == 0);
|
/// script && name == "error" && params == 0);
|
||||||
///
|
///
|
||||||
@ -551,7 +551,7 @@ impl AST {
|
|||||||
/// foo("!")
|
/// foo("!")
|
||||||
/// "#)?;
|
/// "#)?;
|
||||||
///
|
///
|
||||||
/// // Combine 'ast2', picking only 'error()' but not 'foo(_)', into 'ast1'
|
/// // Combine 'ast2', picking only 'error()' but not 'foo(..)', into 'ast1'
|
||||||
/// ast1.combine_filtered(ast2, |_, _, script, name, params|
|
/// ast1.combine_filtered(ast2, |_, _, script, name, params|
|
||||||
/// script && name == "error" && params == 0);
|
/// script && name == "error" && params == 0);
|
||||||
///
|
///
|
||||||
@ -613,7 +613,7 @@ impl AST {
|
|||||||
/// fn bar() { print("hello"); }
|
/// fn bar() { print("hello"); }
|
||||||
/// "#)?;
|
/// "#)?;
|
||||||
///
|
///
|
||||||
/// // Remove all functions except 'foo(_)'
|
/// // Remove all functions except 'foo(..)'
|
||||||
/// ast.retain_functions(|_, _, name, params| name == "foo" && params == 1);
|
/// ast.retain_functions(|_, _, name, params| name == "foo" && params == 1);
|
||||||
/// # }
|
/// # }
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
@ -640,7 +640,7 @@ impl AST {
|
|||||||
pub fn iter_fn_def(&self) -> impl Iterator<Item = &super::ScriptFnDef> {
|
pub fn iter_fn_def(&self) -> impl Iterator<Item = &super::ScriptFnDef> {
|
||||||
self.lib
|
self.lib
|
||||||
.iter_script_fn()
|
.iter_script_fn()
|
||||||
.map(|(_, _, _, _, fn_def)| fn_def.as_ref())
|
.map(|(.., fn_def)| fn_def.as_ref())
|
||||||
}
|
}
|
||||||
/// Iterate through all function definitions.
|
/// Iterate through all function definitions.
|
||||||
///
|
///
|
||||||
@ -652,7 +652,7 @@ impl AST {
|
|||||||
pub(crate) fn iter_fn_def(&self) -> impl Iterator<Item = &super::ScriptFnDef> {
|
pub(crate) fn iter_fn_def(&self) -> impl Iterator<Item = &super::ScriptFnDef> {
|
||||||
self.lib
|
self.lib
|
||||||
.iter_script_fn()
|
.iter_script_fn()
|
||||||
.map(|(_, _, _, _, fn_def)| fn_def.as_ref())
|
.map(|(.., fn_def)| fn_def.as_ref())
|
||||||
}
|
}
|
||||||
/// Iterate through all function definitions.
|
/// Iterate through all function definitions.
|
||||||
///
|
///
|
||||||
@ -662,7 +662,7 @@ impl AST {
|
|||||||
pub fn iter_functions<'a>(&'a self) -> impl Iterator<Item = super::ScriptFnMetadata> + 'a {
|
pub fn iter_functions<'a>(&'a self) -> impl Iterator<Item = super::ScriptFnMetadata> + 'a {
|
||||||
self.lib
|
self.lib
|
||||||
.iter_script_fn()
|
.iter_script_fn()
|
||||||
.map(|(_, _, _, _, fn_def)| fn_def.as_ref().into())
|
.map(|(.., fn_def)| fn_def.as_ref().into())
|
||||||
}
|
}
|
||||||
/// Clear all function definitions in the [`AST`].
|
/// Clear all function definitions in the [`AST`].
|
||||||
///
|
///
|
||||||
@ -744,7 +744,7 @@ impl AST {
|
|||||||
include_variables: bool,
|
include_variables: bool,
|
||||||
) -> impl Iterator<Item = (&str, bool, Dynamic)> {
|
) -> impl Iterator<Item = (&str, bool, Dynamic)> {
|
||||||
self.statements().iter().filter_map(move |stmt| match stmt {
|
self.statements().iter().filter_map(move |stmt| match stmt {
|
||||||
Stmt::Var(expr, name, options, _)
|
Stmt::Var(expr, name, options, ..)
|
||||||
if options.contains(AST_OPTION_CONSTANT) && include_constants
|
if options.contains(AST_OPTION_CONSTANT) && include_constants
|
||||||
|| !options.contains(AST_OPTION_CONSTANT) && include_variables =>
|
|| !options.contains(AST_OPTION_CONSTANT) && include_variables =>
|
||||||
{
|
{
|
||||||
|
282
src/ast/expr.rs
282
src/ast/expr.rs
@ -443,24 +443,24 @@ impl fmt::Debug for Expr {
|
|||||||
let mut display_pos = self.start_position();
|
let mut display_pos = self.start_position();
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Self::DynamicConstant(value, _) => write!(f, "{:?}", value),
|
Self::DynamicConstant(value, ..) => write!(f, "{:?}", value),
|
||||||
Self::BoolConstant(value, _) => write!(f, "{:?}", value),
|
Self::BoolConstant(value, ..) => write!(f, "{:?}", value),
|
||||||
Self::IntegerConstant(value, _) => write!(f, "{:?}", value),
|
Self::IntegerConstant(value, ..) => write!(f, "{:?}", value),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Self::FloatConstant(value, _) => write!(f, "{:?}", value),
|
Self::FloatConstant(value, ..) => write!(f, "{:?}", value),
|
||||||
Self::CharConstant(value, _) => write!(f, "{:?}", value),
|
Self::CharConstant(value, ..) => write!(f, "{:?}", value),
|
||||||
Self::StringConstant(value, _) => write!(f, "{:?}", value),
|
Self::StringConstant(value, ..) => write!(f, "{:?}", value),
|
||||||
Self::Unit(_) => f.write_str("()"),
|
Self::Unit(..) => f.write_str("()"),
|
||||||
|
|
||||||
Self::InterpolatedString(x, _) => {
|
Self::InterpolatedString(x, ..) => {
|
||||||
f.write_str("InterpolatedString")?;
|
f.write_str("InterpolatedString")?;
|
||||||
return f.debug_list().entries(x.iter()).finish();
|
return f.debug_list().entries(x.iter()).finish();
|
||||||
}
|
}
|
||||||
Self::Array(x, _) => {
|
Self::Array(x, ..) => {
|
||||||
f.write_str("Array")?;
|
f.write_str("Array")?;
|
||||||
f.debug_list().entries(x.iter()).finish()
|
f.debug_list().entries(x.iter()).finish()
|
||||||
}
|
}
|
||||||
Self::Map(x, _) => {
|
Self::Map(x, ..) => {
|
||||||
f.write_str("Map")?;
|
f.write_str("Map")?;
|
||||||
f.debug_map()
|
f.debug_map()
|
||||||
.entries(x.0.iter().map(|(k, v)| (k, v)))
|
.entries(x.0.iter().map(|(k, v)| (k, v)))
|
||||||
@ -470,7 +470,7 @@ impl fmt::Debug for Expr {
|
|||||||
f.write_str("Variable(")?;
|
f.write_str("Variable(")?;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
if let Some((_, ref namespace)) = x.1 {
|
if let Some((.., ref namespace)) = x.1 {
|
||||||
write!(f, "{}{}", namespace, Token::DoubleColon.literal_syntax())?
|
write!(f, "{}{}", namespace, Token::DoubleColon.literal_syntax())?
|
||||||
}
|
}
|
||||||
f.write_str(&x.2)?;
|
f.write_str(&x.2)?;
|
||||||
@ -479,13 +479,13 @@ impl fmt::Debug for Expr {
|
|||||||
}
|
}
|
||||||
f.write_str(")")
|
f.write_str(")")
|
||||||
}
|
}
|
||||||
Self::Property(x, _) => write!(f, "Property({})", x.2),
|
Self::Property(x, ..) => write!(f, "Property({})", x.2),
|
||||||
Self::Stack(x, _) => write!(f, "ConstantArg#{}", x),
|
Self::Stack(x, ..) => write!(f, "ConstantArg#{}", x),
|
||||||
Self::Stmt(x) => {
|
Self::Stmt(x) => {
|
||||||
f.write_str("ExprStmtBlock")?;
|
f.write_str("ExprStmtBlock")?;
|
||||||
f.debug_list().entries(x.iter()).finish()
|
f.debug_list().entries(x.iter()).finish()
|
||||||
}
|
}
|
||||||
Self::FnCall(x, _) => fmt::Debug::fmt(x, f),
|
Self::FnCall(x, ..) => fmt::Debug::fmt(x, f),
|
||||||
Self::Index(x, term, pos) => {
|
Self::Index(x, term, pos) => {
|
||||||
display_pos = *pos;
|
display_pos = *pos;
|
||||||
|
|
||||||
@ -497,9 +497,9 @@ impl fmt::Debug for Expr {
|
|||||||
}
|
}
|
||||||
Self::Dot(x, _, pos) | Self::And(x, pos) | Self::Or(x, pos) => {
|
Self::Dot(x, _, pos) | Self::And(x, pos) | Self::Or(x, pos) => {
|
||||||
let op_name = match self {
|
let op_name = match self {
|
||||||
Self::Dot(_, _, _) => "Dot",
|
Self::Dot(..) => "Dot",
|
||||||
Self::And(_, _) => "And",
|
Self::And(..) => "And",
|
||||||
Self::Or(_, _) => "Or",
|
Self::Or(..) => "Or",
|
||||||
expr => unreachable!(
|
expr => unreachable!(
|
||||||
"Self::Dot or Self::And or Self::Or expected but gets {:?}",
|
"Self::Dot or Self::And or Self::Or expected but gets {:?}",
|
||||||
expr
|
expr
|
||||||
@ -513,7 +513,7 @@ impl fmt::Debug for Expr {
|
|||||||
.field("rhs", &x.rhs)
|
.field("rhs", &x.rhs)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
Self::Custom(x, _) => f.debug_tuple("Custom").field(x).finish(),
|
Self::Custom(x, ..) => f.debug_tuple("Custom").field(x).finish(),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
display_pos.debug_print(f)
|
display_pos.debug_print(f)
|
||||||
@ -528,24 +528,24 @@ impl Expr {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_literal_value(&self) -> Option<Dynamic> {
|
pub fn get_literal_value(&self) -> Option<Dynamic> {
|
||||||
Some(match self {
|
Some(match self {
|
||||||
Self::DynamicConstant(x, _) => x.as_ref().clone(),
|
Self::DynamicConstant(x, ..) => x.as_ref().clone(),
|
||||||
Self::IntegerConstant(x, _) => (*x).into(),
|
Self::IntegerConstant(x, ..) => (*x).into(),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Self::FloatConstant(x, _) => (*x).into(),
|
Self::FloatConstant(x, ..) => (*x).into(),
|
||||||
Self::CharConstant(x, _) => (*x).into(),
|
Self::CharConstant(x, ..) => (*x).into(),
|
||||||
Self::StringConstant(x, _) => x.clone().into(),
|
Self::StringConstant(x, ..) => x.clone().into(),
|
||||||
Self::BoolConstant(x, _) => (*x).into(),
|
Self::BoolConstant(x, ..) => (*x).into(),
|
||||||
Self::Unit(_) => Dynamic::UNIT,
|
Self::Unit(..) => Dynamic::UNIT,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Self::Array(x, _) if self.is_constant() => {
|
Self::Array(x, ..) if self.is_constant() => {
|
||||||
let mut arr = crate::Array::with_capacity(x.len());
|
let mut arr = crate::Array::with_capacity(x.len());
|
||||||
arr.extend(x.iter().map(|v| v.get_literal_value().unwrap()));
|
arr.extend(x.iter().map(|v| v.get_literal_value().unwrap()));
|
||||||
Dynamic::from_array(arr)
|
Dynamic::from_array(arr)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Self::Map(x, _) if self.is_constant() => {
|
Self::Map(x, ..) if self.is_constant() => {
|
||||||
Dynamic::from_map(x.0.iter().fold(x.1.clone(), |mut map, (k, v)| {
|
Dynamic::from_map(x.0.iter().fold(x.1.clone(), |mut map, (k, v)| {
|
||||||
let value_ref = map.get_mut(k.name.as_str()).unwrap();
|
let value_ref = map.get_mut(k.name.as_str()).unwrap();
|
||||||
*value_ref = v.get_literal_value().unwrap();
|
*value_ref = v.get_literal_value().unwrap();
|
||||||
@ -554,10 +554,10 @@ impl Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fn
|
// Fn
|
||||||
Self::FnCall(ref x, _)
|
Self::FnCall(ref x, ..)
|
||||||
if !x.is_qualified() && x.args.len() == 1 && x.name == KEYWORD_FN_PTR =>
|
if !x.is_qualified() && x.args.len() == 1 && x.name == KEYWORD_FN_PTR =>
|
||||||
{
|
{
|
||||||
if let Expr::StringConstant(ref s, _) = x.args[0] {
|
if let Expr::StringConstant(ref s, ..) = x.args[0] {
|
||||||
if let Ok(fn_ptr) = FnPtr::new(s) {
|
if let Ok(fn_ptr) = FnPtr::new(s) {
|
||||||
fn_ptr.into()
|
fn_ptr.into()
|
||||||
} else {
|
} else {
|
||||||
@ -569,33 +569,35 @@ impl Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Binary operators
|
// Binary operators
|
||||||
Self::FnCall(x, _) if !x.is_qualified() && x.args.len() == 2 => match x.name.as_str() {
|
Self::FnCall(x, ..) if !x.is_qualified() && x.args.len() == 2 => {
|
||||||
// x..y
|
match x.name.as_str() {
|
||||||
OP_EXCLUSIVE_RANGE => {
|
// x..y
|
||||||
if let Expr::IntegerConstant(ref start, _) = x.args[0] {
|
OP_EXCLUSIVE_RANGE => {
|
||||||
if let Expr::IntegerConstant(ref end, _) = x.args[1] {
|
if let Expr::IntegerConstant(ref start, ..) = x.args[0] {
|
||||||
(*start..*end).into()
|
if let Expr::IntegerConstant(ref end, ..) = x.args[1] {
|
||||||
|
(*start..*end).into()
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
}
|
// x..=y
|
||||||
// x..=y
|
OP_INCLUSIVE_RANGE => {
|
||||||
OP_INCLUSIVE_RANGE => {
|
if let Expr::IntegerConstant(ref start, ..) = x.args[0] {
|
||||||
if let Expr::IntegerConstant(ref start, _) = x.args[0] {
|
if let Expr::IntegerConstant(ref end, ..) = x.args[1] {
|
||||||
if let Expr::IntegerConstant(ref end, _) = x.args[1] {
|
(*start..=*end).into()
|
||||||
(*start..=*end).into()
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
|
_ => return None,
|
||||||
}
|
}
|
||||||
_ => return None,
|
}
|
||||||
},
|
|
||||||
|
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
@ -605,25 +607,25 @@ impl Expr {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_dynamic(value: Dynamic, pos: Position) -> Self {
|
pub fn from_dynamic(value: Dynamic, pos: Position) -> Self {
|
||||||
match value.0 {
|
match value.0 {
|
||||||
Union::Unit(_, _, _) => Self::Unit(pos),
|
Union::Unit(..) => Self::Unit(pos),
|
||||||
Union::Bool(b, _, _) => Self::BoolConstant(b, pos),
|
Union::Bool(b, ..) => Self::BoolConstant(b, pos),
|
||||||
Union::Str(s, _, _) => Self::StringConstant(s, pos),
|
Union::Str(s, ..) => Self::StringConstant(s, pos),
|
||||||
Union::Char(c, _, _) => Self::CharConstant(c, pos),
|
Union::Char(c, ..) => Self::CharConstant(c, pos),
|
||||||
Union::Int(i, _, _) => Self::IntegerConstant(i, pos),
|
Union::Int(i, ..) => Self::IntegerConstant(i, pos),
|
||||||
|
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
Union::Decimal(value, _, _) => Self::DynamicConstant(Box::new((*value).into()), pos),
|
Union::Decimal(value, ..) => Self::DynamicConstant(Box::new((*value).into()), pos),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Union::Float(f, _, _) => Self::FloatConstant(f, pos),
|
Union::Float(f, ..) => Self::FloatConstant(f, pos),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(a, _, _) => Self::DynamicConstant(Box::new((*a).into()), pos),
|
Union::Array(a, ..) => Self::DynamicConstant(Box::new((*a).into()), pos),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(m, _, _) => Self::DynamicConstant(Box::new((*m).into()), pos),
|
Union::Map(m, ..) => Self::DynamicConstant(Box::new((*m).into()), pos),
|
||||||
|
|
||||||
Union::FnPtr(f, _, _) if !f.is_curried() => Self::FnCall(
|
Union::FnPtr(f, ..) if !f.is_curried() => Self::FnCall(
|
||||||
FnCallExpr {
|
FnCallExpr {
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
namespace: None,
|
namespace: None,
|
||||||
@ -651,8 +653,8 @@ impl Expr {
|
|||||||
|
|
||||||
match self {
|
match self {
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Variable(_, _, x) if _non_qualified && x.1.is_some() => false,
|
Self::Variable(.., x) if _non_qualified && x.1.is_some() => false,
|
||||||
Self::Variable(_, _, _) => true,
|
Self::Variable(..) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -666,8 +668,8 @@ impl Expr {
|
|||||||
|
|
||||||
match self {
|
match self {
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Variable(_, _, x) if _non_qualified && x.1.is_some() => None,
|
Self::Variable(.., x) if _non_qualified && x.1.is_some() => None,
|
||||||
Self::Variable(_, _, x) => Some(x.2.as_str()),
|
Self::Variable(.., x) => Some(x.2.as_str()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -677,27 +679,27 @@ impl Expr {
|
|||||||
pub const fn position(&self) -> Position {
|
pub const fn position(&self) -> Position {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Self::FloatConstant(_, pos) => *pos,
|
Self::FloatConstant(.., pos) => *pos,
|
||||||
|
|
||||||
Self::DynamicConstant(_, pos)
|
Self::DynamicConstant(.., pos)
|
||||||
| Self::BoolConstant(_, pos)
|
| Self::BoolConstant(.., pos)
|
||||||
| Self::IntegerConstant(_, pos)
|
| Self::IntegerConstant(.., pos)
|
||||||
| Self::CharConstant(_, pos)
|
| Self::CharConstant(.., pos)
|
||||||
| Self::Unit(pos)
|
| Self::Unit(pos)
|
||||||
| Self::StringConstant(_, pos)
|
| Self::StringConstant(.., pos)
|
||||||
| Self::Array(_, pos)
|
| Self::Array(.., pos)
|
||||||
| Self::Map(_, pos)
|
| Self::Map(.., pos)
|
||||||
| Self::Variable(_, pos, _)
|
| Self::Variable(.., pos, _)
|
||||||
| Self::Stack(_, pos)
|
| Self::Stack(.., pos)
|
||||||
| Self::And(_, pos)
|
| Self::And(.., pos)
|
||||||
| Self::Or(_, pos)
|
| Self::Or(.., pos)
|
||||||
| Self::Index(_, _, pos)
|
| Self::Index(.., pos)
|
||||||
| Self::Dot(_, _, pos)
|
| Self::Dot(.., pos)
|
||||||
| Self::Custom(_, pos)
|
| Self::Custom(.., pos)
|
||||||
| Self::InterpolatedString(_, pos)
|
| Self::InterpolatedString(.., pos)
|
||||||
| Self::Property(_, pos) => *pos,
|
| Self::Property(.., pos) => *pos,
|
||||||
|
|
||||||
Self::FnCall(x, _) => x.pos,
|
Self::FnCall(x, ..) => x.pos,
|
||||||
|
|
||||||
Self::Stmt(x) => x.position(),
|
Self::Stmt(x) => x.position(),
|
||||||
}
|
}
|
||||||
@ -708,10 +710,10 @@ impl Expr {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn start_position(&self) -> Position {
|
pub const fn start_position(&self) -> Position {
|
||||||
match self {
|
match self {
|
||||||
Self::And(x, _) | Self::Or(x, _) | Self::Index(x, _, _) | Self::Dot(x, _, _) => {
|
Self::And(x, ..) | Self::Or(x, ..) | Self::Index(x, ..) | Self::Dot(x, ..) => {
|
||||||
x.lhs.start_position()
|
x.lhs.start_position()
|
||||||
}
|
}
|
||||||
Self::FnCall(_, pos) => *pos,
|
Self::FnCall(.., pos) => *pos,
|
||||||
_ => self.position(),
|
_ => self.position(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -720,26 +722,26 @@ impl Expr {
|
|||||||
pub fn set_position(&mut self, new_pos: Position) -> &mut Self {
|
pub fn set_position(&mut self, new_pos: Position) -> &mut Self {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Self::FloatConstant(_, pos) => *pos = new_pos,
|
Self::FloatConstant(.., pos) => *pos = new_pos,
|
||||||
|
|
||||||
Self::DynamicConstant(_, pos)
|
Self::DynamicConstant(.., pos)
|
||||||
| Self::BoolConstant(_, pos)
|
| Self::BoolConstant(.., pos)
|
||||||
| Self::IntegerConstant(_, pos)
|
| Self::IntegerConstant(.., pos)
|
||||||
| Self::CharConstant(_, pos)
|
| Self::CharConstant(.., pos)
|
||||||
| Self::Unit(pos)
|
| Self::Unit(pos)
|
||||||
| Self::StringConstant(_, pos)
|
| Self::StringConstant(.., pos)
|
||||||
| Self::Array(_, pos)
|
| Self::Array(.., pos)
|
||||||
| Self::Map(_, pos)
|
| Self::Map(.., pos)
|
||||||
| Self::And(_, pos)
|
| Self::And(.., pos)
|
||||||
| Self::Or(_, pos)
|
| Self::Or(.., pos)
|
||||||
| Self::Dot(_, _, pos)
|
| Self::Dot(.., pos)
|
||||||
| Self::Index(_, _, pos)
|
| Self::Index(.., pos)
|
||||||
| Self::Variable(_, pos, _)
|
| Self::Variable(.., pos, _)
|
||||||
| Self::Stack(_, pos)
|
| Self::Stack(.., pos)
|
||||||
| Self::FnCall(_, pos)
|
| Self::FnCall(.., pos)
|
||||||
| Self::Custom(_, pos)
|
| Self::Custom(.., pos)
|
||||||
| Self::InterpolatedString(_, pos)
|
| Self::InterpolatedString(.., pos)
|
||||||
| Self::Property(_, pos) => *pos = new_pos,
|
| Self::Property(.., pos) => *pos = new_pos,
|
||||||
|
|
||||||
Self::Stmt(x) => x.set_position(new_pos, Position::NONE),
|
Self::Stmt(x) => x.set_position(new_pos, Position::NONE),
|
||||||
}
|
}
|
||||||
@ -753,15 +755,15 @@ impl Expr {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_pure(&self) -> bool {
|
pub fn is_pure(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::InterpolatedString(x, _) | Self::Array(x, _) => x.iter().all(Self::is_pure),
|
Self::InterpolatedString(x, ..) | Self::Array(x, ..) => x.iter().all(Self::is_pure),
|
||||||
|
|
||||||
Self::Map(x, _) => x.0.iter().map(|(_, v)| v).all(Self::is_pure),
|
Self::Map(x, ..) => x.0.iter().map(|(.., v)| v).all(Self::is_pure),
|
||||||
|
|
||||||
Self::And(x, _) | Self::Or(x, _) => x.lhs.is_pure() && x.rhs.is_pure(),
|
Self::And(x, ..) | Self::Or(x, ..) => x.lhs.is_pure() && x.rhs.is_pure(),
|
||||||
|
|
||||||
Self::Stmt(x) => x.iter().all(Stmt::is_pure),
|
Self::Stmt(x) => x.iter().all(Stmt::is_pure),
|
||||||
|
|
||||||
Self::Variable(_, _, _) | Self::Stack(_, _) => true,
|
Self::Variable(..) | Self::Stack(..) => true,
|
||||||
|
|
||||||
_ => self.is_constant(),
|
_ => self.is_constant(),
|
||||||
}
|
}
|
||||||
@ -770,7 +772,7 @@ impl Expr {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_unit(&self) -> bool {
|
pub const fn is_unit(&self) -> bool {
|
||||||
matches!(self, Self::Unit(_))
|
matches!(self, Self::Unit(..))
|
||||||
}
|
}
|
||||||
/// Is the expression a constant?
|
/// Is the expression a constant?
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -778,19 +780,19 @@ impl Expr {
|
|||||||
pub fn is_constant(&self) -> bool {
|
pub fn is_constant(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Self::FloatConstant(_, _) => true,
|
Self::FloatConstant(..) => true,
|
||||||
|
|
||||||
Self::DynamicConstant(_, _)
|
Self::DynamicConstant(..)
|
||||||
| Self::BoolConstant(_, _)
|
| Self::BoolConstant(..)
|
||||||
| Self::IntegerConstant(_, _)
|
| Self::IntegerConstant(..)
|
||||||
| Self::CharConstant(_, _)
|
| Self::CharConstant(..)
|
||||||
| Self::StringConstant(_, _)
|
| Self::StringConstant(..)
|
||||||
| Self::Unit(_)
|
| Self::Unit(..)
|
||||||
| Self::Stack(_, _) => true,
|
| Self::Stack(..) => true,
|
||||||
|
|
||||||
Self::InterpolatedString(x, _) | Self::Array(x, _) => x.iter().all(Self::is_constant),
|
Self::InterpolatedString(x, ..) | Self::Array(x, ..) => x.iter().all(Self::is_constant),
|
||||||
|
|
||||||
Self::Map(x, _) => x.0.iter().map(|(_, expr)| expr).all(Self::is_constant),
|
Self::Map(x, ..) => x.0.iter().map(|(.., expr)| expr).all(Self::is_constant),
|
||||||
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
@ -807,31 +809,31 @@ impl Expr {
|
|||||||
|
|
||||||
match self {
|
match self {
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Self::FloatConstant(_, _) => false,
|
Self::FloatConstant(..) => false,
|
||||||
|
|
||||||
Self::DynamicConstant(_, _)
|
Self::DynamicConstant(..)
|
||||||
| Self::BoolConstant(_, _)
|
| Self::BoolConstant(..)
|
||||||
| Self::CharConstant(_, _)
|
| Self::CharConstant(..)
|
||||||
| Self::And(_, _)
|
| Self::And(..)
|
||||||
| Self::Or(_, _)
|
| Self::Or(..)
|
||||||
| Self::Unit(_) => false,
|
| Self::Unit(..) => false,
|
||||||
|
|
||||||
Self::IntegerConstant(_, _)
|
Self::IntegerConstant(..)
|
||||||
| Self::StringConstant(_, _)
|
| Self::StringConstant(..)
|
||||||
| Self::InterpolatedString(_, _)
|
| Self::InterpolatedString(..)
|
||||||
| Self::FnCall(_, _)
|
| Self::FnCall(..)
|
||||||
| Self::Stmt(_)
|
| Self::Stmt(..)
|
||||||
| Self::Dot(_, _, _)
|
| Self::Dot(..)
|
||||||
| Self::Index(_, _, _)
|
| Self::Index(..)
|
||||||
| Self::Array(_, _)
|
| Self::Array(..)
|
||||||
| Self::Map(_, _)
|
| Self::Map(..)
|
||||||
| Self::Custom(_, _) => match token {
|
| Self::Custom(..) => match token {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Token::LeftBracket => true,
|
Token::LeftBracket => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
|
||||||
Self::Variable(_, _, _) => match token {
|
Self::Variable(..) => match token {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Token::LeftBracket => true,
|
Token::LeftBracket => true,
|
||||||
Token::LeftParen => true,
|
Token::LeftParen => true,
|
||||||
@ -840,14 +842,14 @@ impl Expr {
|
|||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
|
||||||
Self::Property(_, _) => match token {
|
Self::Property(..) => match token {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Token::LeftBracket => true,
|
Token::LeftBracket => true,
|
||||||
Token::LeftParen => true,
|
Token::LeftParen => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
|
||||||
Self::Stack(_, _) => false,
|
Self::Stack(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Recursively walk this expression.
|
/// Recursively walk this expression.
|
||||||
@ -872,21 +874,21 @@ impl Expr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::InterpolatedString(x, _) | Self::Array(x, _) => {
|
Self::InterpolatedString(x, ..) | Self::Array(x, ..) => {
|
||||||
for e in x.as_ref() {
|
for e in x.as_ref() {
|
||||||
if !e.walk(path, on_node) {
|
if !e.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::Map(x, _) => {
|
Self::Map(x, ..) => {
|
||||||
for (_, e) in &x.0 {
|
for (.., e) in &x.0 {
|
||||||
if !e.walk(path, on_node) {
|
if !e.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::Index(x, _, _) | Self::Dot(x, _, _) | Expr::And(x, _) | Expr::Or(x, _) => {
|
Self::Index(x, ..) | Self::Dot(x, ..) | Expr::And(x, ..) | Expr::Or(x, ..) => {
|
||||||
if !x.lhs.walk(path, on_node) {
|
if !x.lhs.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -894,14 +896,14 @@ impl Expr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::FnCall(x, _) => {
|
Self::FnCall(x, ..) => {
|
||||||
for e in &x.args {
|
for e in &x.args {
|
||||||
if !e.walk(path, on_node) {
|
if !e.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::Custom(x, _) => {
|
Self::Custom(x, ..) => {
|
||||||
for e in &x.inputs {
|
for e in &x.inputs {
|
||||||
if !e.walk(path, on_node) {
|
if !e.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
|
191
src/ast/stmt.rs
191
src/ast/stmt.rs
@ -404,65 +404,65 @@ impl Stmt {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_noop(&self) -> bool {
|
pub const fn is_noop(&self) -> bool {
|
||||||
matches!(self, Self::Noop(_))
|
matches!(self, Self::Noop(..))
|
||||||
}
|
}
|
||||||
/// Get the [position][Position] of this statement.
|
/// Get the [position][Position] of this statement.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn position(&self) -> Position {
|
pub const fn position(&self) -> Position {
|
||||||
match self {
|
match self {
|
||||||
Self::Noop(pos)
|
Self::Noop(pos)
|
||||||
| Self::BreakLoop(_, pos)
|
| Self::BreakLoop(.., pos)
|
||||||
| Self::Block(_, (pos, _))
|
| Self::Block(.., (pos, ..))
|
||||||
| Self::Assignment(_, pos)
|
| Self::Assignment(.., pos)
|
||||||
| Self::FnCall(_, pos)
|
| Self::FnCall(.., pos)
|
||||||
| Self::If(_, _, pos)
|
| Self::If(.., pos)
|
||||||
| Self::Switch(_, _, pos)
|
| Self::Switch(.., pos)
|
||||||
| Self::While(_, _, pos)
|
| Self::While(.., pos)
|
||||||
| Self::Do(_, _, _, pos)
|
| Self::Do(.., pos)
|
||||||
| Self::For(_, _, pos)
|
| Self::For(.., pos)
|
||||||
| Self::Return(_, _, pos)
|
| Self::Return(.., pos)
|
||||||
| Self::Var(_, _, _, pos)
|
| Self::Var(.., pos)
|
||||||
| Self::TryCatch(_, pos) => *pos,
|
| Self::TryCatch(.., pos) => *pos,
|
||||||
|
|
||||||
Self::Expr(x) => x.start_position(),
|
Self::Expr(x) => x.start_position(),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Import(_, _, pos) => *pos,
|
Self::Import(.., pos) => *pos,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Export(_, pos) => *pos,
|
Self::Export(.., pos) => *pos,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Self::Share(_) => Position::NONE,
|
Self::Share(..) => Position::NONE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Override the [position][Position] of this statement.
|
/// Override the [position][Position] of this statement.
|
||||||
pub fn set_position(&mut self, new_pos: Position) -> &mut Self {
|
pub fn set_position(&mut self, new_pos: Position) -> &mut Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Noop(pos)
|
Self::Noop(pos)
|
||||||
| Self::BreakLoop(_, pos)
|
| Self::BreakLoop(.., pos)
|
||||||
| Self::Block(_, (pos, _))
|
| Self::Block(.., (pos, ..))
|
||||||
| Self::Assignment(_, pos)
|
| Self::Assignment(.., pos)
|
||||||
| Self::FnCall(_, pos)
|
| Self::FnCall(.., pos)
|
||||||
| Self::If(_, _, pos)
|
| Self::If(.., pos)
|
||||||
| Self::Switch(_, _, pos)
|
| Self::Switch(.., pos)
|
||||||
| Self::While(_, _, pos)
|
| Self::While(.., pos)
|
||||||
| Self::Do(_, _, _, pos)
|
| Self::Do(.., pos)
|
||||||
| Self::For(_, _, pos)
|
| Self::For(.., pos)
|
||||||
| Self::Return(_, _, pos)
|
| Self::Return(.., pos)
|
||||||
| Self::Var(_, _, _, pos)
|
| Self::Var(.., pos)
|
||||||
| Self::TryCatch(_, pos) => *pos = new_pos,
|
| Self::TryCatch(.., pos) => *pos = new_pos,
|
||||||
|
|
||||||
Self::Expr(x) => {
|
Self::Expr(x) => {
|
||||||
x.set_position(new_pos);
|
x.set_position(new_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Import(_, _, pos) => *pos = new_pos,
|
Self::Import(.., pos) => *pos = new_pos,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Export(_, pos) => *pos = new_pos,
|
Self::Export(.., pos) => *pos = new_pos,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Self::Share(_) => (),
|
Self::Share(..) => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
@ -471,59 +471,56 @@ impl Stmt {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn returns_value(&self) -> bool {
|
pub const fn returns_value(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::If(_, _, _)
|
Self::If(..)
|
||||||
| Self::Switch(_, _, _)
|
| Self::Switch(..)
|
||||||
| Self::Block(_, _)
|
| Self::Block(..)
|
||||||
| Self::Expr(_)
|
| Self::Expr(..)
|
||||||
| Self::FnCall(_, _) => true,
|
| Self::FnCall(..) => true,
|
||||||
|
|
||||||
Self::Noop(_)
|
Self::Noop(..)
|
||||||
| Self::While(_, _, _)
|
| Self::While(..)
|
||||||
| Self::Do(_, _, _, _)
|
| Self::Do(..)
|
||||||
| Self::For(_, _, _)
|
| Self::For(..)
|
||||||
| Self::TryCatch(_, _) => false,
|
| Self::TryCatch(..) => false,
|
||||||
|
|
||||||
Self::Var(_, _, _, _)
|
Self::Var(..) | Self::Assignment(..) | Self::BreakLoop(..) | Self::Return(..) => false,
|
||||||
| Self::Assignment(_, _)
|
|
||||||
| Self::BreakLoop(_, _)
|
|
||||||
| Self::Return(_, _, _) => false,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Import(_, _, _) | Self::Export(_, _) => false,
|
Self::Import(..) | Self::Export(..) => false,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Self::Share(_) => false,
|
Self::Share(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is this statement self-terminated (i.e. no need for a semicolon terminator)?
|
/// Is this statement self-terminated (i.e. no need for a semicolon terminator)?
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_self_terminated(&self) -> bool {
|
pub const fn is_self_terminated(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::If(_, _, _)
|
Self::If(..)
|
||||||
| Self::Switch(_, _, _)
|
| Self::Switch(..)
|
||||||
| Self::While(_, _, _)
|
| Self::While(..)
|
||||||
| Self::For(_, _, _)
|
| Self::For(..)
|
||||||
| Self::Block(_, _)
|
| Self::Block(..)
|
||||||
| Self::TryCatch(_, _) => true,
|
| Self::TryCatch(..) => true,
|
||||||
|
|
||||||
// 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::Expr(Expr::Custom(x, _)) if x.is_self_terminated() => true,
|
Self::Expr(Expr::Custom(x, ..)) if x.is_self_terminated() => true,
|
||||||
|
|
||||||
Self::Var(_, _, _, _)
|
Self::Var(..)
|
||||||
| Self::Assignment(_, _)
|
| Self::Assignment(..)
|
||||||
| Self::Expr(_)
|
| Self::Expr(..)
|
||||||
| Self::FnCall(_, _)
|
| Self::FnCall(..)
|
||||||
| Self::Do(_, _, _, _)
|
| Self::Do(..)
|
||||||
| Self::BreakLoop(_, _)
|
| Self::BreakLoop(..)
|
||||||
| Self::Return(_, _, _) => false,
|
| Self::Return(..) => false,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Import(_, _, _) | Self::Export(_, _) => false,
|
Self::Import(..) | Self::Export(..) => false,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Self::Share(_) => false,
|
Self::Share(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is this statement _pure_?
|
/// Is this statement _pure_?
|
||||||
@ -532,20 +529,20 @@ impl Stmt {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_pure(&self) -> bool {
|
pub fn is_pure(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Noop(_) => true,
|
Self::Noop(..) => true,
|
||||||
Self::Expr(expr) => expr.is_pure(),
|
Self::Expr(expr) => expr.is_pure(),
|
||||||
Self::If(condition, x, _) => {
|
Self::If(condition, x, ..) => {
|
||||||
condition.is_pure()
|
condition.is_pure()
|
||||||
&& x.0.iter().all(Stmt::is_pure)
|
&& x.0.iter().all(Stmt::is_pure)
|
||||||
&& x.1.iter().all(Stmt::is_pure)
|
&& x.1.iter().all(Stmt::is_pure)
|
||||||
}
|
}
|
||||||
Self::Switch(expr, x, _) => {
|
Self::Switch(expr, x, ..) => {
|
||||||
expr.is_pure()
|
expr.is_pure()
|
||||||
&& x.cases.values().all(|block| {
|
&& x.cases.values().all(|block| {
|
||||||
block.condition.as_ref().map(Expr::is_pure).unwrap_or(true)
|
block.condition.as_ref().map(Expr::is_pure).unwrap_or(true)
|
||||||
&& block.statements.iter().all(Stmt::is_pure)
|
&& block.statements.iter().all(Stmt::is_pure)
|
||||||
})
|
})
|
||||||
&& x.ranges.iter().all(|(_, _, _, block)| {
|
&& x.ranges.iter().all(|(.., block)| {
|
||||||
block.condition.as_ref().map(Expr::is_pure).unwrap_or(true)
|
block.condition.as_ref().map(Expr::is_pure).unwrap_or(true)
|
||||||
&& block.statements.iter().all(Stmt::is_pure)
|
&& block.statements.iter().all(Stmt::is_pure)
|
||||||
})
|
})
|
||||||
@ -553,34 +550,34 @@ impl Stmt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Loops that exit can be pure because it can never be infinite.
|
// Loops that exit can be pure because it can never be infinite.
|
||||||
Self::While(Expr::BoolConstant(false, _), _, _) => true,
|
Self::While(Expr::BoolConstant(false, ..), ..) => true,
|
||||||
Self::Do(body, Expr::BoolConstant(x, _), options, _)
|
Self::Do(body, Expr::BoolConstant(x, ..), options, ..)
|
||||||
if *x == options.contains(AST_OPTION_NEGATED) =>
|
if *x == options.contains(AST_OPTION_NEGATED) =>
|
||||||
{
|
{
|
||||||
body.iter().all(Stmt::is_pure)
|
body.iter().all(Stmt::is_pure)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loops are never pure since they can be infinite - and that's a side effect.
|
// Loops are never pure since they can be infinite - and that's a side effect.
|
||||||
Self::While(_, _, _) | Self::Do(_, _, _, _) => false,
|
Self::While(..) | Self::Do(..) => false,
|
||||||
|
|
||||||
// For loops can be pure because if the iterable is pure, it is finite,
|
// For loops can be pure because if the iterable is pure, it is finite,
|
||||||
// so infinite loops can never occur.
|
// so infinite loops can never occur.
|
||||||
Self::For(iterable, x, _) => iterable.is_pure() && x.2.iter().all(Stmt::is_pure),
|
Self::For(iterable, x, ..) => iterable.is_pure() && x.2.iter().all(Stmt::is_pure),
|
||||||
|
|
||||||
Self::Var(_, _, _, _) | Self::Assignment(_, _) | Self::FnCall(_, _) => false,
|
Self::Var(..) | 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::BreakLoop(_, _) | Self::Return(_, _, _) => false,
|
Self::BreakLoop(..) | Self::Return(..) => false,
|
||||||
Self::TryCatch(x, _) => {
|
Self::TryCatch(x, ..) => {
|
||||||
x.try_block.iter().all(Stmt::is_pure) && x.catch_block.iter().all(Stmt::is_pure)
|
x.try_block.iter().all(Stmt::is_pure) && x.catch_block.iter().all(Stmt::is_pure)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Import(_, _, _) => false,
|
Self::Import(..) => false,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Export(_, _) => false,
|
Self::Export(..) => false,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Self::Share(_) => false,
|
Self::Share(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Does this statement's behavior depend on its containing block?
|
/// Does this statement's behavior depend on its containing block?
|
||||||
@ -594,16 +591,16 @@ impl Stmt {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_block_dependent(&self) -> bool {
|
pub fn is_block_dependent(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Var(_, _, _, _) => true,
|
Self::Var(..) => true,
|
||||||
|
|
||||||
Self::Expr(Expr::Stmt(s)) => s.iter().all(Stmt::is_block_dependent),
|
Self::Expr(Expr::Stmt(s)) => s.iter().all(Stmt::is_block_dependent),
|
||||||
|
|
||||||
Self::FnCall(x, _) | Self::Expr(Expr::FnCall(x, _)) => {
|
Self::FnCall(x, ..) | Self::Expr(Expr::FnCall(x, ..)) => {
|
||||||
!x.is_qualified() && x.name == KEYWORD_EVAL
|
!x.is_qualified() && x.name == KEYWORD_EVAL
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Import(_, _, _) | Self::Export(_, _) => true,
|
Self::Import(..) | Self::Export(..) => true,
|
||||||
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
@ -618,14 +615,14 @@ 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::Var(expr, _, _, _) => expr.is_pure(),
|
Self::Var(expr, _, ..) => expr.is_pure(),
|
||||||
|
|
||||||
Self::Expr(Expr::Stmt(s)) => s.iter().all(Stmt::is_internally_pure),
|
Self::Expr(Expr::Stmt(s)) => s.iter().all(Stmt::is_internally_pure),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Import(expr, _, _) => expr.is_pure(),
|
Self::Import(expr, ..) => expr.is_pure(),
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Export(_, _) => true,
|
Self::Export(..) => true,
|
||||||
|
|
||||||
_ => self.is_pure(),
|
_ => self.is_pure(),
|
||||||
}
|
}
|
||||||
@ -639,7 +636,7 @@ impl Stmt {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_control_flow_break(&self) -> bool {
|
pub const fn is_control_flow_break(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Return(_, _, _) | Self::BreakLoop(_, _) => true,
|
Self::Return(..) | Self::BreakLoop(..) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -658,12 +655,12 @@ impl Stmt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Self::Var(e, _, _, _) => {
|
Self::Var(e, _, ..) => {
|
||||||
if !e.walk(path, on_node) {
|
if !e.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::If(e, x, _) => {
|
Self::If(e, x, ..) => {
|
||||||
if !e.walk(path, on_node) {
|
if !e.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -678,7 +675,7 @@ impl Stmt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::Switch(e, x, _) => {
|
Self::Switch(e, x, ..) => {
|
||||||
if !e.walk(path, on_node) {
|
if !e.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -697,7 +694,7 @@ impl Stmt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (_, _, _, b) in &x.ranges {
|
for (.., b) in &x.ranges {
|
||||||
if !b
|
if !b
|
||||||
.condition
|
.condition
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@ -718,7 +715,7 @@ impl Stmt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::While(e, s, _) | Self::Do(s, e, _, _) => {
|
Self::While(e, s, ..) | Self::Do(s, e, ..) => {
|
||||||
if !e.walk(path, on_node) {
|
if !e.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -728,7 +725,7 @@ impl Stmt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::For(e, x, _) => {
|
Self::For(e, x, ..) => {
|
||||||
if !e.walk(path, on_node) {
|
if !e.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -738,7 +735,7 @@ impl Stmt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::Assignment(x, _) => {
|
Self::Assignment(x, ..) => {
|
||||||
if !x.1.lhs.walk(path, on_node) {
|
if !x.1.lhs.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -746,21 +743,21 @@ impl Stmt {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::FnCall(x, _) => {
|
Self::FnCall(x, ..) => {
|
||||||
for s in &x.args {
|
for s in &x.args {
|
||||||
if !s.walk(path, on_node) {
|
if !s.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::Block(x, _) => {
|
Self::Block(x, ..) => {
|
||||||
for s in x.iter() {
|
for s in x.iter() {
|
||||||
if !s.walk(path, on_node) {
|
if !s.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::TryCatch(x, _) => {
|
Self::TryCatch(x, ..) => {
|
||||||
for s in x.try_block.iter() {
|
for s in x.try_block.iter() {
|
||||||
if !s.walk(path, on_node) {
|
if !s.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
@ -778,7 +775,7 @@ impl Stmt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Import(e, _, _) => {
|
Self::Import(e, ..) => {
|
||||||
if !e.walk(path, on_node) {
|
if !e.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use rhai::debugger::{BreakPoint, DebuggerCommand, DebuggerEvent};
|
use rhai::debugger::{BreakPoint, DebuggerCommand, DebuggerEvent};
|
||||||
use rhai::{Dynamic, Engine, EvalAltResult, ImmutableString, Position, Scope};
|
use rhai::{Dynamic, Engine, EvalAltResult, ImmutableString, Position, Scope, INT};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
@ -271,7 +271,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
DebuggerEvent::FunctionExitWithValue(r) => {
|
DebuggerEvent::FunctionExitWithValue(r) => {
|
||||||
println!(
|
println!(
|
||||||
"! Return from function call '{}' => {}",
|
"! Return from function call '{}' => {:?}",
|
||||||
context
|
context
|
||||||
.global_runtime_state()
|
.global_runtime_state()
|
||||||
.debugger
|
.debugger
|
||||||
@ -553,7 +553,16 @@ fn main() {
|
|||||||
["throw"] => {
|
["throw"] => {
|
||||||
break Err(EvalAltResult::ErrorRuntime(Dynamic::UNIT, pos).into())
|
break Err(EvalAltResult::ErrorRuntime(Dynamic::UNIT, pos).into())
|
||||||
}
|
}
|
||||||
["throw", _msg, ..] => {
|
["throw", num] if num.trim().parse::<INT>().is_ok() => {
|
||||||
|
let value = num.trim().parse::<INT>().unwrap().into();
|
||||||
|
break Err(EvalAltResult::ErrorRuntime(value, pos).into());
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
["throw", num] if num.trim().parse::<rhai::FLOAT>().is_ok() => {
|
||||||
|
let value = num.trim().parse::<rhai::FLOAT>().unwrap().into();
|
||||||
|
break Err(EvalAltResult::ErrorRuntime(value, pos).into());
|
||||||
|
}
|
||||||
|
["throw", ..] => {
|
||||||
let msg = input.trim().splitn(2, ' ').skip(1).next().unwrap_or("");
|
let msg = input.trim().splitn(2, ' ').skip(1).next().unwrap_or("");
|
||||||
break Err(EvalAltResult::ErrorRuntime(msg.trim().into(), pos).into());
|
break Err(EvalAltResult::ErrorRuntime(msg.trim().into(), pos).into());
|
||||||
}
|
}
|
||||||
@ -584,7 +593,7 @@ fn main() {
|
|||||||
while let Err(err) = engine.run_ast_with_scope(&mut Scope::new(), &main_ast) {
|
while let Err(err) = engine.run_ast_with_scope(&mut Scope::new(), &main_ast) {
|
||||||
match *err {
|
match *err {
|
||||||
// Loop back to restart
|
// Loop back to restart
|
||||||
EvalAltResult::ErrorTerminated(_, _) => (),
|
EvalAltResult::ErrorTerminated(..) => (),
|
||||||
// Break evaluation
|
// Break evaluation
|
||||||
_ => {
|
_ => {
|
||||||
print_error(&script, *err);
|
print_error(&script, *err);
|
||||||
|
@ -62,8 +62,8 @@ fn print_help() {
|
|||||||
println!("ast => print the last AST (optimized)");
|
println!("ast => print the last AST (optimized)");
|
||||||
println!("astu => print the last raw, un-optimized AST");
|
println!("astu => print the last raw, un-optimized AST");
|
||||||
println!();
|
println!();
|
||||||
println!("press Shift-Enter to continue to the next line,");
|
println!("press Ctrl-Enter or end a line with `\\`");
|
||||||
println!(r"or end a line with '\' (e.g. when pasting code).");
|
println!("to continue to the next line.");
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,6 +204,7 @@ fn load_script_files(engine: &mut Engine) {
|
|||||||
|
|
||||||
// Setup the Rustyline editor.
|
// Setup the Rustyline editor.
|
||||||
fn setup_editor() -> Editor<()> {
|
fn setup_editor() -> Editor<()> {
|
||||||
|
//env_logger::init();
|
||||||
let config = Builder::new()
|
let config = Builder::new()
|
||||||
.tab_stop(4)
|
.tab_stop(4)
|
||||||
.indent_size(4)
|
.indent_size(4)
|
||||||
@ -225,23 +226,13 @@ fn setup_editor() -> Editor<()> {
|
|||||||
Event::KeySeq(smallvec![KeyEvent::ctrl('z')]),
|
Event::KeySeq(smallvec![KeyEvent::ctrl('z')]),
|
||||||
EventHandler::Simple(Cmd::Undo(1)),
|
EventHandler::Simple(Cmd::Undo(1)),
|
||||||
);
|
);
|
||||||
// Map Shift-Return to insert a new line - bypass need for `\` continuation
|
// Map Ctrl-Enter to insert a new line - bypass need for `\` continuation
|
||||||
rl.bind_sequence(
|
rl.bind_sequence(
|
||||||
Event::KeySeq(smallvec![KeyEvent(
|
Event::KeySeq(smallvec![KeyEvent(KeyCode::Char('J'), Modifiers::CTRL)]),
|
||||||
KeyCode::Char('m'),
|
|
||||||
Modifiers::CTRL_SHIFT
|
|
||||||
)]),
|
|
||||||
EventHandler::Simple(Cmd::Newline),
|
EventHandler::Simple(Cmd::Newline),
|
||||||
);
|
);
|
||||||
rl.bind_sequence(
|
rl.bind_sequence(
|
||||||
Event::KeySeq(smallvec![KeyEvent(
|
Event::KeySeq(smallvec![KeyEvent(KeyCode::Enter, Modifiers::CTRL)]),
|
||||||
KeyCode::Char('j'),
|
|
||||||
Modifiers::CTRL_SHIFT
|
|
||||||
)]),
|
|
||||||
EventHandler::Simple(Cmd::Newline),
|
|
||||||
);
|
|
||||||
rl.bind_sequence(
|
|
||||||
Event::KeySeq(smallvec![KeyEvent(KeyCode::Enter, Modifiers::SHIFT)]),
|
|
||||||
EventHandler::Simple(Cmd::Newline),
|
EventHandler::Simple(Cmd::Newline),
|
||||||
);
|
);
|
||||||
// Map Ctrl-Home and Ctrl-End for beginning/end of input
|
// Map Ctrl-Home and Ctrl-End for beginning/end of input
|
||||||
@ -489,7 +480,7 @@ fn main() {
|
|||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|&(_, h)| h.contains(text))
|
.find(|&(.., h)| h.contains(text))
|
||||||
{
|
{
|
||||||
replacement = Some(line.clone());
|
replacement = Some(line.clone());
|
||||||
replacement_index = history_offset + (rl.history().len() - 1 - n);
|
replacement_index = history_offset + (rl.history().len() - 1 - n);
|
||||||
@ -514,7 +505,7 @@ fn main() {
|
|||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|&(_, h)| h.trim_start().starts_with(prefix))
|
.find(|&(.., h)| h.trim_start().starts_with(prefix))
|
||||||
{
|
{
|
||||||
replacement = Some(line.clone());
|
replacement = Some(line.clone());
|
||||||
replacement_index = history_offset + (rl.history().len() - 1 - n);
|
replacement_index = history_offset + (rl.history().len() - 1 - n);
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
use rhai::{Engine, EvalAltResult, Position};
|
use rhai::{Engine, EvalAltResult, Position};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
|
||||||
use rhai::OptimizationLevel;
|
|
||||||
|
|
||||||
use std::{env, fs::File, io::Read, path::Path, process::exit};
|
use std::{env, fs::File, io::Read, path::Path, process::exit};
|
||||||
|
|
||||||
fn eprint_error(input: &str, mut err: EvalAltResult) {
|
fn eprint_error(input: &str, mut err: EvalAltResult) {
|
||||||
@ -53,7 +50,7 @@ fn main() {
|
|||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
engine.set_optimization_level(OptimizationLevel::Full);
|
engine.set_optimization_level(rhai::OptimizationLevel::Full);
|
||||||
|
|
||||||
let mut f = match File::open(&filename) {
|
let mut f = match File::open(&filename) {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
@ -8,7 +8,8 @@ use crate::packages::{Package, StandardPackage};
|
|||||||
use crate::tokenizer::Token;
|
use crate::tokenizer::Token;
|
||||||
use crate::types::dynamic::Union;
|
use crate::types::dynamic::Union;
|
||||||
use crate::{
|
use crate::{
|
||||||
Dynamic, Identifier, ImmutableString, Module, Position, RhaiResult, Shared, StaticVec,
|
Dynamic, Identifier, ImmutableString, Module, OptimizationLevel, Position, RhaiResult, Shared,
|
||||||
|
StaticVec,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -131,8 +132,7 @@ pub struct Engine {
|
|||||||
pub(crate) progress: Option<Box<crate::func::native::OnProgressCallback>>,
|
pub(crate) progress: Option<Box<crate::func::native::OnProgressCallback>>,
|
||||||
|
|
||||||
/// Optimize the [`AST`][crate::AST] after compilation.
|
/// Optimize the [`AST`][crate::AST] after compilation.
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
pub(crate) optimization_level: OptimizationLevel,
|
||||||
pub(crate) optimization_level: crate::OptimizationLevel,
|
|
||||||
|
|
||||||
/// Language options.
|
/// Language options.
|
||||||
pub(crate) options: crate::api::options::LanguageOptions,
|
pub(crate) options: crate::api::options::LanguageOptions,
|
||||||
@ -287,8 +287,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
progress: None,
|
progress: None,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
optimization_level: OptimizationLevel::default(),
|
||||||
optimization_level: crate::OptimizationLevel::default(),
|
|
||||||
|
|
||||||
options: crate::api::options::LanguageOptions::new(),
|
options: crate::api::options::LanguageOptions::new(),
|
||||||
|
|
||||||
@ -324,7 +323,7 @@ impl Engine {
|
|||||||
match result {
|
match result {
|
||||||
Ok(ref mut r) => {
|
Ok(ref mut r) => {
|
||||||
// Concentrate all empty strings into one instance to save memory
|
// Concentrate all empty strings into one instance to save memory
|
||||||
if let Dynamic(Union::Str(s, _, _)) = r {
|
if let Dynamic(Union::Str(s, ..)) = r {
|
||||||
if s.is_empty() {
|
if s.is_empty() {
|
||||||
if !s.ptr_eq(&self.empty_string) {
|
if !s.ptr_eq(&self.empty_string) {
|
||||||
*s = self.const_empty_string();
|
*s = self.const_empty_string();
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
use super::{EvalState, GlobalRuntimeState, Target};
|
use super::{EvalState, GlobalRuntimeState, Target};
|
||||||
use crate::ast::{Expr, OpAssignment};
|
use crate::ast::{Expr, OpAssignment};
|
||||||
use crate::types::dynamic::Union;
|
use crate::types::dynamic::Union;
|
||||||
use crate::{Dynamic, Engine, Module, Position, RhaiResult, RhaiResultOf, Scope, StaticVec, ERR};
|
use crate::{
|
||||||
|
Dynamic, Engine, Module, Position, RhaiError, RhaiResult, RhaiResultOf, Scope, StaticVec, ERR,
|
||||||
|
};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -25,9 +27,9 @@ impl From<&Expr> for ChainType {
|
|||||||
fn from(expr: &Expr) -> Self {
|
fn from(expr: &Expr) -> Self {
|
||||||
match expr {
|
match expr {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(_, _, _) => Self::Indexing,
|
Expr::Index(..) => Self::Indexing,
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Dot(_, _, _) => Self::Dotting,
|
Expr::Dot(..) => Self::Dotting,
|
||||||
expr => unreachable!("Expr::Index or Expr::Dot expected but gets {:?}", expr),
|
expr => unreachable!("Expr::Index or Expr::Dot expected but gets {:?}", expr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,7 +60,7 @@ impl ChainArgument {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn into_index_value(self) -> Option<Dynamic> {
|
pub fn into_index_value(self) -> Option<Dynamic> {
|
||||||
match self {
|
match self {
|
||||||
Self::IndexValue(value, _) => Some(value),
|
Self::IndexValue(value, ..) => Some(value),
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
@ -89,9 +91,9 @@ impl ChainArgument {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
ChainArgument::Property(pos) => *pos,
|
ChainArgument::Property(pos) => *pos,
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
ChainArgument::MethodCallArgs(_, pos) => *pos,
|
ChainArgument::MethodCallArgs(.., pos) => *pos,
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
ChainArgument::IndexValue(_, pos) => *pos,
|
ChainArgument::IndexValue(.., pos) => *pos,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Create n [`MethodCallArgs`][ChainArgument::MethodCallArgs].
|
/// Create n [`MethodCallArgs`][ChainArgument::MethodCallArgs].
|
||||||
@ -193,7 +195,7 @@ impl Engine {
|
|||||||
true, root_pos, level,
|
true, root_pos, level,
|
||||||
) {
|
) {
|
||||||
// Just ignore if there is no index setter
|
// Just ignore if there is no index setter
|
||||||
if !matches!(*err, ERR::ErrorFunctionNotFound(_, _)) {
|
if !matches!(*err, ERR::ErrorFunctionNotFound(..)) {
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,9 +227,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
// Can't index - try to call an index setter
|
// Can't index - try to call an index setter
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Err(err) if matches!(*err, ERR::ErrorIndexingType(_, _)) => {
|
Err(err) if matches!(*err, ERR::ErrorIndexingType(..)) => Some(new_val),
|
||||||
Some(new_val)
|
|
||||||
}
|
|
||||||
// Any other error
|
// Any other error
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
};
|
};
|
||||||
@ -283,11 +283,11 @@ impl Engine {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
// xxx.fn_name(...) = ???
|
// xxx.fn_name(...) = ???
|
||||||
Expr::FnCall(_, _) if new_val.is_some() => {
|
Expr::FnCall(..) if new_val.is_some() => {
|
||||||
unreachable!("method call cannot be assigned to")
|
unreachable!("method call cannot be assigned to")
|
||||||
}
|
}
|
||||||
// xxx.module::fn_name(...) - syntax error
|
// xxx.module::fn_name(...) - syntax error
|
||||||
Expr::FnCall(_, _) => {
|
Expr::FnCall(..) => {
|
||||||
unreachable!("function call in dot chain should not be namespace-qualified")
|
unreachable!("function call in dot chain should not be namespace-qualified")
|
||||||
}
|
}
|
||||||
// {xxx:map}.id op= ???
|
// {xxx:map}.id op= ???
|
||||||
@ -333,14 +333,14 @@ impl Engine {
|
|||||||
if op_info.is_some() {
|
if op_info.is_some() {
|
||||||
let hash = crate::ast::FnCallHashes::from_native(*hash_get);
|
let hash = crate::ast::FnCallHashes::from_native(*hash_get);
|
||||||
let args = &mut [target.as_mut()];
|
let args = &mut [target.as_mut()];
|
||||||
let (mut orig_val, _) = self
|
let (mut orig_val, ..) = self
|
||||||
.exec_fn_call(
|
.exec_fn_call(
|
||||||
None, global, state, lib, getter, hash, args, is_ref_mut, true,
|
None, global, state, lib, getter, hash, args, is_ref_mut, true,
|
||||||
*pos, level,
|
*pos, level,
|
||||||
)
|
)
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
// Try an indexer if property does not exist
|
// Try an indexer if property does not exist
|
||||||
ERR::ErrorDotExpr(_, _) => {
|
ERR::ErrorDotExpr(..) => {
|
||||||
let prop = name.into();
|
let prop = name.into();
|
||||||
self.get_indexed_mut(
|
self.get_indexed_mut(
|
||||||
global, state, lib, target, prop, *pos, false, true,
|
global, state, lib, target, prop, *pos, false, true,
|
||||||
@ -349,7 +349,7 @@ impl Engine {
|
|||||||
.map(|v| (v.take_or_clone(), false))
|
.map(|v| (v.take_or_clone(), false))
|
||||||
.map_err(
|
.map_err(
|
||||||
|idx_err| match *idx_err {
|
|idx_err| match *idx_err {
|
||||||
ERR::ErrorIndexingType(_, _) => err,
|
ERR::ErrorIndexingType(..) => err,
|
||||||
_ => idx_err,
|
_ => idx_err,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -381,7 +381,7 @@ impl Engine {
|
|||||||
)
|
)
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
// Try an indexer if property does not exist
|
// Try an indexer if property does not exist
|
||||||
ERR::ErrorDotExpr(_, _) => {
|
ERR::ErrorDotExpr(..) => {
|
||||||
let args = &mut [target, &mut name.into(), &mut new_val];
|
let args = &mut [target, &mut name.into(), &mut new_val];
|
||||||
let fn_name = crate::engine::FN_IDX_SET;
|
let fn_name = crate::engine::FN_IDX_SET;
|
||||||
let hash_set =
|
let hash_set =
|
||||||
@ -394,7 +394,7 @@ impl Engine {
|
|||||||
)
|
)
|
||||||
.map_err(
|
.map_err(
|
||||||
|idx_err| match *idx_err {
|
|idx_err| match *idx_err {
|
||||||
ERR::ErrorIndexingType(_, _) => err,
|
ERR::ErrorIndexingType(..) => err,
|
||||||
_ => idx_err,
|
_ => idx_err,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -417,7 +417,7 @@ impl Engine {
|
|||||||
.map_or_else(
|
.map_or_else(
|
||||||
|err| match *err {
|
|err| match *err {
|
||||||
// Try an indexer if property does not exist
|
// Try an indexer if property does not exist
|
||||||
ERR::ErrorDotExpr(_, _) => {
|
ERR::ErrorDotExpr(..) => {
|
||||||
let prop = name.into();
|
let prop = name.into();
|
||||||
self.get_indexed_mut(
|
self.get_indexed_mut(
|
||||||
global, state, lib, target, prop, *pos, false, true, level,
|
global, state, lib, target, prop, *pos, false, true, level,
|
||||||
@ -425,7 +425,7 @@ impl Engine {
|
|||||||
.map(|v| (v.take_or_clone(), false))
|
.map(|v| (v.take_or_clone(), false))
|
||||||
.map_err(|idx_err| {
|
.map_err(|idx_err| {
|
||||||
match *idx_err {
|
match *idx_err {
|
||||||
ERR::ErrorIndexingType(_, _) => err,
|
ERR::ErrorIndexingType(..) => err,
|
||||||
_ => idx_err,
|
_ => idx_err,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -433,7 +433,7 @@ impl Engine {
|
|||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
},
|
},
|
||||||
// Assume getters are always pure
|
// Assume getters are always pure
|
||||||
|(v, _)| Ok((v, false)),
|
|(v, ..)| Ok((v, false)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// {xxx:map}.sub_lhs[expr] | {xxx:map}.sub_lhs.expr
|
// {xxx:map}.sub_lhs[expr] | {xxx:map}.sub_lhs.expr
|
||||||
@ -475,7 +475,7 @@ impl Engine {
|
|||||||
result?.0.into()
|
result?.0.into()
|
||||||
}
|
}
|
||||||
// {xxx:map}.module::fn_name(...) - syntax error
|
// {xxx:map}.module::fn_name(...) - syntax error
|
||||||
Expr::FnCall(_, _) => unreachable!(
|
Expr::FnCall(..) => unreachable!(
|
||||||
"function call in dot chain should not be namespace-qualified"
|
"function call in dot chain should not be namespace-qualified"
|
||||||
),
|
),
|
||||||
// Others - syntax error
|
// Others - syntax error
|
||||||
@ -509,14 +509,14 @@ impl Engine {
|
|||||||
let args = &mut arg_values[..1];
|
let args = &mut arg_values[..1];
|
||||||
|
|
||||||
// Assume getters are always pure
|
// Assume getters are always pure
|
||||||
let (mut val, _) = self
|
let (mut val, ..) = self
|
||||||
.exec_fn_call(
|
.exec_fn_call(
|
||||||
None, global, state, lib, getter, hash_get, args,
|
None, global, state, lib, getter, hash_get, args,
|
||||||
is_ref_mut, true, pos, level,
|
is_ref_mut, true, pos, level,
|
||||||
)
|
)
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
// Try an indexer if property does not exist
|
// Try an indexer if property does not exist
|
||||||
ERR::ErrorDotExpr(_, _) => {
|
ERR::ErrorDotExpr(..) => {
|
||||||
let prop = name.into();
|
let prop = name.into();
|
||||||
self.get_indexed_mut(
|
self.get_indexed_mut(
|
||||||
global, state, lib, target, prop, pos, false, true,
|
global, state, lib, target, prop, pos, false, true,
|
||||||
@ -525,7 +525,7 @@ impl Engine {
|
|||||||
.map(|v| (v.take_or_clone(), false))
|
.map(|v| (v.take_or_clone(), false))
|
||||||
.map_err(
|
.map_err(
|
||||||
|idx_err| match *idx_err {
|
|idx_err| match *idx_err {
|
||||||
ERR::ErrorIndexingType(_, _) => err,
|
ERR::ErrorIndexingType(..) => err,
|
||||||
_ => idx_err,
|
_ => idx_err,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -565,7 +565,7 @@ impl Engine {
|
|||||||
.or_else(
|
.or_else(
|
||||||
|err| match *err {
|
|err| match *err {
|
||||||
// Try an indexer if property does not exist
|
// Try an indexer if property does not exist
|
||||||
ERR::ErrorDotExpr(_, _) => {
|
ERR::ErrorDotExpr(..) => {
|
||||||
let args =
|
let args =
|
||||||
&mut [target.as_mut(), &mut name.into(), val];
|
&mut [target.as_mut(), &mut name.into(), val];
|
||||||
let fn_name = crate::engine::FN_IDX_SET;
|
let fn_name = crate::engine::FN_IDX_SET;
|
||||||
@ -578,7 +578,7 @@ impl Engine {
|
|||||||
args, is_ref_mut, true, pos, level,
|
args, is_ref_mut, true, pos, level,
|
||||||
)
|
)
|
||||||
.or_else(|idx_err| match *idx_err {
|
.or_else(|idx_err| match *idx_err {
|
||||||
ERR::ErrorIndexingType(_, _) => {
|
ERR::ErrorIndexingType(..) => {
|
||||||
// If there is no setter, no need to feed it back because
|
// If there is no setter, no need to feed it back because
|
||||||
// the property is read-only
|
// the property is read-only
|
||||||
Ok((Dynamic::UNIT, false))
|
Ok((Dynamic::UNIT, false))
|
||||||
@ -621,7 +621,7 @@ impl Engine {
|
|||||||
.map_err(|err| err.fill_position(pos))
|
.map_err(|err| err.fill_position(pos))
|
||||||
}
|
}
|
||||||
// xxx.module::fn_name(...) - syntax error
|
// xxx.module::fn_name(...) - syntax error
|
||||||
Expr::FnCall(_, _) => unreachable!(
|
Expr::FnCall(..) => unreachable!(
|
||||||
"function call in dot chain should not be namespace-qualified"
|
"function call in dot chain should not be namespace-qualified"
|
||||||
),
|
),
|
||||||
// Others - syntax error
|
// Others - syntax error
|
||||||
@ -665,14 +665,14 @@ impl Engine {
|
|||||||
|
|
||||||
match lhs {
|
match lhs {
|
||||||
// id.??? or id[???]
|
// id.??? or id[???]
|
||||||
Expr::Variable(_, var_pos, x) => {
|
Expr::Variable(.., var_pos, x) => {
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
self.run_debugger(scope, global, state, lib, this_ptr, lhs, level)?;
|
self.run_debugger(scope, global, state, lib, this_ptr, lhs, level)?;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.inc_operations(&mut global.num_operations, *var_pos)?;
|
self.inc_operations(&mut global.num_operations, *var_pos)?;
|
||||||
|
|
||||||
let (mut target, _) =
|
let (mut target, ..) =
|
||||||
self.search_namespace(scope, global, state, lib, this_ptr, lhs, level)?;
|
self.search_namespace(scope, global, state, lib, this_ptr, lhs, level)?;
|
||||||
|
|
||||||
let obj_ptr = &mut target;
|
let obj_ptr = &mut target;
|
||||||
@ -682,7 +682,7 @@ impl Engine {
|
|||||||
global, state, lib, &mut None, obj_ptr, root, expr, rhs, term, idx_values,
|
global, state, lib, &mut None, obj_ptr, root, expr, rhs, term, idx_values,
|
||||||
chain_type, level, new_val,
|
chain_type, level, new_val,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| v)
|
.map(|(v, ..)| v)
|
||||||
.map_err(|err| err.fill_position(op_pos))
|
.map_err(|err| err.fill_position(op_pos))
|
||||||
}
|
}
|
||||||
// {expr}.??? = ??? or {expr}[???] = ???
|
// {expr}.??? = ??? or {expr}[???] = ???
|
||||||
@ -696,7 +696,7 @@ impl Engine {
|
|||||||
global, state, lib, this_ptr, obj_ptr, root, expr, rhs, term, idx_values,
|
global, state, lib, this_ptr, obj_ptr, root, expr, rhs, term, idx_values,
|
||||||
chain_type, level, new_val,
|
chain_type, level, new_val,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| if is_assignment { Dynamic::UNIT } else { v })
|
.map(|(v, ..)| if is_assignment { Dynamic::UNIT } else { v })
|
||||||
.map_err(|err| err.fill_position(op_pos))
|
.map_err(|err| err.fill_position(op_pos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -726,14 +726,16 @@ impl Engine {
|
|||||||
|
|
||||||
match expr {
|
match expr {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::FnCall(x, _) if _parent_chain_type == ChainType::Dotting && !x.is_qualified() => {
|
Expr::FnCall(x, ..)
|
||||||
|
if _parent_chain_type == ChainType::Dotting && !x.is_qualified() =>
|
||||||
|
{
|
||||||
let crate::ast::FnCallExpr {
|
let crate::ast::FnCallExpr {
|
||||||
args, constants, ..
|
args, constants, ..
|
||||||
} = x.as_ref();
|
} = x.as_ref();
|
||||||
|
|
||||||
let (values, pos) = args.iter().try_fold(
|
let (values, pos) = args.iter().try_fold(
|
||||||
(crate::FnArgsVec::with_capacity(args.len()), Position::NONE),
|
(crate::FnArgsVec::with_capacity(args.len()), Position::NONE),
|
||||||
|(mut values, mut pos), expr| -> RhaiResultOf<_> {
|
|(mut values, mut pos), expr| {
|
||||||
let (value, arg_pos) = self.get_arg_value(
|
let (value, arg_pos) = self.get_arg_value(
|
||||||
scope, global, state, lib, this_ptr, expr, constants, level,
|
scope, global, state, lib, this_ptr, expr, constants, level,
|
||||||
)?;
|
)?;
|
||||||
@ -741,36 +743,36 @@ impl Engine {
|
|||||||
pos = arg_pos;
|
pos = arg_pos;
|
||||||
}
|
}
|
||||||
values.push(value.flatten());
|
values.push(value.flatten());
|
||||||
Ok((values, pos))
|
Ok::<_, RhaiError>((values, pos))
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
idx_values.push(super::ChainArgument::from_fn_call_args(values, pos));
|
idx_values.push(super::ChainArgument::from_fn_call_args(values, pos));
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::FnCall(_, _) if _parent_chain_type == ChainType::Dotting => {
|
Expr::FnCall(..) if _parent_chain_type == ChainType::Dotting => {
|
||||||
unreachable!("function call in dot chain should not be namespace-qualified")
|
unreachable!("function call in dot chain should not be namespace-qualified")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Property(_, pos) if _parent_chain_type == ChainType::Dotting => {
|
Expr::Property(.., pos) if _parent_chain_type == ChainType::Dotting => {
|
||||||
idx_values.push(super::ChainArgument::Property(*pos))
|
idx_values.push(super::ChainArgument::Property(*pos))
|
||||||
}
|
}
|
||||||
Expr::Property(_, _) => unreachable!("unexpected Expr::Property for indexing"),
|
Expr::Property(..) => unreachable!("unexpected Expr::Property for indexing"),
|
||||||
|
|
||||||
Expr::Index(x, term, _) | Expr::Dot(x, term, _) if !terminate_chaining => {
|
Expr::Index(x, term, ..) | Expr::Dot(x, term, ..) if !terminate_chaining => {
|
||||||
let crate::ast::BinaryExpr { lhs, rhs, .. } = x.as_ref();
|
let crate::ast::BinaryExpr { lhs, rhs, .. } = x.as_ref();
|
||||||
|
|
||||||
// Evaluate in left-to-right order
|
// Evaluate in left-to-right order
|
||||||
let lhs_arg_val = match lhs {
|
let lhs_arg_val = match lhs {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Property(_, pos) if _parent_chain_type == ChainType::Dotting => {
|
Expr::Property(.., pos) if _parent_chain_type == ChainType::Dotting => {
|
||||||
super::ChainArgument::Property(*pos)
|
super::ChainArgument::Property(*pos)
|
||||||
}
|
}
|
||||||
Expr::Property(_, _) => unreachable!("unexpected Expr::Property for indexing"),
|
Expr::Property(..) => unreachable!("unexpected Expr::Property for indexing"),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::FnCall(x, _)
|
Expr::FnCall(x, ..)
|
||||||
if _parent_chain_type == ChainType::Dotting && !x.is_qualified() =>
|
if _parent_chain_type == ChainType::Dotting && !x.is_qualified() =>
|
||||||
{
|
{
|
||||||
let crate::ast::FnCallExpr {
|
let crate::ast::FnCallExpr {
|
||||||
@ -779,7 +781,7 @@ impl Engine {
|
|||||||
|
|
||||||
let (values, pos) = args.iter().try_fold(
|
let (values, pos) = args.iter().try_fold(
|
||||||
(crate::FnArgsVec::with_capacity(args.len()), Position::NONE),
|
(crate::FnArgsVec::with_capacity(args.len()), Position::NONE),
|
||||||
|(mut values, mut pos), expr| -> RhaiResultOf<_> {
|
|(mut values, mut pos), expr| {
|
||||||
let (value, arg_pos) = self.get_arg_value(
|
let (value, arg_pos) = self.get_arg_value(
|
||||||
scope, global, state, lib, this_ptr, expr, constants, level,
|
scope, global, state, lib, this_ptr, expr, constants, level,
|
||||||
)?;
|
)?;
|
||||||
@ -787,13 +789,13 @@ impl Engine {
|
|||||||
pos = arg_pos
|
pos = arg_pos
|
||||||
}
|
}
|
||||||
values.push(value.flatten());
|
values.push(value.flatten());
|
||||||
Ok((values, pos))
|
Ok::<_, RhaiError>((values, pos))
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
super::ChainArgument::from_fn_call_args(values, pos)
|
super::ChainArgument::from_fn_call_args(values, pos)
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::FnCall(_, _) if _parent_chain_type == ChainType::Dotting => {
|
Expr::FnCall(..) if _parent_chain_type == ChainType::Dotting => {
|
||||||
unreachable!("function call in dot chain should not be namespace-qualified")
|
unreachable!("function call in dot chain should not be namespace-qualified")
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
@ -862,7 +864,7 @@ impl Engine {
|
|||||||
|
|
||||||
match target {
|
match target {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Dynamic(Union::Array(arr, _, _)) => {
|
Dynamic(Union::Array(arr, ..)) => {
|
||||||
// val_array[idx]
|
// val_array[idx]
|
||||||
let index = idx
|
let index = idx
|
||||||
.as_int()
|
.as_int()
|
||||||
@ -876,7 +878,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Dynamic(Union::Blob(arr, _, _)) => {
|
Dynamic(Union::Blob(arr, ..)) => {
|
||||||
// val_blob[idx]
|
// val_blob[idx]
|
||||||
let index = idx
|
let index = idx
|
||||||
.as_int()
|
.as_int()
|
||||||
@ -896,7 +898,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Dynamic(Union::Map(map, _, _)) => {
|
Dynamic(Union::Map(map, ..)) => {
|
||||||
// val_map[idx]
|
// val_map[idx]
|
||||||
let index = idx.read_lock::<crate::ImmutableString>().ok_or_else(|| {
|
let index = idx.read_lock::<crate::ImmutableString>().ok_or_else(|| {
|
||||||
self.make_type_mismatch_err::<crate::ImmutableString>(idx.type_name(), pos)
|
self.make_type_mismatch_err::<crate::ImmutableString>(idx.type_name(), pos)
|
||||||
@ -913,7 +915,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Dynamic(Union::Int(value, _, _))
|
Dynamic(Union::Int(value, ..))
|
||||||
if idx.is::<crate::ExclusiveRange>() || idx.is::<crate::InclusiveRange>() =>
|
if idx.is::<crate::ExclusiveRange>() || idx.is::<crate::InclusiveRange>() =>
|
||||||
{
|
{
|
||||||
// val_int[range]
|
// val_int[range]
|
||||||
@ -984,7 +986,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Dynamic(Union::Int(value, _, _)) => {
|
Dynamic(Union::Int(value, ..)) => {
|
||||||
// val_int[idx]
|
// val_int[idx]
|
||||||
let index = idx
|
let index = idx
|
||||||
.as_int()
|
.as_int()
|
||||||
@ -1006,7 +1008,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Dynamic(Union::Str(s, _, _)) => {
|
Dynamic(Union::Str(s, ..)) => {
|
||||||
// val_string[idx]
|
// val_string[idx]
|
||||||
let index = idx
|
let index = idx
|
||||||
.as_int()
|
.as_int()
|
||||||
@ -1052,7 +1054,7 @@ impl Engine {
|
|||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
None, global, state, lib, fn_name, hash_get, args, true, true, pos, level,
|
None, global, state, lib, fn_name, hash_get, args, true, true, pos, level,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| v.into())
|
.map(|(v, ..)| v.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => Err(ERR::ErrorIndexingType(
|
_ => Err(ERR::ErrorIndexingType(
|
||||||
|
@ -10,7 +10,7 @@ use std::prelude::v1::*;
|
|||||||
impl Engine {
|
impl Engine {
|
||||||
/// Recursively calculate the sizes of a value.
|
/// Recursively calculate the sizes of a value.
|
||||||
///
|
///
|
||||||
/// Sizes returned are `(`[`Array`][crate::Array], [`Map`][crate::Map] and `String)`.
|
/// Sizes returned are `(` [`Array`][crate::Array], [`Map`][crate::Map] and [`String`] `)`.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
@ -21,51 +21,51 @@ impl Engine {
|
|||||||
|
|
||||||
match value.0 {
|
match value.0 {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(ref arr, _, _) => {
|
Union::Array(ref arr, ..) => {
|
||||||
arr.iter()
|
arr.iter()
|
||||||
.fold((0, 0, 0), |(arrays, maps, strings), value| match value.0 {
|
.fold((0, 0, 0), |(arrays, maps, strings), value| match value.0 {
|
||||||
Union::Array(_, _, _) => {
|
Union::Array(..) => {
|
||||||
let (a, m, s) = Self::calc_data_sizes(value, false);
|
let (a, m, s) = Self::calc_data_sizes(value, false);
|
||||||
(arrays + a + 1, maps + m, strings + s)
|
(arrays + a + 1, maps + m, strings + s)
|
||||||
}
|
}
|
||||||
Union::Blob(ref a, _, _) => (arrays + 1 + a.len(), maps, strings),
|
Union::Blob(ref a, ..) => (arrays + 1 + a.len(), maps, strings),
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(_, _, _) => {
|
Union::Map(..) => {
|
||||||
let (a, m, s) = Self::calc_data_sizes(value, false);
|
let (a, m, s) = Self::calc_data_sizes(value, false);
|
||||||
(arrays + a + 1, maps + m, strings + s)
|
(arrays + a + 1, maps + m, strings + s)
|
||||||
}
|
}
|
||||||
Union::Str(ref s, _, _) => (arrays + 1, maps, strings + s.len()),
|
Union::Str(ref s, ..) => (arrays + 1, maps, strings + s.len()),
|
||||||
_ => (arrays + 1, maps, strings),
|
_ => (arrays + 1, maps, strings),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Blob(ref arr, _, _) => (arr.len(), 0, 0),
|
Union::Blob(ref arr, ..) => (arr.len(), 0, 0),
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(ref map, _, _) => {
|
Union::Map(ref map, ..) => {
|
||||||
map.values()
|
map.values()
|
||||||
.fold((0, 0, 0), |(arrays, maps, strings), value| match value.0 {
|
.fold((0, 0, 0), |(arrays, maps, strings), value| match value.0 {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(_, _, _) => {
|
Union::Array(..) => {
|
||||||
let (a, m, s) = Self::calc_data_sizes(value, false);
|
let (a, m, s) = Self::calc_data_sizes(value, false);
|
||||||
(arrays + a, maps + m + 1, strings + s)
|
(arrays + a, maps + m + 1, strings + s)
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Blob(ref a, _, _) => (arrays + a.len(), maps, strings),
|
Union::Blob(ref a, ..) => (arrays + a.len(), maps, strings),
|
||||||
Union::Map(_, _, _) => {
|
Union::Map(..) => {
|
||||||
let (a, m, s) = Self::calc_data_sizes(value, false);
|
let (a, m, s) = Self::calc_data_sizes(value, false);
|
||||||
(arrays + a, maps + m + 1, strings + s)
|
(arrays + a, maps + m + 1, strings + s)
|
||||||
}
|
}
|
||||||
Union::Str(ref s, _, _) => (arrays, maps + 1, strings + s.len()),
|
Union::Str(ref s, ..) => (arrays, maps + 1, strings + s.len()),
|
||||||
_ => (arrays, maps + 1, strings),
|
_ => (arrays, maps + 1, strings),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Union::Str(ref s, _, _) => (0, 0, s.len()),
|
Union::Str(ref s, ..) => (0, 0, s.len()),
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(_, _, _) if _top => {
|
Union::Shared(..) if _top => {
|
||||||
Self::calc_data_sizes(&*value.read_lock::<Dynamic>().unwrap(), true)
|
Self::calc_data_sizes(&*value.read_lock::<Dynamic>().unwrap(), true)
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(_, _, _) => {
|
Union::Shared(..) => {
|
||||||
unreachable!("shared values discovered within data: {}", value)
|
unreachable!("shared values discovered within data: {}", value)
|
||||||
}
|
}
|
||||||
_ => (0, 0, 0),
|
_ => (0, 0, 0),
|
||||||
|
@ -271,7 +271,7 @@ impl Debugger {
|
|||||||
} else {
|
} else {
|
||||||
DebuggerStatus::CONTINUE
|
DebuggerStatus::CONTINUE
|
||||||
},
|
},
|
||||||
state: if let Some((ref init, _)) = engine.debugger {
|
state: if let Some((ref init, ..)) = engine.debugger {
|
||||||
init()
|
init()
|
||||||
} else {
|
} else {
|
||||||
Dynamic::UNIT
|
Dynamic::UNIT
|
||||||
@ -348,8 +348,8 @@ impl Debugger {
|
|||||||
self.break_points()
|
self.break_points()
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|&(_, bp)| bp.is_enabled())
|
.filter(|&(.., bp)| bp.is_enabled())
|
||||||
.find(|&(_, bp)| match bp {
|
.find(|&(.., bp)| match bp {
|
||||||
#[cfg(not(feature = "no_position"))]
|
#[cfg(not(feature = "no_position"))]
|
||||||
BreakPoint::AtPosition { pos, .. } if pos.is_none() => false,
|
BreakPoint::AtPosition { pos, .. } if pos.is_none() => false,
|
||||||
#[cfg(not(feature = "no_position"))]
|
#[cfg(not(feature = "no_position"))]
|
||||||
@ -361,26 +361,26 @@ impl Debugger {
|
|||||||
node.position() == *pos && _src == source
|
node.position() == *pos && _src == source
|
||||||
}
|
}
|
||||||
BreakPoint::AtFunctionName { name, .. } => match node {
|
BreakPoint::AtFunctionName { name, .. } => match node {
|
||||||
ASTNode::Expr(Expr::FnCall(x, _))
|
ASTNode::Expr(Expr::FnCall(x, ..))
|
||||||
| ASTNode::Stmt(Stmt::FnCall(x, _))
|
| ASTNode::Stmt(Stmt::FnCall(x, ..))
|
||||||
| ASTNode::Stmt(Stmt::Expr(Expr::FnCall(x, _))) => x.name == *name,
|
| ASTNode::Stmt(Stmt::Expr(Expr::FnCall(x, ..))) => x.name == *name,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
BreakPoint::AtFunctionCall { name, args, .. } => match node {
|
BreakPoint::AtFunctionCall { name, args, .. } => match node {
|
||||||
ASTNode::Expr(Expr::FnCall(x, _))
|
ASTNode::Expr(Expr::FnCall(x, ..))
|
||||||
| ASTNode::Stmt(Stmt::FnCall(x, _))
|
| ASTNode::Stmt(Stmt::FnCall(x, ..))
|
||||||
| ASTNode::Stmt(Stmt::Expr(Expr::FnCall(x, _))) => {
|
| ASTNode::Stmt(Stmt::Expr(Expr::FnCall(x, ..))) => {
|
||||||
x.args.len() == *args && x.name == *name
|
x.args.len() == *args && x.name == *name
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
BreakPoint::AtProperty { name, .. } => match node {
|
BreakPoint::AtProperty { name, .. } => match node {
|
||||||
ASTNode::Expr(Expr::Property(x, _)) => x.2 == *name,
|
ASTNode::Expr(Expr::Property(x, ..)) => x.2 == *name,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.map(|(i, _)| i)
|
.map(|(i, ..)| i)
|
||||||
}
|
}
|
||||||
/// Get a slice of all [`BreakPoint`]'s.
|
/// Get a slice of all [`BreakPoint`]'s.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -465,16 +465,16 @@ impl Engine {
|
|||||||
|
|
||||||
// Skip transitive nodes
|
// Skip transitive nodes
|
||||||
match node {
|
match node {
|
||||||
ASTNode::Expr(Expr::Stmt(_)) | ASTNode::Stmt(Stmt::Expr(_)) => return Ok(None),
|
ASTNode::Expr(Expr::Stmt(..)) | ASTNode::Stmt(Stmt::Expr(..)) => return Ok(None),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let stop = match global.debugger.status {
|
let stop = match global.debugger.status {
|
||||||
DebuggerStatus::Next(false, false) => false,
|
DebuggerStatus::Next(false, false) => false,
|
||||||
DebuggerStatus::Next(true, false) => matches!(node, ASTNode::Stmt(_)),
|
DebuggerStatus::Next(true, false) => matches!(node, ASTNode::Stmt(..)),
|
||||||
DebuggerStatus::Next(false, true) => matches!(node, ASTNode::Expr(_)),
|
DebuggerStatus::Next(false, true) => matches!(node, ASTNode::Expr(..)),
|
||||||
DebuggerStatus::Next(true, true) => true,
|
DebuggerStatus::Next(true, true) => true,
|
||||||
DebuggerStatus::FunctionExit(_) => false,
|
DebuggerStatus::FunctionExit(..) => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let event = if stop {
|
let event = if stop {
|
||||||
@ -525,7 +525,7 @@ impl Engine {
|
|||||||
level,
|
level,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some((_, ref on_debugger)) = self.debugger {
|
if let Some((.., ref on_debugger)) = self.debugger {
|
||||||
let command = on_debugger(&mut context, event, node, source, node.position())?;
|
let command = on_debugger(&mut context, event, node, source, node.position())?;
|
||||||
|
|
||||||
match command {
|
match command {
|
||||||
@ -548,9 +548,9 @@ impl Engine {
|
|||||||
DebuggerCommand::FunctionExit => {
|
DebuggerCommand::FunctionExit => {
|
||||||
// Bump a level if it is a function call
|
// Bump a level if it is a function call
|
||||||
let level = match node {
|
let level = match node {
|
||||||
ASTNode::Expr(Expr::FnCall(_, _))
|
ASTNode::Expr(Expr::FnCall(..))
|
||||||
| ASTNode::Stmt(Stmt::FnCall(_, _))
|
| ASTNode::Stmt(Stmt::FnCall(..))
|
||||||
| ASTNode::Stmt(Stmt::Expr(Expr::FnCall(_, _))) => context.call_level() + 1,
|
| ASTNode::Stmt(Stmt::Expr(Expr::FnCall(..))) => context.call_level() + 1,
|
||||||
_ => context.call_level(),
|
_ => context.call_level(),
|
||||||
};
|
};
|
||||||
global.debugger.status = DebuggerStatus::FunctionExit(level);
|
global.debugger.status = DebuggerStatus::FunctionExit(level);
|
||||||
|
@ -53,7 +53,7 @@ impl Engine {
|
|||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResultOf<(Target<'s>, Position)> {
|
) -> RhaiResultOf<(Target<'s>, Position)> {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Variable(Some(_), _, _) => {
|
Expr::Variable(Some(_), ..) => {
|
||||||
self.search_scope_only(scope, global, state, lib, this_ptr, expr, level)
|
self.search_scope_only(scope, global, state, lib, this_ptr, expr, level)
|
||||||
}
|
}
|
||||||
Expr::Variable(None, _var_pos, v) => match v.as_ref() {
|
Expr::Variable(None, _var_pos, v) => match v.as_ref() {
|
||||||
@ -80,7 +80,7 @@ impl Engine {
|
|||||||
Ok((target.into(), *_var_pos))
|
Ok((target.into(), *_var_pos))
|
||||||
}
|
}
|
||||||
Err(err) => Err(match *err {
|
Err(err) => Err(match *err {
|
||||||
ERR::ErrorVariableNotFound(_, _) => ERR::ErrorVariableNotFound(
|
ERR::ErrorVariableNotFound(..) => ERR::ErrorVariableNotFound(
|
||||||
format!(
|
format!(
|
||||||
"{}{}{}",
|
"{}{}{}",
|
||||||
namespace,
|
namespace,
|
||||||
@ -155,7 +155,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ if state.always_search_scope => (0, expr.start_position()),
|
_ if state.always_search_scope => (0, expr.start_position()),
|
||||||
Expr::Variable(Some(i), pos, _) => (i.get() as usize, *pos),
|
Expr::Variable(Some(i), pos, ..) => (i.get() as usize, *pos),
|
||||||
Expr::Variable(None, pos, v) => (v.0.map(NonZeroUsize::get).unwrap_or(0), *pos),
|
Expr::Variable(None, pos, v) => (v.0.map(NonZeroUsize::get).unwrap_or(0), *pos),
|
||||||
_ => unreachable!("Expr::Variable expected but gets {:?}", expr),
|
_ => unreachable!("Expr::Variable expected but gets {:?}", expr),
|
||||||
};
|
};
|
||||||
@ -270,7 +270,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Function calls should account for a relatively larger portion of expressions because
|
// Function calls should account for a relatively larger portion of expressions because
|
||||||
// binary operators are also function calls.
|
// binary operators are also function calls.
|
||||||
if let Expr::FnCall(x, pos) = expr {
|
if let Expr::FnCall(x, ..) = expr {
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
let reset_debugger =
|
let reset_debugger =
|
||||||
self.run_debugger_with_reset(scope, global, state, lib, this_ptr, expr, level)?;
|
self.run_debugger_with_reset(scope, global, state, lib, this_ptr, expr, level)?;
|
||||||
@ -279,7 +279,7 @@ impl Engine {
|
|||||||
self.inc_operations(&mut global.num_operations, expr.position())?;
|
self.inc_operations(&mut global.num_operations, expr.position())?;
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
self.eval_fn_call_expr(scope, global, state, lib, this_ptr, x, *pos, level);
|
self.eval_fn_call_expr(scope, global, state, lib, this_ptr, x, x.pos, level);
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
global.debugger.reset_status(reset_debugger);
|
global.debugger.reset_status(reset_debugger);
|
||||||
@ -304,7 +304,7 @@ impl Engine {
|
|||||||
.ok_or_else(|| ERR::ErrorUnboundThis(*var_pos).into())
|
.ok_or_else(|| ERR::ErrorUnboundThis(*var_pos).into())
|
||||||
} else {
|
} else {
|
||||||
self.search_namespace(scope, global, state, lib, this_ptr, expr, level)
|
self.search_namespace(scope, global, state, lib, this_ptr, expr, level)
|
||||||
.map(|(val, _)| val.take_or_clone())
|
.map(|(val, ..)| val.take_or_clone())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,14 +317,14 @@ impl Engine {
|
|||||||
|
|
||||||
let result = match expr {
|
let result = match expr {
|
||||||
// Constants
|
// Constants
|
||||||
Expr::DynamicConstant(x, _) => Ok(x.as_ref().clone()),
|
Expr::DynamicConstant(x, ..) => Ok(x.as_ref().clone()),
|
||||||
Expr::IntegerConstant(x, _) => Ok((*x).into()),
|
Expr::IntegerConstant(x, ..) => Ok((*x).into()),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Expr::FloatConstant(x, _) => Ok((*x).into()),
|
Expr::FloatConstant(x, ..) => Ok((*x).into()),
|
||||||
Expr::StringConstant(x, _) => Ok(x.clone().into()),
|
Expr::StringConstant(x, ..) => Ok(x.clone().into()),
|
||||||
Expr::CharConstant(x, _) => Ok((*x).into()),
|
Expr::CharConstant(x, ..) => Ok((*x).into()),
|
||||||
Expr::BoolConstant(x, _) => Ok((*x).into()),
|
Expr::BoolConstant(x, ..) => Ok((*x).into()),
|
||||||
Expr::Unit(_) => Ok(Dynamic::UNIT),
|
Expr::Unit(..) => Ok(Dynamic::UNIT),
|
||||||
|
|
||||||
// `... ${...} ...`
|
// `... ${...} ...`
|
||||||
Expr::InterpolatedString(x, pos) => {
|
Expr::InterpolatedString(x, pos) => {
|
||||||
@ -364,7 +364,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Array(x, _) => {
|
Expr::Array(x, ..) => {
|
||||||
let mut arr = crate::Array::with_capacity(x.len());
|
let mut arr = crate::Array::with_capacity(x.len());
|
||||||
let mut result = Ok(Dynamic::UNIT);
|
let mut result = Ok(Dynamic::UNIT);
|
||||||
|
|
||||||
@ -402,7 +402,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Map(x, _) => {
|
Expr::Map(x, ..) => {
|
||||||
let mut map = x.1.clone();
|
let mut map = x.1.clone();
|
||||||
let mut result = Ok(Dynamic::UNIT);
|
let mut result = Ok(Dynamic::UNIT);
|
||||||
|
|
||||||
@ -440,7 +440,7 @@ impl Engine {
|
|||||||
result.map(|_| map.into())
|
result.map(|_| map.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::And(x, _) => {
|
Expr::And(x, ..) => {
|
||||||
let lhs = self
|
let lhs = self
|
||||||
.eval_expr(scope, global, state, lib, this_ptr, &x.lhs, level)
|
.eval_expr(scope, global, state, lib, this_ptr, &x.lhs, level)
|
||||||
.and_then(|v| {
|
.and_then(|v| {
|
||||||
@ -463,7 +463,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Or(x, _) => {
|
Expr::Or(x, ..) => {
|
||||||
let lhs = self
|
let lhs = self
|
||||||
.eval_expr(scope, global, state, lib, this_ptr, &x.lhs, level)
|
.eval_expr(scope, global, state, lib, this_ptr, &x.lhs, level)
|
||||||
.and_then(|v| {
|
.and_then(|v| {
|
||||||
@ -519,12 +519,12 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(_, _, _) => {
|
Expr::Index(..) => {
|
||||||
self.eval_dot_index_chain(scope, global, state, lib, this_ptr, expr, level, None)
|
self.eval_dot_index_chain(scope, global, state, lib, this_ptr, expr, level, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Dot(_, _, _) => {
|
Expr::Dot(..) => {
|
||||||
self.eval_dot_index_chain(scope, global, state, lib, this_ptr, expr, level, None)
|
self.eval_dot_index_chain(scope, global, state, lib, this_ptr, expr, level, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,13 +67,13 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
if matches!(stmt, Stmt::Import(_, _, _)) {
|
if matches!(stmt, Stmt::Import(..)) {
|
||||||
// Get the extra modules - see if any functions are marked global.
|
// Get the extra modules - see if any functions are marked global.
|
||||||
// Without global functions, the extra modules never affect function resolution.
|
// Without global functions, the extra modules never affect function resolution.
|
||||||
if global
|
if global
|
||||||
.scan_imports_raw()
|
.scan_imports_raw()
|
||||||
.skip(imports_len)
|
.skip(imports_len)
|
||||||
.any(|(_, m)| m.contains_indexed_global_functions())
|
.any(|(.., m)| m.contains_indexed_global_functions())
|
||||||
{
|
{
|
||||||
if state.fn_resolution_caches_len() > orig_fn_resolution_caches_len {
|
if state.fn_resolution_caches_len() > orig_fn_resolution_caches_len {
|
||||||
// When new module is imported with global functions and there is already
|
// When new module is imported with global functions and there is already
|
||||||
@ -162,10 +162,10 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.check_data_size(&args[0], root.1)?;
|
self.check_data_size(&args[0], root.1)?;
|
||||||
}
|
}
|
||||||
Err(err) if matches!(*err, ERR::ErrorFunctionNotFound(ref f, _) if f.starts_with(op_assign)) =>
|
Err(err) if matches!(*err, ERR::ErrorFunctionNotFound(ref f, ..) if f.starts_with(op_assign)) =>
|
||||||
{
|
{
|
||||||
// Expand to `var = var op rhs`
|
// Expand to `var = var op rhs`
|
||||||
let (value, _) = self.call_native_fn(
|
let (value, ..) = self.call_native_fn(
|
||||||
global, state, lib, op, hash_op, args, true, false, op_pos, level,
|
global, state, lib, op, hash_op, args, true, false, op_pos, level,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -211,12 +211,12 @@ impl Engine {
|
|||||||
// Popular branches are lifted out of the `match` statement into their own branches.
|
// Popular branches are lifted out of the `match` statement into their own branches.
|
||||||
|
|
||||||
// Function calls should account for a relatively larger portion of statements.
|
// Function calls should account for a relatively larger portion of statements.
|
||||||
if let Stmt::FnCall(x, pos) = stmt {
|
if let Stmt::FnCall(x, ..) = stmt {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.inc_operations(&mut global.num_operations, stmt.position())?;
|
self.inc_operations(&mut global.num_operations, stmt.position())?;
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
self.eval_fn_call_expr(scope, global, state, lib, this_ptr, x, *pos, level);
|
self.eval_fn_call_expr(scope, global, state, lib, this_ptr, x, x.pos, level);
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
global.debugger.reset_status(reset_debugger);
|
global.debugger.reset_status(reset_debugger);
|
||||||
@ -288,19 +288,19 @@ impl Engine {
|
|||||||
// Must be either `var[index] op= val` or `var.prop op= val`
|
// Must be either `var[index] op= val` or `var.prop op= val`
|
||||||
match lhs {
|
match lhs {
|
||||||
// name op= rhs (handled above)
|
// name op= rhs (handled above)
|
||||||
Expr::Variable(_, _, _) => {
|
Expr::Variable(..) => {
|
||||||
unreachable!("Expr::Variable case is already handled")
|
unreachable!("Expr::Variable case is already handled")
|
||||||
}
|
}
|
||||||
// idx_lhs[idx_expr] op= rhs
|
// idx_lhs[idx_expr] op= rhs
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(_, _, _) => self
|
Expr::Index(..) => self
|
||||||
.eval_dot_index_chain(
|
.eval_dot_index_chain(
|
||||||
scope, global, state, lib, this_ptr, lhs, level, _new_val,
|
scope, global, state, lib, this_ptr, lhs, level, _new_val,
|
||||||
)
|
)
|
||||||
.map(|_| Dynamic::UNIT),
|
.map(|_| Dynamic::UNIT),
|
||||||
// dot_lhs.dot_rhs op= rhs
|
// dot_lhs.dot_rhs op= rhs
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Dot(_, _, _) => self
|
Expr::Dot(..) => self
|
||||||
.eval_dot_index_chain(
|
.eval_dot_index_chain(
|
||||||
scope, global, state, lib, this_ptr, lhs, level, _new_val,
|
scope, global, state, lib, this_ptr, lhs, level, _new_val,
|
||||||
)
|
)
|
||||||
@ -323,7 +323,7 @@ impl Engine {
|
|||||||
|
|
||||||
let result = match stmt {
|
let result = match stmt {
|
||||||
// No-op
|
// No-op
|
||||||
Stmt::Noop(_) => Ok(Dynamic::UNIT),
|
Stmt::Noop(..) => Ok(Dynamic::UNIT),
|
||||||
|
|
||||||
// Expression as statement
|
// Expression as statement
|
||||||
Stmt::Expr(expr) => self
|
Stmt::Expr(expr) => self
|
||||||
@ -331,13 +331,13 @@ impl Engine {
|
|||||||
.map(Dynamic::flatten),
|
.map(Dynamic::flatten),
|
||||||
|
|
||||||
// Block scope
|
// Block scope
|
||||||
Stmt::Block(statements, _) if statements.is_empty() => Ok(Dynamic::UNIT),
|
Stmt::Block(statements, ..) if statements.is_empty() => Ok(Dynamic::UNIT),
|
||||||
Stmt::Block(statements, _) => {
|
Stmt::Block(statements, ..) => {
|
||||||
self.eval_stmt_block(scope, global, state, lib, this_ptr, statements, true, level)
|
self.eval_stmt_block(scope, global, state, lib, this_ptr, statements, true, level)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If statement
|
// If statement
|
||||||
Stmt::If(expr, x, _) => {
|
Stmt::If(expr, x, ..) => {
|
||||||
let guard_val = self
|
let guard_val = self
|
||||||
.eval_expr(scope, global, state, lib, this_ptr, expr, level)
|
.eval_expr(scope, global, state, lib, this_ptr, expr, level)
|
||||||
.and_then(|v| {
|
.and_then(|v| {
|
||||||
@ -370,7 +370,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Switch statement
|
// Switch statement
|
||||||
Stmt::Switch(match_expr, x, _) => {
|
Stmt::Switch(match_expr, x, ..) => {
|
||||||
let SwitchCases {
|
let SwitchCases {
|
||||||
cases,
|
cases,
|
||||||
def_case,
|
def_case,
|
||||||
@ -414,8 +414,8 @@ impl Engine {
|
|||||||
let value = value.as_int().expect("`INT`");
|
let value = value.as_int().expect("`INT`");
|
||||||
let mut result = Ok(None);
|
let mut result = Ok(None);
|
||||||
|
|
||||||
for (_, _, _, block) in
|
for (.., block) in
|
||||||
ranges.iter().filter(|&&(start, end, inclusive, _)| {
|
ranges.iter().filter(|&&(start, end, inclusive, ..)| {
|
||||||
(!inclusive && (start..end).contains(&value))
|
(!inclusive && (start..end).contains(&value))
|
||||||
|| (inclusive && (start..=end).contains(&value))
|
|| (inclusive && (start..=end).contains(&value))
|
||||||
})
|
})
|
||||||
@ -483,15 +483,15 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Loop
|
// Loop
|
||||||
Stmt::While(Expr::Unit(_), body, _) => loop {
|
Stmt::While(Expr::Unit(..), body, ..) => loop {
|
||||||
if !body.is_empty() {
|
if !body.is_empty() {
|
||||||
match self
|
match self
|
||||||
.eval_stmt_block(scope, global, state, lib, this_ptr, body, true, level)
|
.eval_stmt_block(scope, global, state, lib, this_ptr, body, true, level)
|
||||||
{
|
{
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(err) => match *err {
|
Err(err) => match *err {
|
||||||
ERR::LoopBreak(false, _) => (),
|
ERR::LoopBreak(false, ..) => (),
|
||||||
ERR::LoopBreak(true, _) => break Ok(Dynamic::UNIT),
|
ERR::LoopBreak(true, ..) => break Ok(Dynamic::UNIT),
|
||||||
_ => break Err(err),
|
_ => break Err(err),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -502,7 +502,7 @@ impl Engine {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// While loop
|
// While loop
|
||||||
Stmt::While(expr, body, _) => loop {
|
Stmt::While(expr, body, ..) => loop {
|
||||||
let condition = self
|
let condition = self
|
||||||
.eval_expr(scope, global, state, lib, this_ptr, expr, level)
|
.eval_expr(scope, global, state, lib, this_ptr, expr, level)
|
||||||
.and_then(|v| {
|
.and_then(|v| {
|
||||||
@ -520,8 +520,8 @@ impl Engine {
|
|||||||
{
|
{
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(err) => match *err {
|
Err(err) => match *err {
|
||||||
ERR::LoopBreak(false, _) => (),
|
ERR::LoopBreak(false, ..) => (),
|
||||||
ERR::LoopBreak(true, _) => break Ok(Dynamic::UNIT),
|
ERR::LoopBreak(true, ..) => break Ok(Dynamic::UNIT),
|
||||||
_ => break Err(err),
|
_ => break Err(err),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -531,7 +531,7 @@ impl Engine {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Do loop
|
// Do loop
|
||||||
Stmt::Do(body, expr, options, _) => loop {
|
Stmt::Do(body, expr, options, ..) => loop {
|
||||||
let is_while = !options.contains(AST_OPTION_NEGATED);
|
let is_while = !options.contains(AST_OPTION_NEGATED);
|
||||||
|
|
||||||
if !body.is_empty() {
|
if !body.is_empty() {
|
||||||
@ -540,8 +540,8 @@ impl Engine {
|
|||||||
{
|
{
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(err) => match *err {
|
Err(err) => match *err {
|
||||||
ERR::LoopBreak(false, _) => continue,
|
ERR::LoopBreak(false, ..) => continue,
|
||||||
ERR::LoopBreak(true, _) => break Ok(Dynamic::UNIT),
|
ERR::LoopBreak(true, ..) => break Ok(Dynamic::UNIT),
|
||||||
_ => break Err(err),
|
_ => break Err(err),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -563,7 +563,7 @@ impl Engine {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// For loop
|
// For loop
|
||||||
Stmt::For(expr, x, _) => {
|
Stmt::For(expr, x, ..) => {
|
||||||
let (Ident { name: var_name, .. }, counter, statements) = x.as_ref();
|
let (Ident { name: var_name, .. }, counter, statements) = x.as_ref();
|
||||||
|
|
||||||
let iter_result = self
|
let iter_result = self
|
||||||
@ -672,8 +672,8 @@ impl Engine {
|
|||||||
match result {
|
match result {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(err) => match *err {
|
Err(err) => match *err {
|
||||||
ERR::LoopBreak(false, _) => (),
|
ERR::LoopBreak(false, ..) => (),
|
||||||
ERR::LoopBreak(true, _) => break,
|
ERR::LoopBreak(true, ..) => break,
|
||||||
_ => {
|
_ => {
|
||||||
loop_result = Err(err);
|
loop_result = Err(err);
|
||||||
break;
|
break;
|
||||||
@ -699,7 +699,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try/Catch statement
|
// Try/Catch statement
|
||||||
Stmt::TryCatch(x, _) => {
|
Stmt::TryCatch(x, ..) => {
|
||||||
let TryCatchBlock {
|
let TryCatchBlock {
|
||||||
try_block,
|
try_block,
|
||||||
catch_var,
|
catch_var,
|
||||||
@ -715,8 +715,8 @@ impl Engine {
|
|||||||
Err(err) if err.is_pseudo_error() => Err(err),
|
Err(err) if err.is_pseudo_error() => Err(err),
|
||||||
Err(err) if !err.is_catchable() => Err(err),
|
Err(err) if !err.is_catchable() => Err(err),
|
||||||
Err(mut err) => {
|
Err(mut err) => {
|
||||||
let err_value = match *err {
|
let err_value = match err.unwrap_inner() {
|
||||||
ERR::ErrorRuntime(ref x, _) => x.clone(),
|
ERR::ErrorRuntime(x, ..) => x.clone(),
|
||||||
|
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
_ => {
|
_ => {
|
||||||
@ -773,7 +773,7 @@ impl Engine {
|
|||||||
Ok(_) => Ok(Dynamic::UNIT),
|
Ok(_) => Ok(Dynamic::UNIT),
|
||||||
Err(result_err) => match *result_err {
|
Err(result_err) => match *result_err {
|
||||||
// Re-throw exception
|
// Re-throw exception
|
||||||
ERR::ErrorRuntime(Dynamic(Union::Unit(_, _, _)), pos) => {
|
ERR::ErrorRuntime(Dynamic(Union::Unit(..)), pos) => {
|
||||||
err.set_position(pos);
|
err.set_position(pos);
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
@ -795,15 +795,15 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return value
|
// Return value
|
||||||
Stmt::Return(_, Some(expr), pos) => self
|
Stmt::Return(.., Some(expr), pos) => self
|
||||||
.eval_expr(scope, global, state, lib, this_ptr, expr, level)
|
.eval_expr(scope, global, state, lib, this_ptr, expr, level)
|
||||||
.and_then(|v| Err(ERR::Return(v.flatten(), *pos).into())),
|
.and_then(|v| Err(ERR::Return(v.flatten(), *pos).into())),
|
||||||
|
|
||||||
// Empty return
|
// Empty return
|
||||||
Stmt::Return(_, None, pos) => Err(ERR::Return(Dynamic::UNIT, *pos).into()),
|
Stmt::Return(.., None, pos) => Err(ERR::Return(Dynamic::UNIT, *pos).into()),
|
||||||
|
|
||||||
// Let/const statement - shadowing disallowed
|
// Let/const statement - shadowing disallowed
|
||||||
Stmt::Var(_, x, _, pos) if !self.allow_shadowing() && scope.contains(&x.name) => {
|
Stmt::Var(.., x, _, pos) if !self.allow_shadowing() && scope.contains(&x.name) => {
|
||||||
Err(ERR::ErrorVariableExists(x.name.to_string(), *pos).into())
|
Err(ERR::ErrorVariableExists(x.name.to_string(), *pos).into())
|
||||||
}
|
}
|
||||||
// Let/const statement
|
// Let/const statement
|
||||||
@ -924,7 +924,7 @@ impl Engine {
|
|||||||
let module_result = resolver
|
let module_result = resolver
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|r| match r.resolve_raw(self, global, &path, path_pos) {
|
.and_then(|r| match r.resolve_raw(self, global, &path, path_pos) {
|
||||||
Err(err) if matches!(*err, ERR::ErrorModuleNotFound(_, _)) => None,
|
Err(err) if matches!(*err, ERR::ErrorModuleNotFound(..)) => None,
|
||||||
result => Some(result),
|
result => Some(result),
|
||||||
})
|
})
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
@ -961,10 +961,10 @@ impl Engine {
|
|||||||
|
|
||||||
// Export statement
|
// Export statement
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Stmt::Export(x, _) => {
|
Stmt::Export(x, ..) => {
|
||||||
let (Ident { name, pos, .. }, Ident { name: alias, .. }) = x.as_ref();
|
let (Ident { name, pos, .. }, Ident { name: alias, .. }) = x.as_ref();
|
||||||
// Mark scope variables as public
|
// Mark scope variables as public
|
||||||
if let Some((index, _)) = scope.get_index(name) {
|
if let Some((index, ..)) = scope.get_index(name) {
|
||||||
scope.add_entry_alias(
|
scope.add_entry_alias(
|
||||||
index,
|
index,
|
||||||
if alias.is_empty() { name } else { alias }.clone(),
|
if alias.is_empty() { name } else { alias }.clone(),
|
||||||
@ -978,7 +978,7 @@ impl Engine {
|
|||||||
// Share statement
|
// Share statement
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Stmt::Share(name) => {
|
Stmt::Share(name) => {
|
||||||
if let Some((index, _)) = scope.get_index(name) {
|
if let Some((index, ..)) = scope.get_index(name) {
|
||||||
let val = scope.get_mut_by_index(index);
|
let val = scope.get_mut_by_index(index);
|
||||||
|
|
||||||
if !val.is_shared() {
|
if !val.is_shared() {
|
||||||
|
@ -144,10 +144,10 @@ impl<'a> Target<'a> {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_ref(&self) -> bool {
|
pub const fn is_ref(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::RefMut(_) => true,
|
Self::RefMut(..) => true,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Self::SharedValue { .. } => true,
|
Self::SharedValue { .. } => true,
|
||||||
Self::TempValue(_) => false,
|
Self::TempValue(..) => false,
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Self::Bit { .. }
|
Self::Bit { .. }
|
||||||
| Self::BitField { .. }
|
| Self::BitField { .. }
|
||||||
@ -160,10 +160,10 @@ impl<'a> Target<'a> {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_temp_value(&self) -> bool {
|
pub const fn is_temp_value(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::RefMut(_) => false,
|
Self::RefMut(..) => false,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Self::SharedValue { .. } => false,
|
Self::SharedValue { .. } => false,
|
||||||
Self::TempValue(_) => true,
|
Self::TempValue(..) => true,
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Self::Bit { .. }
|
Self::Bit { .. }
|
||||||
| Self::BitField { .. }
|
| Self::BitField { .. }
|
||||||
@ -275,7 +275,7 @@ impl<'a> Target<'a> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn propagate_changed_value(&mut self) -> RhaiResultOf<()> {
|
pub fn propagate_changed_value(&mut self) -> RhaiResultOf<()> {
|
||||||
match self {
|
match self {
|
||||||
Self::RefMut(_) | Self::TempValue(_) => (),
|
Self::RefMut(..) | Self::TempValue(..) => (),
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Self::SharedValue { .. } => (),
|
Self::SharedValue { .. } => (),
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
@ -12,7 +12,8 @@ use crate::engine::{
|
|||||||
use crate::eval::{EvalState, GlobalRuntimeState};
|
use crate::eval::{EvalState, GlobalRuntimeState};
|
||||||
use crate::{
|
use crate::{
|
||||||
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnArgsVec, FnPtr,
|
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnArgsVec, FnPtr,
|
||||||
Identifier, ImmutableString, Module, Position, RhaiResult, RhaiResultOf, Scope, ERR,
|
Identifier, ImmutableString, Module, OptimizationLevel, Position, RhaiError, RhaiResult,
|
||||||
|
RhaiResultOf, Scope, ERR,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -45,11 +46,13 @@ impl<'a> ArgBackup<'a> {
|
|||||||
/// This function replaces the first argument of a method call with a clone copy.
|
/// This function replaces the first argument of a method call with a clone copy.
|
||||||
/// This is to prevent a pure function unintentionally consuming the first argument.
|
/// This is to prevent a pure function unintentionally consuming the first argument.
|
||||||
///
|
///
|
||||||
/// `restore_first_arg` must be called before the end of the scope to prevent the shorter lifetime from leaking.
|
/// `restore_first_arg` must be called before the end of the scope to prevent the shorter
|
||||||
|
/// lifetime from leaking.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This method blindly casts a reference to another lifetime, which saves allocation and string cloning.
|
/// This method blindly casts a reference to another lifetime, which saves allocation and
|
||||||
|
/// string cloning.
|
||||||
///
|
///
|
||||||
/// As long as `restore_first_arg` is called before the end of the scope, the shorter lifetime
|
/// As long as `restore_first_arg` is called before the end of the scope, the shorter lifetime
|
||||||
/// will not leak.
|
/// will not leak.
|
||||||
@ -70,8 +73,8 @@ impl<'a> ArgBackup<'a> {
|
|||||||
// Blindly casting a reference to another lifetime saves allocation and string cloning,
|
// Blindly casting a reference to another lifetime saves allocation and string cloning,
|
||||||
// but must be used with the utmost care.
|
// but must be used with the utmost care.
|
||||||
//
|
//
|
||||||
// We can do this here because, before the end of this scope, we'd restore the original reference
|
// We can do this here because, before the end of this scope, we'd restore the original
|
||||||
// via `restore_first_arg`. Therefore this shorter lifetime does not leak.
|
// reference via `restore_first_arg`. Therefore this shorter lifetime does not leak.
|
||||||
self.orig_mut = Some(mem::replace(&mut args[0], unsafe {
|
self.orig_mut = Some(mem::replace(&mut args[0], unsafe {
|
||||||
mem::transmute(&mut self.value_copy)
|
mem::transmute(&mut self.value_copy)
|
||||||
}));
|
}));
|
||||||
@ -80,8 +83,8 @@ impl<'a> ArgBackup<'a> {
|
|||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// If `change_first_arg_to_copy` has been called, this function **MUST** be called _BEFORE_ exiting
|
/// If `change_first_arg_to_copy` has been called, this function **MUST** be called _BEFORE_
|
||||||
/// the current scope. Otherwise it is undefined behavior as the shorter lifetime will leak.
|
/// exiting the current scope. Otherwise it is undefined behavior as the shorter lifetime will leak.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn restore_first_arg(mut self, args: &mut FnCallArgs<'a>) {
|
fn restore_first_arg(mut self, args: &mut FnCallArgs<'a>) {
|
||||||
if let Some(p) = self.orig_mut.take() {
|
if let Some(p) = self.orig_mut.take() {
|
||||||
@ -108,11 +111,11 @@ pub fn ensure_no_data_race(
|
|||||||
args: &FnCallArgs,
|
args: &FnCallArgs,
|
||||||
is_method_call: bool,
|
is_method_call: bool,
|
||||||
) -> RhaiResultOf<()> {
|
) -> RhaiResultOf<()> {
|
||||||
if let Some((n, _)) = args
|
if let Some((n, ..)) = args
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.skip(if is_method_call { 1 } else { 0 })
|
.skip(if is_method_call { 1 } else { 0 })
|
||||||
.find(|(_, a)| a.is_locked())
|
.find(|(.., a)| a.is_locked())
|
||||||
{
|
{
|
||||||
return Err(ERR::ErrorDataRace(
|
return Err(ERR::ErrorDataRace(
|
||||||
format!("argument #{} of function '{}'", n + 1, fn_name),
|
format!("argument #{} of function '{}'", n + 1, fn_name),
|
||||||
@ -391,7 +394,7 @@ impl Engine {
|
|||||||
|
|
||||||
let source = match (source.as_str(), parent_source.as_str()) {
|
let source = match (source.as_str(), parent_source.as_str()) {
|
||||||
("", "") => None,
|
("", "") => None,
|
||||||
("", s) | (s, _) => Some(s),
|
("", s) | (s, ..) => Some(s),
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
@ -429,7 +432,7 @@ impl Engine {
|
|||||||
{
|
{
|
||||||
let trigger = match global.debugger.status {
|
let trigger = match global.debugger.status {
|
||||||
crate::eval::DebuggerStatus::FunctionExit(n) => n >= level,
|
crate::eval::DebuggerStatus::FunctionExit(n) => n >= level,
|
||||||
crate::eval::DebuggerStatus::Next(_, true) => true,
|
crate::eval::DebuggerStatus::Next(.., true) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if trigger {
|
if trigger {
|
||||||
@ -773,8 +776,8 @@ impl Engine {
|
|||||||
scope, global, state, lib, &mut None, statements, false, level,
|
scope, global, state, lib, &mut None, statements, false, level,
|
||||||
)
|
)
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
ERR::Return(out, _) => Ok(out),
|
ERR::Return(out, ..) => Ok(out),
|
||||||
ERR::LoopBreak(_, _) => {
|
ERR::LoopBreak(..) => {
|
||||||
unreachable!("no outer loop scope to break out of")
|
unreachable!("no outer loop scope to break out of")
|
||||||
}
|
}
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
@ -957,7 +960,7 @@ impl Engine {
|
|||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResultOf<(Dynamic, Position)> {
|
) -> RhaiResultOf<(Dynamic, Position)> {
|
||||||
Ok((
|
Ok((
|
||||||
if let Expr::Stack(slot, _) = arg_expr {
|
if let Expr::Stack(slot, ..) = arg_expr {
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
self.run_debugger(scope, global, state, lib, this_ptr, arg_expr, level)?;
|
self.run_debugger(scope, global, state, lib, this_ptr, arg_expr, level)?;
|
||||||
constants[*slot].clone()
|
constants[*slot].clone()
|
||||||
@ -969,7 +972,7 @@ impl Engine {
|
|||||||
// Do not match function exit for arguments
|
// Do not match function exit for arguments
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
let reset_debugger = global.debugger.clear_status_if(|status| {
|
let reset_debugger = global.debugger.clear_status_if(|status| {
|
||||||
matches!(status, crate::eval::DebuggerStatus::FunctionExit(_))
|
matches!(status, crate::eval::DebuggerStatus::FunctionExit(..))
|
||||||
});
|
});
|
||||||
|
|
||||||
let result = self.eval_expr(scope, global, state, lib, this_ptr, arg_expr, level);
|
let result = self.eval_expr(scope, global, state, lib, this_ptr, arg_expr, level);
|
||||||
@ -1076,16 +1079,13 @@ impl Engine {
|
|||||||
let (name, fn_curry) = arg_value.cast::<FnPtr>().take_data();
|
let (name, fn_curry) = arg_value.cast::<FnPtr>().take_data();
|
||||||
|
|
||||||
// Append the new curried arguments to the existing list.
|
// Append the new curried arguments to the existing list.
|
||||||
let fn_curry =
|
let fn_curry = a_expr.iter().try_fold(fn_curry, |mut curried, expr| {
|
||||||
a_expr
|
let (value, ..) = self.get_arg_value(
|
||||||
.iter()
|
scope, global, state, lib, this_ptr, expr, constants, level,
|
||||||
.try_fold(fn_curry, |mut curried, expr| -> RhaiResultOf<_> {
|
)?;
|
||||||
let (value, _) = self.get_arg_value(
|
curried.push(value);
|
||||||
scope, global, state, lib, this_ptr, expr, constants, level,
|
Ok::<_, RhaiError>(curried)
|
||||||
)?;
|
})?;
|
||||||
curried.push(value);
|
|
||||||
Ok(curried)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
return Ok(FnPtr::new_unchecked(name, fn_curry).into());
|
return Ok(FnPtr::new_unchecked(name, fn_curry).into());
|
||||||
}
|
}
|
||||||
@ -1094,7 +1094,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
crate::engine::KEYWORD_IS_SHARED if total_args == 1 => {
|
crate::engine::KEYWORD_IS_SHARED if total_args == 1 => {
|
||||||
let arg = first_arg.unwrap();
|
let arg = first_arg.unwrap();
|
||||||
let (arg_value, _) =
|
let (arg_value, ..) =
|
||||||
self.get_arg_value(scope, global, state, lib, this_ptr, arg, constants, level)?;
|
self.get_arg_value(scope, global, state, lib, this_ptr, arg, constants, level)?;
|
||||||
return Ok(arg_value.is_shared().into());
|
return Ok(arg_value.is_shared().into());
|
||||||
}
|
}
|
||||||
@ -1194,7 +1194,7 @@ impl Engine {
|
|||||||
.chain(a_expr.iter())
|
.chain(a_expr.iter())
|
||||||
.try_for_each(|expr| {
|
.try_for_each(|expr| {
|
||||||
self.get_arg_value(scope, global, state, lib, this_ptr, expr, constants, level)
|
self.get_arg_value(scope, global, state, lib, this_ptr, expr, constants, level)
|
||||||
.map(|(value, _)| arg_values.push(value.flatten()))
|
.map(|(value, ..)| arg_values.push(value.flatten()))
|
||||||
})?;
|
})?;
|
||||||
args.extend(curry.iter_mut());
|
args.extend(curry.iter_mut());
|
||||||
args.extend(arg_values.iter_mut());
|
args.extend(arg_values.iter_mut());
|
||||||
@ -1207,7 +1207,7 @@ impl Engine {
|
|||||||
scope, global, state, lib, name, hashes, &mut args, is_ref_mut, false, pos,
|
scope, global, state, lib, name, hashes, &mut args, is_ref_mut, false, pos,
|
||||||
level,
|
level,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| v);
|
.map(|(v, ..)| v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call with blank scope
|
// Call with blank scope
|
||||||
@ -1226,7 +1226,7 @@ impl Engine {
|
|||||||
// func(x, ...) -> x.func(...)
|
// func(x, ...) -> x.func(...)
|
||||||
a_expr.iter().try_for_each(|expr| {
|
a_expr.iter().try_for_each(|expr| {
|
||||||
self.get_arg_value(scope, global, state, lib, this_ptr, expr, constants, level)
|
self.get_arg_value(scope, global, state, lib, this_ptr, expr, constants, level)
|
||||||
.map(|(value, _)| arg_values.push(value.flatten()))
|
.map(|(value, ..)| arg_values.push(value.flatten()))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let (mut target, _pos) =
|
let (mut target, _pos) =
|
||||||
@ -1263,7 +1263,7 @@ impl Engine {
|
|||||||
self.get_arg_value(
|
self.get_arg_value(
|
||||||
scope, global, state, lib, this_ptr, expr, constants, level,
|
scope, global, state, lib, this_ptr, expr, constants, level,
|
||||||
)
|
)
|
||||||
.map(|(value, _)| arg_values.push(value.flatten()))
|
.map(|(value, ..)| arg_values.push(value.flatten()))
|
||||||
})?;
|
})?;
|
||||||
args.extend(curry.iter_mut());
|
args.extend(curry.iter_mut());
|
||||||
args.extend(arg_values.iter_mut());
|
args.extend(arg_values.iter_mut());
|
||||||
@ -1273,7 +1273,7 @@ impl Engine {
|
|||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
None, global, state, lib, name, hashes, &mut args, is_ref_mut, false, pos, level,
|
None, global, state, lib, name, hashes, &mut args, is_ref_mut, false, pos, level,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| v)
|
.map(|(v, ..)| v)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call a namespace-qualified function in normal function-call style.
|
/// Call a namespace-qualified function in normal function-call style.
|
||||||
@ -1312,7 +1312,7 @@ impl Engine {
|
|||||||
|
|
||||||
args_expr.iter().skip(1).try_for_each(|expr| {
|
args_expr.iter().skip(1).try_for_each(|expr| {
|
||||||
self.get_arg_value(scope, global, state, lib, this_ptr, expr, constants, level)
|
self.get_arg_value(scope, global, state, lib, this_ptr, expr, constants, level)
|
||||||
.map(|(value, _)| arg_values.push(value.flatten()))
|
.map(|(value, ..)| arg_values.push(value.flatten()))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Get target reference to first argument
|
// Get target reference to first argument
|
||||||
@ -1343,7 +1343,7 @@ impl Engine {
|
|||||||
// func(..., ...) or func(mod::x, ...)
|
// func(..., ...) or func(mod::x, ...)
|
||||||
args_expr.iter().try_for_each(|expr| {
|
args_expr.iter().try_for_each(|expr| {
|
||||||
self.get_arg_value(scope, global, state, lib, this_ptr, expr, constants, level)
|
self.get_arg_value(scope, global, state, lib, this_ptr, expr, constants, level)
|
||||||
.map(|(value, _)| arg_values.push(value.flatten()))
|
.map(|(value, ..)| arg_values.push(value.flatten()))
|
||||||
})?;
|
})?;
|
||||||
args.extend(arg_values.iter_mut());
|
args.extend(arg_values.iter_mut());
|
||||||
}
|
}
|
||||||
@ -1450,7 +1450,9 @@ impl Engine {
|
|||||||
&Scope::new(),
|
&Scope::new(),
|
||||||
&[script],
|
&[script],
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
crate::OptimizationLevel::None,
|
OptimizationLevel::None,
|
||||||
|
#[cfg(feature = "no_optimize")]
|
||||||
|
OptimizationLevel::default(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// If new functions are defined within the eval string, it is an error
|
// If new functions are defined within the eval string, it is an error
|
||||||
|
@ -30,10 +30,10 @@ pub enum CallableFunction {
|
|||||||
impl fmt::Debug for CallableFunction {
|
impl fmt::Debug for CallableFunction {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Pure(_) => write!(f, "NativePureFunction"),
|
Self::Pure(..) => write!(f, "NativePureFunction"),
|
||||||
Self::Method(_) => write!(f, "NativeMethod"),
|
Self::Method(..) => write!(f, "NativeMethod"),
|
||||||
Self::Iterator(_) => write!(f, "NativeIterator"),
|
Self::Iterator(..) => write!(f, "NativeIterator"),
|
||||||
Self::Plugin(_) => write!(f, "PluginFunction"),
|
Self::Plugin(..) => write!(f, "PluginFunction"),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(fn_def) => fmt::Debug::fmt(fn_def, f),
|
Self::Script(fn_def) => fmt::Debug::fmt(fn_def, f),
|
||||||
@ -44,10 +44,10 @@ impl fmt::Debug for CallableFunction {
|
|||||||
impl fmt::Display for CallableFunction {
|
impl fmt::Display for CallableFunction {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Pure(_) => write!(f, "NativePureFunction"),
|
Self::Pure(..) => write!(f, "NativePureFunction"),
|
||||||
Self::Method(_) => write!(f, "NativeMethod"),
|
Self::Method(..) => write!(f, "NativeMethod"),
|
||||||
Self::Iterator(_) => write!(f, "NativeIterator"),
|
Self::Iterator(..) => write!(f, "NativeIterator"),
|
||||||
Self::Plugin(_) => write!(f, "PluginFunction"),
|
Self::Plugin(..) => write!(f, "PluginFunction"),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(s) => fmt::Display::fmt(s, f),
|
Self::Script(s) => fmt::Display::fmt(s, f),
|
||||||
@ -61,13 +61,13 @@ impl CallableFunction {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_pure(&self) -> bool {
|
pub fn is_pure(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Pure(_) => true,
|
Self::Pure(..) => true,
|
||||||
Self::Method(_) | Self::Iterator(_) => false,
|
Self::Method(..) | Self::Iterator(..) => false,
|
||||||
|
|
||||||
Self::Plugin(p) => !p.is_method_call(),
|
Self::Plugin(p) => !p.is_method_call(),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(_) => false,
|
Self::Script(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is this a native Rust method function?
|
/// Is this a native Rust method function?
|
||||||
@ -75,13 +75,13 @@ impl CallableFunction {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_method(&self) -> bool {
|
pub fn is_method(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Method(_) => true,
|
Self::Method(..) => true,
|
||||||
Self::Pure(_) | Self::Iterator(_) => false,
|
Self::Pure(..) | Self::Iterator(..) => false,
|
||||||
|
|
||||||
Self::Plugin(p) => p.is_method_call(),
|
Self::Plugin(p) => p.is_method_call(),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(_) => false,
|
Self::Script(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is this an iterator function?
|
/// Is this an iterator function?
|
||||||
@ -89,11 +89,11 @@ impl CallableFunction {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_iter(&self) -> bool {
|
pub const fn is_iter(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Iterator(_) => true,
|
Self::Iterator(..) => true,
|
||||||
Self::Pure(_) | Self::Method(_) | Self::Plugin(_) => false,
|
Self::Pure(..) | Self::Method(..) | Self::Plugin(..) => false,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(_) => false,
|
Self::Script(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is this a script-defined function?
|
/// Is this a script-defined function?
|
||||||
@ -105,8 +105,8 @@ impl CallableFunction {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
match self {
|
match self {
|
||||||
Self::Script(_) => true,
|
Self::Script(..) => true,
|
||||||
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) | Self::Plugin(_) => false,
|
Self::Pure(..) | Self::Method(..) | Self::Iterator(..) | Self::Plugin(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is this a plugin function?
|
/// Is this a plugin function?
|
||||||
@ -114,11 +114,11 @@ impl CallableFunction {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_plugin_fn(&self) -> bool {
|
pub const fn is_plugin_fn(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Plugin(_) => true,
|
Self::Plugin(..) => true,
|
||||||
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => false,
|
Self::Pure(..) | Self::Method(..) | Self::Iterator(..) => false,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(_) => false,
|
Self::Script(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is this a native Rust function?
|
/// Is this a native Rust function?
|
||||||
@ -130,10 +130,10 @@ impl CallableFunction {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
match self {
|
match self {
|
||||||
Self::Pure(_) | Self::Method(_) => true,
|
Self::Pure(..) | Self::Method(..) => true,
|
||||||
Self::Plugin(_) => true,
|
Self::Plugin(..) => true,
|
||||||
Self::Iterator(_) => true,
|
Self::Iterator(..) => true,
|
||||||
Self::Script(_) => false,
|
Self::Script(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Get the access mode.
|
/// Get the access mode.
|
||||||
@ -145,8 +145,8 @@ impl CallableFunction {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
match self {
|
match self {
|
||||||
Self::Plugin(_) => FnAccess::Public,
|
Self::Plugin(..) => FnAccess::Public,
|
||||||
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => FnAccess::Public,
|
Self::Pure(..) | Self::Method(..) | Self::Iterator(..) => FnAccess::Public,
|
||||||
Self::Script(f) => f.access,
|
Self::Script(f) => f.access,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,10 +156,10 @@ impl CallableFunction {
|
|||||||
pub fn get_native_fn(&self) -> Option<&Shared<FnAny>> {
|
pub fn get_native_fn(&self) -> Option<&Shared<FnAny>> {
|
||||||
match self {
|
match self {
|
||||||
Self::Pure(f) | Self::Method(f) => Some(f),
|
Self::Pure(f) | Self::Method(f) => Some(f),
|
||||||
Self::Iterator(_) | Self::Plugin(_) => None,
|
Self::Iterator(..) | Self::Plugin(..) => None,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(_) => None,
|
Self::Script(..) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Get a shared reference to a script-defined function definition.
|
/// Get a shared reference to a script-defined function definition.
|
||||||
@ -170,7 +170,7 @@ impl CallableFunction {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn get_script_fn_def(&self) -> Option<&Shared<crate::ast::ScriptFnDef>> {
|
pub const fn get_script_fn_def(&self) -> Option<&Shared<crate::ast::ScriptFnDef>> {
|
||||||
match self {
|
match self {
|
||||||
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) | Self::Plugin(_) => None,
|
Self::Pure(..) | Self::Method(..) | Self::Iterator(..) | Self::Plugin(..) => None,
|
||||||
Self::Script(f) => Some(f),
|
Self::Script(f) => Some(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -180,10 +180,10 @@ impl CallableFunction {
|
|||||||
pub fn get_iter_fn(&self) -> Option<&IteratorFn> {
|
pub fn get_iter_fn(&self) -> Option<&IteratorFn> {
|
||||||
match self {
|
match self {
|
||||||
Self::Iterator(f) => Some(f.as_ref()),
|
Self::Iterator(f) => Some(f.as_ref()),
|
||||||
Self::Pure(_) | Self::Method(_) | Self::Plugin(_) => None,
|
Self::Pure(..) | Self::Method(..) | Self::Plugin(..) => None,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(_) => None,
|
Self::Script(..) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Get a shared reference to a plugin function.
|
/// Get a shared reference to a plugin function.
|
||||||
@ -192,10 +192,10 @@ impl CallableFunction {
|
|||||||
pub fn get_plugin_fn(&self) -> Option<&Shared<FnPlugin>> {
|
pub fn get_plugin_fn(&self) -> Option<&Shared<FnPlugin>> {
|
||||||
match self {
|
match self {
|
||||||
Self::Plugin(f) => Some(f),
|
Self::Plugin(f) => Some(f),
|
||||||
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => None,
|
Self::Pure(..) | Self::Method(..) | Self::Iterator(..) => None,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(_) => None,
|
Self::Script(..) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Create a new [`CallableFunction::Pure`].
|
/// Create a new [`CallableFunction::Pure`].
|
||||||
|
@ -333,7 +333,7 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
Position::NONE,
|
Position::NONE,
|
||||||
self.level + 1,
|
self.level + 1,
|
||||||
)
|
)
|
||||||
.map(|(r, _)| r)
|
.map(|(r, ..)| r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,10 +5,9 @@
|
|||||||
use super::call::FnCallArgs;
|
use super::call::FnCallArgs;
|
||||||
use super::callable_function::CallableFunction;
|
use super::callable_function::CallableFunction;
|
||||||
use super::native::{FnAny, SendSync};
|
use super::native::{FnAny, SendSync};
|
||||||
use crate::r#unsafe::unsafe_cast;
|
|
||||||
use crate::tokenizer::Position;
|
use crate::tokenizer::Position;
|
||||||
use crate::types::dynamic::{DynamicWriteLock, Variant};
|
use crate::types::dynamic::{DynamicWriteLock, Variant};
|
||||||
use crate::{Dynamic, NativeCallContext, RhaiResultOf, ERR};
|
use crate::{reify, Dynamic, NativeCallContext, RhaiResultOf, ERR};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
use std::{any::TypeId, mem};
|
use std::{any::TypeId, mem};
|
||||||
@ -39,23 +38,26 @@ pub fn by_ref<T: Variant + Clone>(data: &mut Dynamic) -> DynamicWriteLock<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Dereference into value.
|
/// Dereference into value.
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn by_value<T: Variant + Clone>(data: &mut Dynamic) -> T {
|
pub fn by_value<T: Variant + Clone>(data: &mut Dynamic) -> T {
|
||||||
if TypeId::of::<T>() == TypeId::of::<&str>() {
|
if TypeId::of::<T>() == TypeId::of::<&str>() {
|
||||||
// If T is `&str`, data must be `ImmutableString`, so map directly to it
|
// If T is `&str`, data must be `ImmutableString`, so map directly to it
|
||||||
data.flatten_in_place();
|
data.flatten_in_place();
|
||||||
let ref_str = data.as_str_ref().expect("&str");
|
let ref_str = data.as_str_ref().expect("&str");
|
||||||
let ref_t = unsafe { mem::transmute::<_, &T>(&ref_str) };
|
// # Safety
|
||||||
ref_t.clone()
|
//
|
||||||
} else if TypeId::of::<T>() == TypeId::of::<String>() {
|
// We already checked that `T` is `&str`, so it is safe to cast here.
|
||||||
// If T is `String`, data must be `ImmutableString`, so map directly to it
|
return unsafe { std::mem::transmute_copy::<_, T>(&ref_str) };
|
||||||
unsafe_cast(mem::take(data).into_string().expect("`ImmutableString`"))
|
|
||||||
} else {
|
|
||||||
// We consume the argument and then replace it with () - the argument is not supposed to be used again.
|
|
||||||
// This way, we avoid having to clone the argument again, because it is already a clone when passed here.
|
|
||||||
mem::take(data).cast::<T>()
|
|
||||||
}
|
}
|
||||||
|
if TypeId::of::<T>() == TypeId::of::<String>() {
|
||||||
|
// If T is `String`, data must be `ImmutableString`, so map directly to it
|
||||||
|
return reify!(mem::take(data).into_string().expect("`ImmutableString`") => T);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We consume the argument and then replace it with () - the argument is not supposed to be used again.
|
||||||
|
// This way, we avoid having to clone the argument again, because it is already a clone when passed here.
|
||||||
|
return mem::take(data).cast::<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait to register custom Rust functions.
|
/// Trait to register custom Rust functions.
|
||||||
|
@ -103,7 +103,7 @@ impl Engine {
|
|||||||
scope
|
scope
|
||||||
.iter()
|
.iter()
|
||||||
.skip(orig_scope_len)
|
.skip(orig_scope_len)
|
||||||
.map(|(_, _, v)| v.clone())
|
.map(|(.., v)| v.clone())
|
||||||
.collect(),
|
.collect(),
|
||||||
global.source.clone(),
|
global.source.clone(),
|
||||||
pos,
|
pos,
|
||||||
@ -161,9 +161,9 @@ impl Engine {
|
|||||||
)
|
)
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
// Convert return statement to return value
|
// Convert return statement to return value
|
||||||
ERR::Return(x, _) => Ok(x),
|
ERR::Return(x, ..) => Ok(x),
|
||||||
// Error in sub function call
|
// Error in sub function call
|
||||||
ERR::ErrorInFunctionCall(name, src, err, _) => {
|
ERR::ErrorInFunctionCall(name, src, err, ..) => {
|
||||||
let fn_name = if src.is_empty() {
|
let fn_name = if src.is_empty() {
|
||||||
format!("{} < {}", name, fn_def.name)
|
format!("{} < {}", name, fn_def.name)
|
||||||
} else {
|
} else {
|
||||||
@ -185,7 +185,7 @@ impl Engine {
|
|||||||
{
|
{
|
||||||
let trigger = match global.debugger.status {
|
let trigger = match global.debugger.status {
|
||||||
crate::eval::DebuggerStatus::FunctionExit(n) => n >= level,
|
crate::eval::DebuggerStatus::FunctionExit(n) => n >= level,
|
||||||
crate::eval::DebuggerStatus::Next(_, true) => true,
|
crate::eval::DebuggerStatus::Next(.., true) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if trigger {
|
if trigger {
|
||||||
|
@ -68,7 +68,6 @@ extern crate no_std_compat as std;
|
|||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
// Internal modules
|
// Internal modules
|
||||||
|
|
||||||
mod api;
|
mod api;
|
||||||
mod ast;
|
mod ast;
|
||||||
mod engine;
|
mod engine;
|
||||||
@ -78,10 +77,10 @@ mod module;
|
|||||||
mod optimizer;
|
mod optimizer;
|
||||||
pub mod packages;
|
pub mod packages;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
mod reify;
|
||||||
mod tests;
|
mod tests;
|
||||||
mod tokenizer;
|
mod tokenizer;
|
||||||
mod types;
|
mod types;
|
||||||
mod r#unsafe;
|
|
||||||
|
|
||||||
/// Error encountered when parsing a script.
|
/// Error encountered when parsing a script.
|
||||||
type PERR = ParseErrorType;
|
type PERR = ParseErrorType;
|
||||||
@ -234,6 +233,10 @@ pub mod serde;
|
|||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
pub use optimizer::OptimizationLevel;
|
pub use optimizer::OptimizationLevel;
|
||||||
|
|
||||||
|
/// Placeholder for the optimization level.
|
||||||
|
#[cfg(feature = "no_optimize")]
|
||||||
|
pub type OptimizationLevel = ();
|
||||||
|
|
||||||
// Expose internal data structures.
|
// Expose internal data structures.
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
|
@ -1402,7 +1402,7 @@ impl Module {
|
|||||||
/// Sub-modules are flattened onto the root [`Module`], with higher level overriding lower level.
|
/// Sub-modules are flattened onto the root [`Module`], with higher level overriding lower level.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn combine_flatten(&mut self, other: Self) -> &mut Self {
|
pub fn combine_flatten(&mut self, other: Self) -> &mut Self {
|
||||||
for (_, m) in other.modules.into_iter() {
|
for (.., m) in other.modules.into_iter() {
|
||||||
self.combine_flatten(shared_take_or_clone(m));
|
self.combine_flatten(shared_take_or_clone(m));
|
||||||
}
|
}
|
||||||
self.variables.extend(other.variables.into_iter());
|
self.variables.extend(other.variables.into_iter());
|
||||||
@ -1471,7 +1471,7 @@ impl Module {
|
|||||||
other
|
other
|
||||||
.functions
|
.functions
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&(_, f)| {
|
.filter(|&(.., f)| {
|
||||||
_filter(
|
_filter(
|
||||||
f.metadata.namespace,
|
f.metadata.namespace,
|
||||||
f.metadata.access,
|
f.metadata.access,
|
||||||
@ -1502,7 +1502,7 @@ impl Module {
|
|||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.functions = std::mem::take(&mut self.functions)
|
self.functions = std::mem::take(&mut self.functions)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|(_, f)| {
|
.filter(|(.., f)| {
|
||||||
if f.func.is_script() {
|
if f.func.is_script() {
|
||||||
filter(
|
filter(
|
||||||
f.metadata.namespace,
|
f.metadata.namespace,
|
||||||
@ -1717,7 +1717,7 @@ impl Module {
|
|||||||
result?;
|
result?;
|
||||||
|
|
||||||
// Variables with an alias left in the scope become module variables
|
// Variables with an alias left in the scope become module variables
|
||||||
for (_, value, mut aliases) in scope {
|
for (.., value, mut aliases) in scope {
|
||||||
match aliases.len() {
|
match aliases.len() {
|
||||||
0 => (),
|
0 => (),
|
||||||
1 => {
|
1 => {
|
||||||
|
@ -128,7 +128,7 @@ impl ModuleResolver for ModuleResolversCollection {
|
|||||||
match resolver.resolve(engine, source_path, path, pos) {
|
match resolver.resolve(engine, source_path, path, pos) {
|
||||||
Ok(module) => return Ok(module),
|
Ok(module) => return Ok(module),
|
||||||
Err(err) => match *err {
|
Err(err) => match *err {
|
||||||
ERR::ErrorModuleNotFound(_, _) => continue,
|
ERR::ErrorModuleNotFound(..) => continue,
|
||||||
ERR::ErrorInModule(_, err, _) => return Err(err),
|
ERR::ErrorInModule(_, err, _) => return Err(err),
|
||||||
_ => panic!("ModuleResolver::resolve returns error that is not ErrorModuleNotFound or ErrorInModule"),
|
_ => panic!("ModuleResolver::resolve returns error that is not ErrorModuleNotFound or ErrorInModule"),
|
||||||
},
|
},
|
||||||
|
@ -230,7 +230,7 @@ impl FileModuleResolver {
|
|||||||
|
|
||||||
locked_write(&self.cache)
|
locked_write(&self.cache)
|
||||||
.remove_entry(&file_path)
|
.remove_entry(&file_path)
|
||||||
.map(|(_, v)| v)
|
.map(|(.., v)| v)
|
||||||
}
|
}
|
||||||
/// Construct a full file path.
|
/// Construct a full file path.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -288,7 +288,7 @@ impl FileModuleResolver {
|
|||||||
let mut ast = engine
|
let mut ast = engine
|
||||||
.compile_file(file_path.clone())
|
.compile_file(file_path.clone())
|
||||||
.map_err(|err| match *err {
|
.map_err(|err| match *err {
|
||||||
ERR::ErrorSystem(_, err) if err.is::<IoError>() => {
|
ERR::ErrorSystem(.., err) if err.is::<IoError>() => {
|
||||||
Box::new(ERR::ErrorModuleNotFound(path.to_string(), pos))
|
Box::new(ERR::ErrorModuleNotFound(path.to_string(), pos))
|
||||||
}
|
}
|
||||||
_ => Box::new(ERR::ErrorInModule(path.to_string(), err, pos)),
|
_ => Box::new(ERR::ErrorInModule(path.to_string(), err, pos)),
|
||||||
@ -356,7 +356,7 @@ impl ModuleResolver for FileModuleResolver {
|
|||||||
ast
|
ast
|
||||||
})
|
})
|
||||||
.map_err(|err| match *err {
|
.map_err(|err| match *err {
|
||||||
ERR::ErrorSystem(_, err) if err.is::<IoError>() => {
|
ERR::ErrorSystem(.., err) if err.is::<IoError>() => {
|
||||||
ERR::ErrorModuleNotFound(path.to_string(), pos).into()
|
ERR::ErrorModuleNotFound(path.to_string(), pos).into()
|
||||||
}
|
}
|
||||||
_ => ERR::ErrorInModule(path.to_string(), err, pos).into(),
|
_ => ERR::ErrorInModule(path.to_string(), err, pos).into(),
|
||||||
|
174
src/optimizer.rs
174
src/optimizer.rs
@ -150,7 +150,7 @@ impl<'a> OptimizerState<'a> {
|
|||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
.ok()
|
.ok()
|
||||||
.map(|(v, _)| v)
|
.map(|(v, ..)| v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,13 +205,13 @@ fn optimize_stmt_block(
|
|||||||
// Flatten blocks
|
// Flatten blocks
|
||||||
loop {
|
loop {
|
||||||
if let Some(n) = statements.iter().enumerate().find_map(|(i, s)| match s {
|
if let Some(n) = statements.iter().enumerate().find_map(|(i, s)| match s {
|
||||||
Stmt::Block(block, _) if !block.iter().any(Stmt::is_block_dependent) => Some(i),
|
Stmt::Block(block, ..) if !block.iter().any(Stmt::is_block_dependent) => Some(i),
|
||||||
_ => None,
|
_ => None,
|
||||||
}) {
|
}) {
|
||||||
let (first, second) = statements.split_at_mut(n);
|
let (first, second) = statements.split_at_mut(n);
|
||||||
let stmt = mem::take(&mut second[0]);
|
let stmt = mem::take(&mut second[0]);
|
||||||
let mut stmts = match stmt {
|
let mut stmts = match stmt {
|
||||||
Stmt::Block(block, _) => block,
|
Stmt::Block(block, ..) => block,
|
||||||
stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt),
|
stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt),
|
||||||
};
|
};
|
||||||
statements = first
|
statements = first
|
||||||
@ -252,7 +252,7 @@ fn optimize_stmt_block(
|
|||||||
// Optimize each statement in the block
|
// Optimize each statement in the block
|
||||||
for stmt in statements.iter_mut() {
|
for stmt in statements.iter_mut() {
|
||||||
match stmt {
|
match stmt {
|
||||||
Stmt::Var(value_expr, x, options, _) => {
|
Stmt::Var(value_expr, x, options, ..) => {
|
||||||
if options.contains(AST_OPTION_CONSTANT) {
|
if options.contains(AST_OPTION_CONSTANT) {
|
||||||
// Add constant literals into the state
|
// Add constant literals into the state
|
||||||
optimize_expr(value_expr, state, false);
|
optimize_expr(value_expr, state, false);
|
||||||
@ -284,10 +284,10 @@ 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::Var(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"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Stmt::Import(e, _, _) if !e.is_constant() => Some(i),
|
Stmt::Import(e, ..) if !e.is_constant() => Some(i),
|
||||||
|
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
@ -320,7 +320,7 @@ fn optimize_stmt_block(
|
|||||||
loop {
|
loop {
|
||||||
match statements[..] {
|
match statements[..] {
|
||||||
// { return; } -> {}
|
// { return; } -> {}
|
||||||
[Stmt::Return(options, None, _)]
|
[Stmt::Return(options, None, ..)]
|
||||||
if reduce_return && !options.contains(AST_OPTION_BREAK) =>
|
if reduce_return && !options.contains(AST_OPTION_BREAK) =>
|
||||||
{
|
{
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
@ -331,7 +331,7 @@ fn optimize_stmt_block(
|
|||||||
statements.clear();
|
statements.clear();
|
||||||
}
|
}
|
||||||
// { ...; return; } -> { ... }
|
// { ...; return; } -> { ... }
|
||||||
[.., ref last_stmt, Stmt::Return(options, None, _)]
|
[.., ref last_stmt, Stmt::Return(options, None, ..)]
|
||||||
if reduce_return
|
if reduce_return
|
||||||
&& !options.contains(AST_OPTION_BREAK)
|
&& !options.contains(AST_OPTION_BREAK)
|
||||||
&& !last_stmt.returns_value() =>
|
&& !last_stmt.returns_value() =>
|
||||||
@ -349,7 +349,7 @@ fn optimize_stmt_block(
|
|||||||
.map_or_else(|| Stmt::Noop(pos), |e| Stmt::Expr(mem::take(e)));
|
.map_or_else(|| Stmt::Noop(pos), |e| Stmt::Expr(mem::take(e)));
|
||||||
}
|
}
|
||||||
// { ...; stmt; noop } -> done
|
// { ...; stmt; noop } -> done
|
||||||
[.., ref second_last_stmt, Stmt::Noop(_)]
|
[.., ref second_last_stmt, Stmt::Noop(..)]
|
||||||
if second_last_stmt.returns_value() =>
|
if second_last_stmt.returns_value() =>
|
||||||
{
|
{
|
||||||
break
|
break
|
||||||
@ -377,14 +377,14 @@ fn optimize_stmt_block(
|
|||||||
statements.clear();
|
statements.clear();
|
||||||
}
|
}
|
||||||
// { ...; return; } -> { ... }
|
// { ...; return; } -> { ... }
|
||||||
[.., Stmt::Return(options, None, _)]
|
[.., Stmt::Return(options, None, ..)]
|
||||||
if reduce_return && !options.contains(AST_OPTION_BREAK) =>
|
if reduce_return && !options.contains(AST_OPTION_BREAK) =>
|
||||||
{
|
{
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
statements.pop().unwrap();
|
statements.pop().unwrap();
|
||||||
}
|
}
|
||||||
// { ...; return pure_val; } -> { ... }
|
// { ...; return pure_val; } -> { ... }
|
||||||
[.., Stmt::Return(options, Some(ref expr), _)]
|
[.., Stmt::Return(options, Some(ref expr), ..)]
|
||||||
if reduce_return
|
if reduce_return
|
||||||
&& !options.contains(AST_OPTION_BREAK)
|
&& !options.contains(AST_OPTION_BREAK)
|
||||||
&& expr.is_pure() =>
|
&& expr.is_pure() =>
|
||||||
@ -424,17 +424,17 @@ fn optimize_stmt_block(
|
|||||||
fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: bool) {
|
fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: bool) {
|
||||||
match stmt {
|
match stmt {
|
||||||
// var = var op expr => var op= expr
|
// var = var op expr => var op= expr
|
||||||
Stmt::Assignment(x, _)
|
Stmt::Assignment(x, ..)
|
||||||
if x.0.is_none()
|
if x.0.is_none()
|
||||||
&& x.1.lhs.is_variable_access(true)
|
&& x.1.lhs.is_variable_access(true)
|
||||||
&& matches!(&x.1.rhs, Expr::FnCall(x2, _)
|
&& matches!(&x.1.rhs, Expr::FnCall(x2, ..)
|
||||||
if Token::lookup_from_syntax(&x2.name).map(|t| t.has_op_assignment()).unwrap_or(false)
|
if Token::lookup_from_syntax(&x2.name).map(|t| t.has_op_assignment()).unwrap_or(false)
|
||||||
&& x2.args.len() == 2
|
&& x2.args.len() == 2
|
||||||
&& x2.args[0].get_variable_name(true) == x.1.lhs.get_variable_name(true)
|
&& x2.args[0].get_variable_name(true) == x.1.lhs.get_variable_name(true)
|
||||||
) =>
|
) =>
|
||||||
{
|
{
|
||||||
match x.1.rhs {
|
match x.1.rhs {
|
||||||
Expr::FnCall(ref mut x2, _) => {
|
Expr::FnCall(ref mut x2, ..) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
x.0 = Some(OpAssignment::new_from_base(&x2.name));
|
x.0 = Some(OpAssignment::new_from_base(&x2.name));
|
||||||
|
|
||||||
@ -452,7 +452,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
}
|
}
|
||||||
|
|
||||||
// expr op= expr
|
// expr op= expr
|
||||||
Stmt::Assignment(x, _) => {
|
Stmt::Assignment(x, ..) => {
|
||||||
if !x.1.lhs.is_variable_access(false) {
|
if !x.1.lhs.is_variable_access(false) {
|
||||||
optimize_expr(&mut x.1.lhs, state, false);
|
optimize_expr(&mut x.1.lhs, state, false);
|
||||||
}
|
}
|
||||||
@ -460,7 +460,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if expr {}
|
// if expr {}
|
||||||
Stmt::If(condition, x, _) if x.0.is_empty() && x.1.is_empty() => {
|
Stmt::If(condition, x, ..) if x.0.is_empty() && x.1.is_empty() => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
|
|
||||||
let pos = condition.start_position();
|
let pos = condition.start_position();
|
||||||
@ -479,12 +479,12 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
// if false { if_block } -> Noop
|
// if false { if_block } -> Noop
|
||||||
Stmt::If(Expr::BoolConstant(false, pos), x, _) if x.1.is_empty() => {
|
Stmt::If(Expr::BoolConstant(false, pos), x, ..) if x.1.is_empty() => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*stmt = Stmt::Noop(*pos);
|
*stmt = Stmt::Noop(*pos);
|
||||||
}
|
}
|
||||||
// if false { if_block } else { else_block } -> else_block
|
// if false { if_block } else { else_block } -> else_block
|
||||||
Stmt::If(Expr::BoolConstant(false, _), x, _) => {
|
Stmt::If(Expr::BoolConstant(false, ..), x, ..) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*stmt =
|
*stmt =
|
||||||
match optimize_stmt_block(mem::take(&mut *x.1), state, preserve_result, true, false)
|
match optimize_stmt_block(mem::take(&mut *x.1), state, preserve_result, true, false)
|
||||||
@ -494,7 +494,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if true { if_block } else { else_block } -> if_block
|
// if true { if_block } else { else_block } -> if_block
|
||||||
Stmt::If(Expr::BoolConstant(true, _), x, _) => {
|
Stmt::If(Expr::BoolConstant(true, ..), x, ..) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*stmt =
|
*stmt =
|
||||||
match optimize_stmt_block(mem::take(&mut *x.0), state, preserve_result, true, false)
|
match optimize_stmt_block(mem::take(&mut *x.0), state, preserve_result, true, false)
|
||||||
@ -504,7 +504,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if expr { if_block } else { else_block }
|
// if expr { if_block } else { else_block }
|
||||||
Stmt::If(condition, x, _) => {
|
Stmt::If(condition, x, ..) => {
|
||||||
optimize_expr(condition, state, false);
|
optimize_expr(condition, state, false);
|
||||||
*x.0 = optimize_stmt_block(mem::take(&mut *x.0), state, preserve_result, true, false);
|
*x.0 = optimize_stmt_block(mem::take(&mut *x.0), state, preserve_result, true, false);
|
||||||
*x.1 = optimize_stmt_block(mem::take(&mut *x.1), state, preserve_result, true, false);
|
*x.1 = optimize_stmt_block(mem::take(&mut *x.1), state, preserve_result, true, false);
|
||||||
@ -564,11 +564,11 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
let value = value.as_int().expect("`INT`");
|
let value = value.as_int().expect("`INT`");
|
||||||
|
|
||||||
// Only one range or all ranges without conditions
|
// Only one range or all ranges without conditions
|
||||||
if ranges.len() == 1 || ranges.iter().all(|(_, _, _, c)| !c.has_condition()) {
|
if ranges.len() == 1 || ranges.iter().all(|(.., c)| !c.has_condition()) {
|
||||||
for (_, _, _, block) in
|
for (.., block) in
|
||||||
ranges
|
ranges
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.filter(|&&mut (start, end, inclusive, _)| {
|
.filter(|&&mut (start, end, inclusive, ..)| {
|
||||||
(!inclusive && (start..end).contains(&value))
|
(!inclusive && (start..end).contains(&value))
|
||||||
|| (inclusive && (start..=end).contains(&value))
|
|| (inclusive && (start..=end).contains(&value))
|
||||||
})
|
})
|
||||||
@ -619,7 +619,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
|
|
||||||
let old_ranges_len = ranges.len();
|
let old_ranges_len = ranges.len();
|
||||||
|
|
||||||
ranges.retain(|&mut (start, end, inclusive, _)| {
|
ranges.retain(|&mut (start, end, inclusive, ..)| {
|
||||||
(!inclusive && (start..end).contains(&value))
|
(!inclusive && (start..end).contains(&value))
|
||||||
|| (inclusive && (start..=end).contains(&value))
|
|| (inclusive && (start..=end).contains(&value))
|
||||||
});
|
});
|
||||||
@ -628,7 +628,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (_, _, _, block) in ranges.iter_mut() {
|
for (.., block) in ranges.iter_mut() {
|
||||||
let statements = mem::take(&mut *block.statements);
|
let statements = mem::take(&mut *block.statements);
|
||||||
*block.statements =
|
*block.statements =
|
||||||
optimize_stmt_block(statements, state, preserve_result, true, false);
|
optimize_stmt_block(statements, state, preserve_result, true, false);
|
||||||
@ -636,7 +636,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
if let Some(mut condition) = mem::take(&mut block.condition) {
|
if let Some(mut condition) = mem::take(&mut block.condition) {
|
||||||
optimize_expr(&mut condition, state, false);
|
optimize_expr(&mut condition, state, false);
|
||||||
match condition {
|
match condition {
|
||||||
Expr::Unit(_) | Expr::BoolConstant(true, _) => state.set_dirty(),
|
Expr::Unit(..) | Expr::BoolConstant(true, ..) => state.set_dirty(),
|
||||||
_ => block.condition = Some(condition),
|
_ => block.condition = Some(condition),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -655,7 +655,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
// switch
|
// switch
|
||||||
Stmt::Switch(match_expr, x, _) => {
|
Stmt::Switch(match_expr, x, ..) => {
|
||||||
optimize_expr(match_expr, state, false);
|
optimize_expr(match_expr, state, false);
|
||||||
for block in x.cases.values_mut() {
|
for block in x.cases.values_mut() {
|
||||||
let statements = mem::take(&mut *block.statements);
|
let statements = mem::take(&mut *block.statements);
|
||||||
@ -665,15 +665,15 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
if let Some(mut condition) = mem::take(&mut block.condition) {
|
if let Some(mut condition) = mem::take(&mut block.condition) {
|
||||||
optimize_expr(&mut condition, state, false);
|
optimize_expr(&mut condition, state, false);
|
||||||
match condition {
|
match condition {
|
||||||
Expr::Unit(_) | Expr::BoolConstant(true, _) => state.set_dirty(),
|
Expr::Unit(..) | Expr::BoolConstant(true, ..) => state.set_dirty(),
|
||||||
_ => block.condition = Some(condition),
|
_ => block.condition = Some(condition),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove false cases
|
// Remove false cases
|
||||||
while let Some((&key, _)) = x.cases.iter().find(|(_, block)| match block.condition {
|
while let Some((&key, ..)) = x.cases.iter().find(|(.., block)| match block.condition {
|
||||||
Some(Expr::BoolConstant(false, _)) => true,
|
Some(Expr::BoolConstant(false, ..)) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}) {
|
}) {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
@ -685,12 +685,12 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
}
|
}
|
||||||
|
|
||||||
// while false { block } -> Noop
|
// while false { block } -> Noop
|
||||||
Stmt::While(Expr::BoolConstant(false, pos), _, _) => {
|
Stmt::While(Expr::BoolConstant(false, pos), ..) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*stmt = Stmt::Noop(*pos)
|
*stmt = Stmt::Noop(*pos)
|
||||||
}
|
}
|
||||||
// while expr { block }
|
// while expr { block }
|
||||||
Stmt::While(condition, body, _) => {
|
Stmt::While(condition, body, ..) => {
|
||||||
optimize_expr(condition, state, false);
|
optimize_expr(condition, state, false);
|
||||||
if let Expr::BoolConstant(true, pos) = condition {
|
if let Expr::BoolConstant(true, pos) = condition {
|
||||||
*condition = Expr::Unit(*pos);
|
*condition = Expr::Unit(*pos);
|
||||||
@ -719,7 +719,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// do { block } while false | do { block } until true -> { block }
|
// do { block } while false | do { block } until true -> { block }
|
||||||
Stmt::Do(body, Expr::BoolConstant(x, _), options, _)
|
Stmt::Do(body, Expr::BoolConstant(x, ..), options, ..)
|
||||||
if *x == options.contains(AST_OPTION_NEGATED) =>
|
if *x == options.contains(AST_OPTION_NEGATED) =>
|
||||||
{
|
{
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
@ -730,22 +730,22 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
// do { block } while|until expr
|
// do { block } while|until expr
|
||||||
Stmt::Do(body, condition, _, _) => {
|
Stmt::Do(body, condition, ..) => {
|
||||||
optimize_expr(condition, state, false);
|
optimize_expr(condition, state, false);
|
||||||
***body = optimize_stmt_block(mem::take(&mut **body), state, false, true, false);
|
***body = optimize_stmt_block(mem::take(&mut **body), state, false, true, false);
|
||||||
}
|
}
|
||||||
// for id in expr { block }
|
// for id in expr { block }
|
||||||
Stmt::For(iterable, x, _) => {
|
Stmt::For(iterable, x, ..) => {
|
||||||
optimize_expr(iterable, state, false);
|
optimize_expr(iterable, state, false);
|
||||||
*x.2 = optimize_stmt_block(mem::take(&mut *x.2), state, false, true, false);
|
*x.2 = optimize_stmt_block(mem::take(&mut *x.2), state, false, true, false);
|
||||||
}
|
}
|
||||||
// let id = expr;
|
// let id = expr;
|
||||||
Stmt::Var(expr, _, options, _) if !options.contains(AST_OPTION_CONSTANT) => {
|
Stmt::Var(expr, _, options, ..) if !options.contains(AST_OPTION_CONSTANT) => {
|
||||||
optimize_expr(expr, state, false)
|
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),
|
||||||
// { block }
|
// { block }
|
||||||
Stmt::Block(statements, pos) => {
|
Stmt::Block(statements, pos) => {
|
||||||
let statements = mem::take(statements).into_vec().into();
|
let statements = mem::take(statements).into_vec().into();
|
||||||
@ -765,7 +765,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// try { pure try_block } catch ( var ) { catch_block } -> try_block
|
// try { pure try_block } catch ( var ) { catch_block } -> try_block
|
||||||
Stmt::TryCatch(x, _) if x.try_block.iter().all(Stmt::is_pure) => {
|
Stmt::TryCatch(x, ..) if x.try_block.iter().all(Stmt::is_pure) => {
|
||||||
// If try block is pure, there will never be any exceptions
|
// If try block is pure, there will never be any exceptions
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*stmt = Stmt::Block(
|
*stmt = Stmt::Block(
|
||||||
@ -775,14 +775,14 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
// try { try_block } catch ( var ) { catch_block }
|
// try { try_block } catch ( var ) { catch_block }
|
||||||
Stmt::TryCatch(x, _) => {
|
Stmt::TryCatch(x, ..) => {
|
||||||
*x.try_block =
|
*x.try_block =
|
||||||
optimize_stmt_block(mem::take(&mut *x.try_block), state, false, true, false);
|
optimize_stmt_block(mem::take(&mut *x.try_block), state, false, true, false);
|
||||||
*x.catch_block =
|
*x.catch_block =
|
||||||
optimize_stmt_block(mem::take(&mut *x.catch_block), state, false, true, false);
|
optimize_stmt_block(mem::take(&mut *x.catch_block), state, false, true, false);
|
||||||
}
|
}
|
||||||
// func(...)
|
// func(...)
|
||||||
Stmt::Expr(expr @ Expr::FnCall(_, _)) => {
|
Stmt::Expr(expr @ Expr::FnCall(..)) => {
|
||||||
optimize_expr(expr, state, false);
|
optimize_expr(expr, state, false);
|
||||||
match expr {
|
match expr {
|
||||||
Expr::FnCall(x, pos) => {
|
Expr::FnCall(x, pos) => {
|
||||||
@ -838,31 +838,31 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
|||||||
}
|
}
|
||||||
// lhs.rhs
|
// lhs.rhs
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Dot(x,_, _) if !_chaining => match (&mut x.lhs, &mut x.rhs) {
|
Expr::Dot(x,_, ..) if !_chaining => match (&mut x.lhs, &mut x.rhs) {
|
||||||
// map.string
|
// map.string
|
||||||
(Expr::Map(m, pos), Expr::Property(p, _)) if m.0.iter().all(|(_, x)| x.is_pure()) => {
|
(Expr::Map(m, pos), Expr::Property(p, ..)) if m.0.iter().all(|(.., x)| x.is_pure()) => {
|
||||||
let prop = p.2.as_str();
|
let prop = p.2.as_str();
|
||||||
// Map literal where everything is pure - promote the indexed item.
|
// Map literal where everything is pure - promote the indexed item.
|
||||||
// All other items can be thrown away.
|
// All other items can be thrown away.
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = mem::take(&mut m.0).into_iter().find(|(x, _)| x.name == prop)
|
*expr = mem::take(&mut m.0).into_iter().find(|(x, ..)| x.name == prop)
|
||||||
.map(|(_, mut expr)| { expr.set_position(*pos); expr })
|
.map(|(.., mut expr)| { expr.set_position(*pos); expr })
|
||||||
.unwrap_or_else(|| Expr::Unit(*pos));
|
.unwrap_or_else(|| Expr::Unit(*pos));
|
||||||
}
|
}
|
||||||
// var.rhs
|
// var.rhs
|
||||||
(Expr::Variable(_, _, _), rhs) => optimize_expr(rhs, state, true),
|
(Expr::Variable(..), rhs) => optimize_expr(rhs, state, true),
|
||||||
// lhs.rhs
|
// lhs.rhs
|
||||||
(lhs, rhs) => { optimize_expr(lhs, state, false); optimize_expr(rhs, state, true); }
|
(lhs, rhs) => { optimize_expr(lhs, state, false); optimize_expr(rhs, state, true); }
|
||||||
}
|
}
|
||||||
// ....lhs.rhs
|
// ....lhs.rhs
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Dot(x,_, _) => { optimize_expr(&mut x.lhs, state, false); optimize_expr(&mut x.rhs, state, _chaining); }
|
Expr::Dot(x,_, ..) => { optimize_expr(&mut x.lhs, state, false); optimize_expr(&mut x.rhs, state, _chaining); }
|
||||||
|
|
||||||
// lhs[rhs]
|
// lhs[rhs]
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(x, _, _) if !_chaining => match (&mut x.lhs, &mut x.rhs) {
|
Expr::Index(x, ..) if !_chaining => match (&mut x.lhs, &mut x.rhs) {
|
||||||
// array[int]
|
// array[int]
|
||||||
(Expr::Array(a, pos), Expr::IntegerConstant(i, _)) if *i >= 0 && (*i as usize) < a.len() && a.iter().all(Expr::is_pure) => {
|
(Expr::Array(a, pos), Expr::IntegerConstant(i, ..)) if *i >= 0 && (*i as usize) < a.len() && a.iter().all(Expr::is_pure) => {
|
||||||
// Array literal where everything is pure - promote the indexed item.
|
// Array literal where everything is pure - promote the indexed item.
|
||||||
// All other items can be thrown away.
|
// All other items can be thrown away.
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
@ -871,7 +871,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
|||||||
*expr = result;
|
*expr = result;
|
||||||
}
|
}
|
||||||
// array[-int]
|
// array[-int]
|
||||||
(Expr::Array(a, pos), Expr::IntegerConstant(i, _)) if *i < 0 && i.checked_abs().map(|n| n as usize <= a.len()).unwrap_or(false) && a.iter().all(Expr::is_pure) => {
|
(Expr::Array(a, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.checked_abs().map(|n| n as usize <= a.len()).unwrap_or(false) && a.iter().all(Expr::is_pure) => {
|
||||||
// Array literal where everything is pure - promote the indexed item.
|
// Array literal where everything is pure - promote the indexed item.
|
||||||
// All other items can be thrown away.
|
// All other items can be thrown away.
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
@ -881,58 +881,58 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
|||||||
*expr = result;
|
*expr = result;
|
||||||
}
|
}
|
||||||
// map[string]
|
// map[string]
|
||||||
(Expr::Map(m, pos), Expr::StringConstant(s, _)) if m.0.iter().all(|(_, x)| x.is_pure()) => {
|
(Expr::Map(m, pos), Expr::StringConstant(s, ..)) if m.0.iter().all(|(.., x)| x.is_pure()) => {
|
||||||
// Map literal where everything is pure - promote the indexed item.
|
// Map literal where everything is pure - promote the indexed item.
|
||||||
// All other items can be thrown away.
|
// All other items can be thrown away.
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = mem::take(&mut m.0).into_iter().find(|(x, _)| x.name.as_str() == s.as_str())
|
*expr = mem::take(&mut m.0).into_iter().find(|(x, ..)| x.name.as_str() == s.as_str())
|
||||||
.map(|(_, mut expr)| { expr.set_position(*pos); expr })
|
.map(|(.., mut expr)| { expr.set_position(*pos); expr })
|
||||||
.unwrap_or_else(|| Expr::Unit(*pos));
|
.unwrap_or_else(|| Expr::Unit(*pos));
|
||||||
}
|
}
|
||||||
// int[int]
|
// int[int]
|
||||||
(Expr::IntegerConstant(n, pos), Expr::IntegerConstant(i, _)) if *i >= 0 && (*i as usize) < (std::mem::size_of_val(n) * 8) => {
|
(Expr::IntegerConstant(n, pos), Expr::IntegerConstant(i, ..)) if *i >= 0 && (*i as usize) < (std::mem::size_of_val(n) * 8) => {
|
||||||
// Bit-field literal indexing - get the bit
|
// Bit-field literal indexing - get the bit
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = Expr::BoolConstant((*n & (1 << (*i as usize))) != 0, *pos);
|
*expr = Expr::BoolConstant((*n & (1 << (*i as usize))) != 0, *pos);
|
||||||
}
|
}
|
||||||
// int[-int]
|
// int[-int]
|
||||||
(Expr::IntegerConstant(n, pos), Expr::IntegerConstant(i, _)) if *i < 0 && i.checked_abs().map(|i| i as usize <= (std::mem::size_of_val(n) * 8)).unwrap_or(false) => {
|
(Expr::IntegerConstant(n, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.checked_abs().map(|i| i as usize <= (std::mem::size_of_val(n) * 8)).unwrap_or(false) => {
|
||||||
// Bit-field literal indexing - get the bit
|
// Bit-field literal indexing - get the bit
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = Expr::BoolConstant((*n & (1 << (std::mem::size_of_val(n) * 8 - i.abs() as usize))) != 0, *pos);
|
*expr = Expr::BoolConstant((*n & (1 << (std::mem::size_of_val(n) * 8 - i.abs() as usize))) != 0, *pos);
|
||||||
}
|
}
|
||||||
// string[int]
|
// string[int]
|
||||||
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, _)) if *i >= 0 && (*i as usize) < s.chars().count() => {
|
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, ..)) if *i >= 0 && (*i as usize) < s.chars().count() => {
|
||||||
// String literal indexing - get the character
|
// String literal indexing - get the character
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = Expr::CharConstant(s.chars().nth(*i as usize).unwrap(), *pos);
|
*expr = Expr::CharConstant(s.chars().nth(*i as usize).unwrap(), *pos);
|
||||||
}
|
}
|
||||||
// string[-int]
|
// string[-int]
|
||||||
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, _)) if *i < 0 && i.checked_abs().map(|n| n as usize <= s.chars().count()).unwrap_or(false) => {
|
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.checked_abs().map(|n| n as usize <= s.chars().count()).unwrap_or(false) => {
|
||||||
// String literal indexing - get the character
|
// String literal indexing - get the character
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = Expr::CharConstant(s.chars().rev().nth(i.abs() as usize - 1).unwrap(), *pos);
|
*expr = Expr::CharConstant(s.chars().rev().nth(i.abs() as usize - 1).unwrap(), *pos);
|
||||||
}
|
}
|
||||||
// var[rhs]
|
// var[rhs]
|
||||||
(Expr::Variable(_, _, _), rhs) => optimize_expr(rhs, state, true),
|
(Expr::Variable(..), rhs) => optimize_expr(rhs, state, true),
|
||||||
// lhs[rhs]
|
// lhs[rhs]
|
||||||
(lhs, rhs) => { optimize_expr(lhs, state, false); optimize_expr(rhs, state, true); }
|
(lhs, rhs) => { optimize_expr(lhs, state, false); optimize_expr(rhs, state, true); }
|
||||||
},
|
},
|
||||||
// ...[lhs][rhs]
|
// ...[lhs][rhs]
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(x, _, _) => { optimize_expr(&mut x.lhs, state, false); optimize_expr(&mut x.rhs, state, _chaining); }
|
Expr::Index(x, ..) => { optimize_expr(&mut x.lhs, state, false); optimize_expr(&mut x.rhs, state, _chaining); }
|
||||||
// ``
|
// ``
|
||||||
Expr::InterpolatedString(x, pos) if x.is_empty() => {
|
Expr::InterpolatedString(x, pos) if x.is_empty() => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = Expr::StringConstant(state.engine.const_empty_string(), *pos);
|
*expr = Expr::StringConstant(state.engine.const_empty_string(), *pos);
|
||||||
}
|
}
|
||||||
// `...`
|
// `...`
|
||||||
Expr::InterpolatedString(x, _) if x.len() == 1 && matches!(x[0], Expr::StringConstant(_, _)) => {
|
Expr::InterpolatedString(x, ..) if x.len() == 1 && matches!(x[0], Expr::StringConstant(..)) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = mem::take(&mut x[0]);
|
*expr = mem::take(&mut x[0]);
|
||||||
}
|
}
|
||||||
// `... ${ ... } ...`
|
// `... ${ ... } ...`
|
||||||
Expr::InterpolatedString(x, _) => {
|
Expr::InterpolatedString(x, ..) => {
|
||||||
x.iter_mut().for_each(|expr| optimize_expr(expr, state, false));
|
x.iter_mut().for_each(|expr| optimize_expr(expr, state, false));
|
||||||
|
|
||||||
let mut n = 0;
|
let mut n = 0;
|
||||||
@ -940,11 +940,11 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
|||||||
// Merge consecutive strings
|
// Merge consecutive strings
|
||||||
while n < x.len() - 1 {
|
while n < x.len() - 1 {
|
||||||
match (mem::take(&mut x[n]), mem::take(&mut x[n+1])) {
|
match (mem::take(&mut x[n]), mem::take(&mut x[n+1])) {
|
||||||
(Expr::StringConstant(mut s1, pos), Expr::StringConstant(s2, _)) => { s1 += s2; x[n] = Expr::StringConstant(s1, pos); x.remove(n+1); state.set_dirty(); }
|
(Expr::StringConstant(mut s1, pos), Expr::StringConstant(s2, ..)) => { s1 += s2; x[n] = Expr::StringConstant(s1, pos); x.remove(n+1); state.set_dirty(); }
|
||||||
(expr1, Expr::Unit(_)) => { x[n] = expr1; x.remove(n+1); state.set_dirty(); }
|
(expr1, Expr::Unit(..)) => { x[n] = expr1; x.remove(n+1); state.set_dirty(); }
|
||||||
(Expr::Unit(_), expr2) => { x[n+1] = expr2; x.remove(n); state.set_dirty(); }
|
(Expr::Unit(..), expr2) => { x[n+1] = expr2; x.remove(n); state.set_dirty(); }
|
||||||
(expr1, Expr::StringConstant(s, _)) if s.is_empty() => { x[n] = expr1; x.remove(n+1); state.set_dirty(); }
|
(expr1, Expr::StringConstant(s, ..)) if s.is_empty() => { x[n] = expr1; x.remove(n+1); state.set_dirty(); }
|
||||||
(Expr::StringConstant(s, _), expr2) if s.is_empty()=> { x[n+1] = expr2; x.remove(n); state.set_dirty(); }
|
(Expr::StringConstant(s, ..), expr2) if s.is_empty()=> { x[n+1] = expr2; x.remove(n); state.set_dirty(); }
|
||||||
(expr1, expr2) => { x[n] = expr1; x[n+1] = expr2; n += 1; }
|
(expr1, expr2) => { x[n] = expr1; x[n+1] = expr2; n += 1; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -953,47 +953,47 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
|||||||
}
|
}
|
||||||
// [ constant .. ]
|
// [ constant .. ]
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Array(_, _) if expr.is_constant() => {
|
Expr::Array(..) if expr.is_constant() => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = Expr::DynamicConstant(expr.get_literal_value().unwrap().into(), expr.position());
|
*expr = Expr::DynamicConstant(expr.get_literal_value().unwrap().into(), expr.position());
|
||||||
}
|
}
|
||||||
// [ items .. ]
|
// [ items .. ]
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Array(x, _) => x.iter_mut().for_each(|expr| optimize_expr(expr, state, false)),
|
Expr::Array(x, ..) => x.iter_mut().for_each(|expr| optimize_expr(expr, state, false)),
|
||||||
// #{ key:constant, .. }
|
// #{ key:constant, .. }
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Map(_, _) if expr.is_constant() => {
|
Expr::Map(..) if expr.is_constant() => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = Expr::DynamicConstant(expr.get_literal_value().unwrap().into(), expr.position());
|
*expr = Expr::DynamicConstant(expr.get_literal_value().unwrap().into(), expr.position());
|
||||||
}
|
}
|
||||||
// #{ key:value, .. }
|
// #{ key:value, .. }
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Map(x, _) => x.0.iter_mut().for_each(|(_, expr)| optimize_expr(expr, state, false)),
|
Expr::Map(x, ..) => x.0.iter_mut().for_each(|(.., expr)| optimize_expr(expr, state, false)),
|
||||||
// lhs && rhs
|
// lhs && rhs
|
||||||
Expr::And(x, _) => match (&mut x.lhs, &mut x.rhs) {
|
Expr::And(x, ..) => match (&mut x.lhs, &mut x.rhs) {
|
||||||
// true && rhs -> rhs
|
// true && rhs -> rhs
|
||||||
(Expr::BoolConstant(true, _), rhs) => { state.set_dirty(); optimize_expr(rhs, state, false); *expr = mem::take(rhs); }
|
(Expr::BoolConstant(true, ..), rhs) => { state.set_dirty(); optimize_expr(rhs, state, false); *expr = mem::take(rhs); }
|
||||||
// false && rhs -> false
|
// false && rhs -> false
|
||||||
(Expr::BoolConstant(false, pos), _) => { state.set_dirty(); *expr = Expr::BoolConstant(false, *pos); }
|
(Expr::BoolConstant(false, pos), ..) => { state.set_dirty(); *expr = Expr::BoolConstant(false, *pos); }
|
||||||
// lhs && true -> lhs
|
// lhs && true -> lhs
|
||||||
(lhs, Expr::BoolConstant(true, _)) => { state.set_dirty(); optimize_expr(lhs, state, false); *expr = mem::take(lhs); }
|
(lhs, Expr::BoolConstant(true, ..)) => { state.set_dirty(); optimize_expr(lhs, state, false); *expr = mem::take(lhs); }
|
||||||
// lhs && rhs
|
// lhs && rhs
|
||||||
(lhs, rhs) => { optimize_expr(lhs, state, false); optimize_expr(rhs, state, false); }
|
(lhs, rhs) => { optimize_expr(lhs, state, false); optimize_expr(rhs, state, false); }
|
||||||
},
|
},
|
||||||
// lhs || rhs
|
// lhs || rhs
|
||||||
Expr::Or(ref mut x, _) => match (&mut x.lhs, &mut x.rhs) {
|
Expr::Or(ref mut x, ..) => match (&mut x.lhs, &mut x.rhs) {
|
||||||
// false || rhs -> rhs
|
// false || rhs -> rhs
|
||||||
(Expr::BoolConstant(false, _), rhs) => { state.set_dirty(); optimize_expr(rhs, state, false); *expr = mem::take(rhs); }
|
(Expr::BoolConstant(false, ..), rhs) => { state.set_dirty(); optimize_expr(rhs, state, false); *expr = mem::take(rhs); }
|
||||||
// true || rhs -> true
|
// true || rhs -> true
|
||||||
(Expr::BoolConstant(true, pos), _) => { state.set_dirty(); *expr = Expr::BoolConstant(true, *pos); }
|
(Expr::BoolConstant(true, pos), ..) => { state.set_dirty(); *expr = Expr::BoolConstant(true, *pos); }
|
||||||
// lhs || false
|
// lhs || false
|
||||||
(lhs, Expr::BoolConstant(false, _)) => { state.set_dirty(); optimize_expr(lhs, state, false); *expr = mem::take(lhs); }
|
(lhs, Expr::BoolConstant(false, ..)) => { state.set_dirty(); optimize_expr(lhs, state, false); *expr = mem::take(lhs); }
|
||||||
// lhs || rhs
|
// lhs || rhs
|
||||||
(lhs, rhs) => { optimize_expr(lhs, state, false); optimize_expr(rhs, state, false); }
|
(lhs, rhs) => { optimize_expr(lhs, state, false); optimize_expr(rhs, state, false); }
|
||||||
},
|
},
|
||||||
|
|
||||||
// eval!
|
// eval!
|
||||||
Expr::FnCall(x, _) if x.name == KEYWORD_EVAL => {
|
Expr::FnCall(x, ..) if x.name == KEYWORD_EVAL => {
|
||||||
state.propagate_constants = false;
|
state.propagate_constants = false;
|
||||||
}
|
}
|
||||||
// Fn
|
// Fn
|
||||||
@ -1005,8 +1005,8 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
|||||||
&& x.args[0].is_constant()
|
&& x.args[0].is_constant()
|
||||||
=> {
|
=> {
|
||||||
let fn_name = match x.args[0] {
|
let fn_name = match x.args[0] {
|
||||||
Expr::Stack(slot, _) => x.constants[slot].clone(),
|
Expr::Stack(slot, ..) => x.constants[slot].clone(),
|
||||||
Expr::StringConstant(ref s, _) => s.clone().into(),
|
Expr::StringConstant(ref s, ..) => s.clone().into(),
|
||||||
_ => Dynamic::UNIT
|
_ => Dynamic::UNIT
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1019,7 +1019,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Do not call some special keywords
|
// Do not call some special keywords
|
||||||
Expr::FnCall(x, _) if DONT_EVAL_KEYWORDS.contains(&x.name.as_ref()) => {
|
Expr::FnCall(x, ..) if DONT_EVAL_KEYWORDS.contains(&x.name.as_ref()) => {
|
||||||
x.args.iter_mut().for_each(|a| optimize_expr(a, state, false));
|
x.args.iter_mut().for_each(|a| optimize_expr(a, state, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1031,7 +1031,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
|||||||
//&& !is_valid_identifier(x.name.chars()) // cannot be scripted
|
//&& !is_valid_identifier(x.name.chars()) // cannot be scripted
|
||||||
=> {
|
=> {
|
||||||
let arg_values = &mut x.args.iter().map(|e| match e {
|
let arg_values = &mut x.args.iter().map(|e| match e {
|
||||||
Expr::Stack(slot, _) => x.constants[*slot].clone(),
|
Expr::Stack(slot, ..) => x.constants[*slot].clone(),
|
||||||
_ => e.get_literal_value().unwrap()
|
_ => e.get_literal_value().unwrap()
|
||||||
}).collect::<StaticVec<_>>();
|
}).collect::<StaticVec<_>>();
|
||||||
|
|
||||||
@ -1097,7 +1097,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
|||||||
|
|
||||||
if !has_script_fn {
|
if !has_script_fn {
|
||||||
let arg_values = &mut x.args.iter().map(|e| match e {
|
let arg_values = &mut x.args.iter().map(|e| match e {
|
||||||
Expr::Stack(slot, _) => x.constants[*slot].clone(),
|
Expr::Stack(slot, ..) => x.constants[*slot].clone(),
|
||||||
_ => e.get_literal_value().unwrap()
|
_ => e.get_literal_value().unwrap()
|
||||||
}).collect::<StaticVec<_>>();
|
}).collect::<StaticVec<_>>();
|
||||||
|
|
||||||
@ -1119,7 +1119,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// id(args ..) -> optimize function call arguments
|
// id(args ..) -> optimize function call arguments
|
||||||
Expr::FnCall(x, _) => for arg in x.args.iter_mut() {
|
Expr::FnCall(x, ..) => for arg in x.args.iter_mut() {
|
||||||
optimize_expr(arg, state, false);
|
optimize_expr(arg, state, false);
|
||||||
|
|
||||||
// Move constant arguments
|
// Move constant arguments
|
||||||
@ -1132,15 +1132,15 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
|||||||
|
|
||||||
// constant-name
|
// constant-name
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Expr::Variable(_, _, x) if x.1.is_some() => (),
|
Expr::Variable(.., x) if x.1.is_some() => (),
|
||||||
Expr::Variable(_, pos, x) if state.find_constant(&x.2).is_some() => {
|
Expr::Variable(.., pos, x) if state.find_constant(&x.2).is_some() => {
|
||||||
// Replace constant with value
|
// Replace constant with value
|
||||||
*expr = Expr::from_dynamic(state.find_constant(&x.2).unwrap().clone(), *pos);
|
*expr = Expr::from_dynamic(state.find_constant(&x.2).unwrap().clone(), *pos);
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom syntax
|
// Custom syntax
|
||||||
Expr::Custom(x, _) => {
|
Expr::Custom(x, ..) => {
|
||||||
if x.scope_may_be_changed {
|
if x.scope_may_be_changed {
|
||||||
state.propagate_constants = false;
|
state.propagate_constants = false;
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ pub mod array_functions {
|
|||||||
return Dynamic::UNIT;
|
return Dynamic::UNIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (index, _) = calc_offset_len(array.len(), index, 0);
|
let (index, ..) = calc_offset_len(array.len(), index, 0);
|
||||||
|
|
||||||
if index >= array.len() {
|
if index >= array.len() {
|
||||||
Dynamic::UNIT
|
Dynamic::UNIT
|
||||||
@ -88,7 +88,7 @@ pub mod array_functions {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (index, _) = calc_offset_len(array.len(), index, 0);
|
let (index, ..) = calc_offset_len(array.len(), index, 0);
|
||||||
|
|
||||||
if index < array.len() {
|
if index < array.len() {
|
||||||
array[index] = value;
|
array[index] = value;
|
||||||
@ -182,7 +182,7 @@ pub mod array_functions {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (index, _) = calc_offset_len(array.len(), index, 0);
|
let (index, ..) = calc_offset_len(array.len(), index, 0);
|
||||||
|
|
||||||
if index >= array.len() {
|
if index >= array.len() {
|
||||||
array.push(item);
|
array.push(item);
|
||||||
@ -231,10 +231,11 @@ pub mod array_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let check_sizes = match item.0 {
|
let check_sizes = match item.0 {
|
||||||
crate::types::dynamic::Union::Array(_, _, _)
|
crate::types::dynamic::Union::Array(..) | crate::types::dynamic::Union::Str(..) => {
|
||||||
| crate::types::dynamic::Union::Str(_, _, _) => true,
|
true
|
||||||
|
}
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
crate::types::dynamic::Union::Map(_, _, _) => true,
|
crate::types::dynamic::Union::Map(..) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -651,7 +652,7 @@ pub mod array_functions {
|
|||||||
mapper
|
mapper
|
||||||
.call_raw(&ctx, None, [item.clone()])
|
.call_raw(&ctx, None, [item.clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
ERR::ErrorFunctionNotFound(fn_sig, _)
|
ERR::ErrorFunctionNotFound(fn_sig, ..)
|
||||||
if fn_sig.starts_with(mapper.fn_name()) =>
|
if fn_sig.starts_with(mapper.fn_name()) =>
|
||||||
{
|
{
|
||||||
mapper.call_raw(&ctx, None, [item.clone(), (i as INT).into()])
|
mapper.call_raw(&ctx, None, [item.clone(), (i as INT).into()])
|
||||||
@ -740,7 +741,7 @@ pub mod array_functions {
|
|||||||
if filter
|
if filter
|
||||||
.call_raw(&ctx, None, [item.clone()])
|
.call_raw(&ctx, None, [item.clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
ERR::ErrorFunctionNotFound(fn_sig, _)
|
ERR::ErrorFunctionNotFound(fn_sig, ..)
|
||||||
if fn_sig.starts_with(filter.fn_name()) =>
|
if fn_sig.starts_with(filter.fn_name()) =>
|
||||||
{
|
{
|
||||||
filter.call_raw(&ctx, None, [item.clone(), (i as INT).into()])
|
filter.call_raw(&ctx, None, [item.clone(), (i as INT).into()])
|
||||||
@ -828,7 +829,7 @@ pub mod array_functions {
|
|||||||
if ctx
|
if ctx
|
||||||
.call_fn_raw(OP_EQUALS, true, false, &mut [item, &mut value.clone()])
|
.call_fn_raw(OP_EQUALS, true, false, &mut [item, &mut value.clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
ERR::ErrorFunctionNotFound(ref fn_sig, _) if fn_sig.starts_with(OP_EQUALS) => {
|
ERR::ErrorFunctionNotFound(ref fn_sig, ..) if fn_sig.starts_with(OP_EQUALS) => {
|
||||||
if item.type_id() == value.type_id() {
|
if item.type_id() == value.type_id() {
|
||||||
// No default when comparing same type
|
// No default when comparing same type
|
||||||
Err(err)
|
Err(err)
|
||||||
@ -914,13 +915,13 @@ pub mod array_functions {
|
|||||||
return Ok(-1);
|
return Ok(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (start, _) = calc_offset_len(array.len(), start, 0);
|
let (start, ..) = calc_offset_len(array.len(), start, 0);
|
||||||
|
|
||||||
for (i, item) in array.iter_mut().enumerate().skip(start) {
|
for (i, item) in array.iter_mut().enumerate().skip(start) {
|
||||||
if ctx
|
if ctx
|
||||||
.call_fn_raw(OP_EQUALS, true, false, &mut [item, &mut value.clone()])
|
.call_fn_raw(OP_EQUALS, true, false, &mut [item, &mut value.clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
ERR::ErrorFunctionNotFound(ref fn_sig, _) if fn_sig.starts_with(OP_EQUALS) => {
|
ERR::ErrorFunctionNotFound(ref fn_sig, ..) if fn_sig.starts_with(OP_EQUALS) => {
|
||||||
if item.type_id() == value.type_id() {
|
if item.type_id() == value.type_id() {
|
||||||
// No default when comparing same type
|
// No default when comparing same type
|
||||||
Err(err)
|
Err(err)
|
||||||
@ -1044,13 +1045,13 @@ pub mod array_functions {
|
|||||||
return Ok(-1);
|
return Ok(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (start, _) = calc_offset_len(array.len(), start, 0);
|
let (start, ..) = calc_offset_len(array.len(), start, 0);
|
||||||
|
|
||||||
for (i, item) in array.iter().enumerate().skip(start) {
|
for (i, item) in array.iter().enumerate().skip(start) {
|
||||||
if filter
|
if filter
|
||||||
.call_raw(&ctx, None, [item.clone()])
|
.call_raw(&ctx, None, [item.clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
ERR::ErrorFunctionNotFound(fn_sig, _)
|
ERR::ErrorFunctionNotFound(fn_sig, ..)
|
||||||
if fn_sig.starts_with(filter.fn_name()) =>
|
if fn_sig.starts_with(filter.fn_name()) =>
|
||||||
{
|
{
|
||||||
filter.call_raw(&ctx, None, [item.clone(), (i as INT).into()])
|
filter.call_raw(&ctx, None, [item.clone(), (i as INT).into()])
|
||||||
@ -1149,7 +1150,7 @@ pub mod array_functions {
|
|||||||
if filter
|
if filter
|
||||||
.call_raw(&ctx, None, [item.clone()])
|
.call_raw(&ctx, None, [item.clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
ERR::ErrorFunctionNotFound(fn_sig, _)
|
ERR::ErrorFunctionNotFound(fn_sig, ..)
|
||||||
if fn_sig.starts_with(filter.fn_name()) =>
|
if fn_sig.starts_with(filter.fn_name()) =>
|
||||||
{
|
{
|
||||||
filter.call_raw(&ctx, None, [item.clone(), (i as INT).into()])
|
filter.call_raw(&ctx, None, [item.clone(), (i as INT).into()])
|
||||||
@ -1236,7 +1237,7 @@ pub mod array_functions {
|
|||||||
if !filter
|
if !filter
|
||||||
.call_raw(&ctx, None, [item.clone()])
|
.call_raw(&ctx, None, [item.clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
ERR::ErrorFunctionNotFound(fn_sig, _)
|
ERR::ErrorFunctionNotFound(fn_sig, ..)
|
||||||
if fn_sig.starts_with(filter.fn_name()) =>
|
if fn_sig.starts_with(filter.fn_name()) =>
|
||||||
{
|
{
|
||||||
filter.call_raw(&ctx, None, [item.clone(), (i as INT).into()])
|
filter.call_raw(&ctx, None, [item.clone(), (i as INT).into()])
|
||||||
@ -1486,7 +1487,7 @@ pub mod array_functions {
|
|||||||
result = reducer
|
result = reducer
|
||||||
.call_raw(&ctx, None, [result.clone(), item.clone()])
|
.call_raw(&ctx, None, [result.clone(), item.clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
ERR::ErrorFunctionNotFound(fn_sig, _)
|
ERR::ErrorFunctionNotFound(fn_sig, ..)
|
||||||
if fn_sig.starts_with(reducer.fn_name()) =>
|
if fn_sig.starts_with(reducer.fn_name()) =>
|
||||||
{
|
{
|
||||||
reducer.call_raw(&ctx, None, [result, item, (i as INT).into()])
|
reducer.call_raw(&ctx, None, [result, item, (i as INT).into()])
|
||||||
@ -1648,7 +1649,7 @@ pub mod array_functions {
|
|||||||
result = reducer
|
result = reducer
|
||||||
.call_raw(&ctx, None, [result.clone(), item.clone()])
|
.call_raw(&ctx, None, [result.clone(), item.clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
ERR::ErrorFunctionNotFound(fn_sig, _)
|
ERR::ErrorFunctionNotFound(fn_sig, ..)
|
||||||
if fn_sig.starts_with(reducer.fn_name()) =>
|
if fn_sig.starts_with(reducer.fn_name()) =>
|
||||||
{
|
{
|
||||||
reducer.call_raw(&ctx, None, [result, item, ((len - 1 - i) as INT).into()])
|
reducer.call_raw(&ctx, None, [result, item, ((len - 1 - i) as INT).into()])
|
||||||
@ -1925,7 +1926,7 @@ pub mod array_functions {
|
|||||||
if filter
|
if filter
|
||||||
.call_raw(&ctx, None, [array[x].clone()])
|
.call_raw(&ctx, None, [array[x].clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
ERR::ErrorFunctionNotFound(fn_sig, _)
|
ERR::ErrorFunctionNotFound(fn_sig, ..)
|
||||||
if fn_sig.starts_with(filter.fn_name()) =>
|
if fn_sig.starts_with(filter.fn_name()) =>
|
||||||
{
|
{
|
||||||
filter.call_raw(&ctx, None, [array[x].clone(), (i as INT).into()])
|
filter.call_raw(&ctx, None, [array[x].clone(), (i as INT).into()])
|
||||||
@ -2121,7 +2122,7 @@ pub mod array_functions {
|
|||||||
if !filter
|
if !filter
|
||||||
.call_raw(&ctx, None, [array[x].clone()])
|
.call_raw(&ctx, None, [array[x].clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
ERR::ErrorFunctionNotFound(fn_sig, _)
|
ERR::ErrorFunctionNotFound(fn_sig, ..)
|
||||||
if fn_sig.starts_with(filter.fn_name()) =>
|
if fn_sig.starts_with(filter.fn_name()) =>
|
||||||
{
|
{
|
||||||
filter.call_raw(&ctx, None, [array[x].clone(), (i as INT).into()])
|
filter.call_raw(&ctx, None, [array[x].clone(), (i as INT).into()])
|
||||||
@ -2311,7 +2312,7 @@ pub mod array_functions {
|
|||||||
if !ctx
|
if !ctx
|
||||||
.call_fn_raw(OP_EQUALS, true, false, &mut [a1, a2])
|
.call_fn_raw(OP_EQUALS, true, false, &mut [a1, a2])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
ERR::ErrorFunctionNotFound(ref fn_sig, _) if fn_sig.starts_with(OP_EQUALS) => {
|
ERR::ErrorFunctionNotFound(ref fn_sig, ..) if fn_sig.starts_with(OP_EQUALS) => {
|
||||||
if a1.type_id() == a2.type_id() {
|
if a1.type_id() == a2.type_id() {
|
||||||
// No default when comparing same type
|
// No default when comparing same type
|
||||||
Err(err)
|
Err(err)
|
||||||
|
@ -124,7 +124,7 @@ pub mod blob_functions {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (index, _) = calc_offset_len(blob.len(), index, 0);
|
let (index, ..) = calc_offset_len(blob.len(), index, 0);
|
||||||
|
|
||||||
if index >= blob.len() {
|
if index >= blob.len() {
|
||||||
0
|
0
|
||||||
@ -162,7 +162,7 @@ pub mod blob_functions {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (index, _) = calc_offset_len(blob.len(), index, 0);
|
let (index, ..) = calc_offset_len(blob.len(), index, 0);
|
||||||
|
|
||||||
if index < blob.len() {
|
if index < blob.len() {
|
||||||
blob[index] = (value & 0x000000ff) as u8;
|
blob[index] = (value & 0x000000ff) as u8;
|
||||||
@ -256,7 +256,7 @@ pub mod blob_functions {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (index, _) = calc_offset_len(blob.len(), index, 0);
|
let (index, ..) = calc_offset_len(blob.len(), index, 0);
|
||||||
|
|
||||||
if index >= blob.len() {
|
if index >= blob.len() {
|
||||||
blob.push(value);
|
blob.push(value);
|
||||||
|
@ -152,7 +152,7 @@ fn collect_fn_metadata(
|
|||||||
ctx.iter_namespaces()
|
ctx.iter_namespaces()
|
||||||
.flat_map(Module::iter_script_fn)
|
.flat_map(Module::iter_script_fn)
|
||||||
.filter(|(s, a, n, p, f)| filter(*s, *a, n, *p, f))
|
.filter(|(s, a, n, p, f)| filter(*s, *a, n, *p, f))
|
||||||
.for_each(|(_, _, _, _, f)| {
|
.for_each(|(.., f)| {
|
||||||
list.push(
|
list.push(
|
||||||
make_metadata(
|
make_metadata(
|
||||||
&dict,
|
&dict,
|
||||||
@ -169,7 +169,7 @@ fn collect_fn_metadata(
|
|||||||
.iter()
|
.iter()
|
||||||
.flat_map(|m| m.iter_script_fn())
|
.flat_map(|m| m.iter_script_fn())
|
||||||
.filter(|(ns, a, n, p, f)| filter(*ns, *a, n, *p, f))
|
.filter(|(ns, a, n, p, f)| filter(*ns, *a, n, *p, f))
|
||||||
.for_each(|(_, _, _, _, f)| {
|
.for_each(|(.., f)| {
|
||||||
list.push(
|
list.push(
|
||||||
make_metadata(
|
make_metadata(
|
||||||
&dict,
|
&dict,
|
||||||
@ -187,7 +187,7 @@ fn collect_fn_metadata(
|
|||||||
.values()
|
.values()
|
||||||
.flat_map(|m| m.iter_script_fn())
|
.flat_map(|m| m.iter_script_fn())
|
||||||
.filter(|(ns, a, n, p, f)| filter(*ns, *a, n, *p, f))
|
.filter(|(ns, a, n, p, f)| filter(*ns, *a, n, *p, f))
|
||||||
.for_each(|(_, _, _, _, f)| {
|
.for_each(|(.., f)| {
|
||||||
list.push(
|
list.push(
|
||||||
make_metadata(
|
make_metadata(
|
||||||
&dict,
|
&dict,
|
||||||
@ -219,7 +219,7 @@ fn collect_fn_metadata(
|
|||||||
module
|
module
|
||||||
.iter_script_fn()
|
.iter_script_fn()
|
||||||
.filter(|(s, a, n, p, f)| filter(*s, *a, n, *p, f))
|
.filter(|(s, a, n, p, f)| filter(*s, *a, n, *p, f))
|
||||||
.for_each(|(_, _, _, _, f)| {
|
.for_each(|(.., f)| {
|
||||||
list.push(make_metadata(dict, Some(namespace.clone()), f).into())
|
list.push(make_metadata(dict, Some(namespace.clone()), f).into())
|
||||||
});
|
});
|
||||||
for (ns, m) in module.iter_sub_modules() {
|
for (ns, m) in module.iter_sub_modules() {
|
||||||
|
424
src/parser.rs
424
src/parser.rs
File diff suppressed because it is too large
Load Diff
40
src/reify.rs
Normal file
40
src/reify.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/// Runs `$code` if `$old` is of type `$t`.
|
||||||
|
///
|
||||||
|
/// This macro is primarily used for type casting between known types.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! reify {
|
||||||
|
($old:ident, |$new:ident : $t:ty| $code:expr, || $fallback:expr) => {{
|
||||||
|
if std::any::TypeId::of::<$t>() == std::any::Any::type_id(&$old) {
|
||||||
|
// SAFETY: This is safe because we check to make sure the two types are
|
||||||
|
// actually the same type.
|
||||||
|
let $new: $t = unsafe { std::mem::transmute_copy(&std::mem::ManuallyDrop::new($old)) };
|
||||||
|
$code
|
||||||
|
} else {
|
||||||
|
$fallback
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
($old:expr, |$new:ident : $t:ty| $code:expr, || $fallback:expr) => {{
|
||||||
|
let old = $old;
|
||||||
|
reify!(old, |$new: $t| $code, || $fallback)
|
||||||
|
}};
|
||||||
|
($old:ident, |$new:ident : $t:ty| $code:expr) => {
|
||||||
|
reify!($old, |$new: $t| $code, || ())
|
||||||
|
};
|
||||||
|
($old:expr, |$new:ident : $t:ty| $code:expr) => {
|
||||||
|
reify!($old, |$new: $t| $code, || ())
|
||||||
|
};
|
||||||
|
|
||||||
|
($old:ident => Option<$t:ty>) => {
|
||||||
|
reify!($old, |v: $t| Some(v), || None)
|
||||||
|
};
|
||||||
|
($old:expr => Option<$t:ty>) => {
|
||||||
|
reify!($old, |v: $t| Some(v), || None)
|
||||||
|
};
|
||||||
|
|
||||||
|
($old:ident => $t:ty) => {
|
||||||
|
reify!($old, |v: $t| v, || unreachable!())
|
||||||
|
};
|
||||||
|
($old:expr => $t:ty) => {
|
||||||
|
reify!($old, |v: $t| v, || unreachable!())
|
||||||
|
};
|
||||||
|
}
|
@ -118,55 +118,55 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
match self.value.0 {
|
match self.value.0 {
|
||||||
Union::Unit(_, _, _) => self.deserialize_unit(visitor),
|
Union::Unit(..) => self.deserialize_unit(visitor),
|
||||||
Union::Bool(_, _, _) => self.deserialize_bool(visitor),
|
Union::Bool(..) => self.deserialize_bool(visitor),
|
||||||
Union::Str(_, _, _) => self.deserialize_str(visitor),
|
Union::Str(..) => self.deserialize_str(visitor),
|
||||||
Union::Char(_, _, _) => self.deserialize_char(visitor),
|
Union::Char(..) => self.deserialize_char(visitor),
|
||||||
|
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
Union::Int(_, _, _) => self.deserialize_i64(visitor),
|
Union::Int(..) => self.deserialize_i64(visitor),
|
||||||
#[cfg(feature = "only_i32")]
|
#[cfg(feature = "only_i32")]
|
||||||
Union::Int(_, _, _) => self.deserialize_i32(visitor),
|
Union::Int(..) => self.deserialize_i32(visitor),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[cfg(not(feature = "f32_float"))]
|
#[cfg(not(feature = "f32_float"))]
|
||||||
Union::Float(_, _, _) => self.deserialize_f64(visitor),
|
Union::Float(..) => self.deserialize_f64(visitor),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[cfg(feature = "f32_float")]
|
#[cfg(feature = "f32_float")]
|
||||||
Union::Float(_, _, _) => self.deserialize_f32(visitor),
|
Union::Float(..) => self.deserialize_f32(visitor),
|
||||||
|
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
#[cfg(not(feature = "f32_float"))]
|
#[cfg(not(feature = "f32_float"))]
|
||||||
Union::Decimal(_, _, _) => self.deserialize_f64(visitor),
|
Union::Decimal(..) => self.deserialize_f64(visitor),
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
#[cfg(feature = "f32_float")]
|
#[cfg(feature = "f32_float")]
|
||||||
Union::Decimal(_, _, _) => self.deserialize_f32(visitor),
|
Union::Decimal(..) => self.deserialize_f32(visitor),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(_, _, _) => self.deserialize_seq(visitor),
|
Union::Array(..) => self.deserialize_seq(visitor),
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Blob(_, _, _) => self.deserialize_bytes(visitor),
|
Union::Blob(..) => self.deserialize_bytes(visitor),
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(_, _, _) => self.deserialize_map(visitor),
|
Union::Map(..) => self.deserialize_map(visitor),
|
||||||
Union::FnPtr(_, _, _) => self.type_error(),
|
Union::FnPtr(..) => self.type_error(),
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
Union::TimeStamp(_, _, _) => self.type_error(),
|
Union::TimeStamp(..) => self.type_error(),
|
||||||
|
|
||||||
Union::Variant(ref value, _, _) if value.is::<i8>() => self.deserialize_i8(visitor),
|
Union::Variant(ref value, ..) if value.is::<i8>() => self.deserialize_i8(visitor),
|
||||||
Union::Variant(ref value, _, _) if value.is::<i16>() => self.deserialize_i16(visitor),
|
Union::Variant(ref value, ..) if value.is::<i16>() => self.deserialize_i16(visitor),
|
||||||
Union::Variant(ref value, _, _) if value.is::<i32>() => self.deserialize_i32(visitor),
|
Union::Variant(ref value, ..) if value.is::<i32>() => self.deserialize_i32(visitor),
|
||||||
Union::Variant(ref value, _, _) if value.is::<i64>() => self.deserialize_i64(visitor),
|
Union::Variant(ref value, ..) if value.is::<i64>() => self.deserialize_i64(visitor),
|
||||||
Union::Variant(ref value, _, _) if value.is::<i128>() => self.deserialize_i128(visitor),
|
Union::Variant(ref value, ..) if value.is::<i128>() => self.deserialize_i128(visitor),
|
||||||
Union::Variant(ref value, _, _) if value.is::<u8>() => self.deserialize_u8(visitor),
|
Union::Variant(ref value, ..) if value.is::<u8>() => self.deserialize_u8(visitor),
|
||||||
Union::Variant(ref value, _, _) if value.is::<u16>() => self.deserialize_u16(visitor),
|
Union::Variant(ref value, ..) if value.is::<u16>() => self.deserialize_u16(visitor),
|
||||||
Union::Variant(ref value, _, _) if value.is::<u32>() => self.deserialize_u32(visitor),
|
Union::Variant(ref value, ..) if value.is::<u32>() => self.deserialize_u32(visitor),
|
||||||
Union::Variant(ref value, _, _) if value.is::<u64>() => self.deserialize_u64(visitor),
|
Union::Variant(ref value, ..) if value.is::<u64>() => self.deserialize_u64(visitor),
|
||||||
Union::Variant(ref value, _, _) if value.is::<u128>() => self.deserialize_u128(visitor),
|
Union::Variant(ref value, ..) if value.is::<u128>() => self.deserialize_u128(visitor),
|
||||||
|
|
||||||
Union::Variant(_, _, _) => self.type_error(),
|
Union::Variant(..) => self.type_error(),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(_, _, _) => self.type_error(),
|
Union::Shared(..) => self.type_error(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,26 +15,26 @@ use crate::types::dynamic::Variant;
|
|||||||
impl Serialize for Dynamic {
|
impl Serialize for Dynamic {
|
||||||
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
|
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Unit(_, _, _) => ser.serialize_unit(),
|
Union::Unit(..) => ser.serialize_unit(),
|
||||||
Union::Bool(x, _, _) => ser.serialize_bool(x),
|
Union::Bool(x, ..) => ser.serialize_bool(x),
|
||||||
Union::Str(ref s, _, _) => ser.serialize_str(s.as_str()),
|
Union::Str(ref s, ..) => ser.serialize_str(s.as_str()),
|
||||||
Union::Char(c, _, _) => ser.serialize_str(&c.to_string()),
|
Union::Char(c, ..) => ser.serialize_str(&c.to_string()),
|
||||||
|
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
Union::Int(x, _, _) => ser.serialize_i64(x),
|
Union::Int(x, ..) => ser.serialize_i64(x),
|
||||||
#[cfg(feature = "only_i32")]
|
#[cfg(feature = "only_i32")]
|
||||||
Union::Int(x, _, _) => ser.serialize_i32(x),
|
Union::Int(x, ..) => ser.serialize_i32(x),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[cfg(not(feature = "f32_float"))]
|
#[cfg(not(feature = "f32_float"))]
|
||||||
Union::Float(x, _, _) => ser.serialize_f64(*x),
|
Union::Float(x, ..) => ser.serialize_f64(*x),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[cfg(feature = "f32_float")]
|
#[cfg(feature = "f32_float")]
|
||||||
Union::Float(x, _, _) => ser.serialize_f32(*x),
|
Union::Float(x, ..) => ser.serialize_f32(*x),
|
||||||
|
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
#[cfg(not(feature = "f32_float"))]
|
#[cfg(not(feature = "f32_float"))]
|
||||||
Union::Decimal(ref x, _, _) => {
|
Union::Decimal(ref x, ..) => {
|
||||||
use rust_decimal::prelude::ToPrimitive;
|
use rust_decimal::prelude::ToPrimitive;
|
||||||
|
|
||||||
if let Some(v) = x.to_f64() {
|
if let Some(v) = x.to_f64() {
|
||||||
@ -45,7 +45,7 @@ impl Serialize for Dynamic {
|
|||||||
}
|
}
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
#[cfg(feature = "f32_float")]
|
#[cfg(feature = "f32_float")]
|
||||||
Union::Decimal(ref x, _, _) => {
|
Union::Decimal(ref x, ..) => {
|
||||||
use rust_decimal::prelude::ToPrimitive;
|
use rust_decimal::prelude::ToPrimitive;
|
||||||
|
|
||||||
if let Some(v) = x.to_f32() {
|
if let Some(v) = x.to_f32() {
|
||||||
@ -56,28 +56,28 @@ impl Serialize for Dynamic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(ref a, _, _) => (**a).serialize(ser),
|
Union::Array(ref a, ..) => (**a).serialize(ser),
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Blob(ref a, _, _) => (**a).serialize(ser),
|
Union::Blob(ref a, ..) => (**a).serialize(ser),
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(ref m, _, _) => {
|
Union::Map(ref m, ..) => {
|
||||||
let mut map = ser.serialize_map(Some(m.len()))?;
|
let mut map = ser.serialize_map(Some(m.len()))?;
|
||||||
m.iter()
|
m.iter()
|
||||||
.try_for_each(|(k, v)| map.serialize_entry(k.as_str(), v))?;
|
.try_for_each(|(k, v)| map.serialize_entry(k.as_str(), v))?;
|
||||||
map.end()
|
map.end()
|
||||||
}
|
}
|
||||||
Union::FnPtr(ref f, _, _) => ser.serialize_str(f.fn_name()),
|
Union::FnPtr(ref f, ..) => ser.serialize_str(f.fn_name()),
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
Union::TimeStamp(ref x, _, _) => ser.serialize_str(x.as_ref().type_name()),
|
Union::TimeStamp(ref x, ..) => ser.serialize_str(x.as_ref().type_name()),
|
||||||
|
|
||||||
Union::Variant(ref v, _, _) => ser.serialize_str((***v).type_name()),
|
Union::Variant(ref v, ..) => ser.serialize_str((***v).type_name()),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
Union::Shared(ref cell, _, _) => cell.borrow().serialize(ser),
|
Union::Shared(ref cell, ..) => cell.borrow().serialize(ser),
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
Union::Shared(ref cell, _, _) => cell.read().unwrap().serialize(ser),
|
Union::Shared(ref cell, ..) => cell.read().unwrap().serialize(ser),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -603,8 +603,8 @@ impl Token {
|
|||||||
FloatConstant(f) => f.to_string().into(),
|
FloatConstant(f) => f.to_string().into(),
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
DecimalConstant(d) => d.to_string().into(),
|
DecimalConstant(d) => d.to_string().into(),
|
||||||
StringConstant(_) => "string".into(),
|
StringConstant(..) => "string".into(),
|
||||||
InterpolatedString(_) => "string".into(),
|
InterpolatedString(..) => "string".into(),
|
||||||
CharConstant(c) => c.to_string().into(),
|
CharConstant(c) => c.to_string().into(),
|
||||||
Identifier(s) => s.to_string().into(),
|
Identifier(s) => s.to_string().into(),
|
||||||
Reserved(s) => s.to_string().into(),
|
Reserved(s) => s.to_string().into(),
|
||||||
@ -825,7 +825,7 @@ impl Token {
|
|||||||
use Token::*;
|
use Token::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
LexError(_) |
|
LexError(..) |
|
||||||
SemiColon | // ; - is unary
|
SemiColon | // ; - is unary
|
||||||
Colon | // #{ foo: - is unary
|
Colon | // #{ foo: - is unary
|
||||||
Comma | // ( ... , -expr ) - is unary
|
Comma | // ( ... , -expr ) - is unary
|
||||||
@ -970,7 +970,7 @@ impl Token {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_reserved(&self) -> bool {
|
pub const fn is_reserved(&self) -> bool {
|
||||||
matches!(self, Self::Reserved(_))
|
matches!(self, Self::Reserved(..))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a token into a function name, if possible.
|
/// Convert a token into a function name, if possible.
|
||||||
@ -987,7 +987,7 @@ impl Token {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_custom(&self) -> bool {
|
pub const fn is_custom(&self) -> bool {
|
||||||
matches!(self, Self::Custom(_))
|
matches!(self, Self::Custom(..))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1332,7 +1332,7 @@ pub fn get_next_token(
|
|||||||
let result = get_next_token_inner(stream, state, pos);
|
let result = get_next_token_inner(stream, state, pos);
|
||||||
|
|
||||||
// Save the last token's state
|
// Save the last token's state
|
||||||
if let Some((ref token, _)) = result {
|
if let Some((ref token, ..)) = result {
|
||||||
state.next_token_cannot_be_unary = !token.is_next_unary();
|
state.next_token_cannot_be_unary = !token.is_next_unary();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1420,10 +1420,10 @@ fn get_next_token_inner(
|
|||||||
|
|
||||||
match (c, stream.peek_next().unwrap_or('\0')) {
|
match (c, stream.peek_next().unwrap_or('\0')) {
|
||||||
// \n
|
// \n
|
||||||
('\n', _) => pos.new_line(),
|
('\n', ..) => pos.new_line(),
|
||||||
|
|
||||||
// digit ...
|
// digit ...
|
||||||
('0'..='9', _) => {
|
('0'..='9', ..) => {
|
||||||
let mut result = smallvec::SmallVec::<[char; 16]>::new();
|
let mut result = smallvec::SmallVec::<[char; 16]>::new();
|
||||||
let mut radix_base: Option<u32> = None;
|
let mut radix_base: Option<u32> = None;
|
||||||
let mut valid: fn(char) -> bool = is_numeric_digit;
|
let mut valid: fn(char) -> bool = is_numeric_digit;
|
||||||
@ -1573,24 +1573,24 @@ fn get_next_token_inner(
|
|||||||
|
|
||||||
// letter or underscore ...
|
// letter or underscore ...
|
||||||
#[cfg(not(feature = "unicode-xid-ident"))]
|
#[cfg(not(feature = "unicode-xid-ident"))]
|
||||||
('a'..='z', _) | ('_', _) | ('A'..='Z', _) => {
|
('a'..='z', ..) | ('_', ..) | ('A'..='Z', ..) => {
|
||||||
return get_identifier(stream, pos, start_pos, c);
|
return get_identifier(stream, pos, start_pos, c);
|
||||||
}
|
}
|
||||||
#[cfg(feature = "unicode-xid-ident")]
|
#[cfg(feature = "unicode-xid-ident")]
|
||||||
(ch, _) if unicode_xid::UnicodeXID::is_xid_start(ch) || ch == '_' => {
|
(ch, ..) if unicode_xid::UnicodeXID::is_xid_start(ch) || ch == '_' => {
|
||||||
return get_identifier(stream, pos, start_pos, c);
|
return get_identifier(stream, pos, start_pos, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// " - string literal
|
// " - string literal
|
||||||
('"', _) => {
|
('"', ..) => {
|
||||||
return parse_string_literal(stream, state, pos, c, false, true, false)
|
return parse_string_literal(stream, state, pos, c, false, true, false)
|
||||||
.map_or_else(
|
.map_or_else(
|
||||||
|(err, err_pos)| Some((Token::LexError(err), err_pos)),
|
|(err, err_pos)| Some((Token::LexError(err), err_pos)),
|
||||||
|(result, _)| Some((Token::StringConstant(result), start_pos)),
|
|(result, ..)| Some((Token::StringConstant(result), start_pos)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// ` - string literal
|
// ` - string literal
|
||||||
('`', _) => {
|
('`', ..) => {
|
||||||
// Start from the next line if at the end of line
|
// Start from the next line if at the end of line
|
||||||
match stream.peek_next() {
|
match stream.peek_next() {
|
||||||
// `\r - start from next line
|
// `\r - start from next line
|
||||||
@ -1629,11 +1629,11 @@ fn get_next_token_inner(
|
|||||||
start_pos,
|
start_pos,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
('\'', _) => {
|
('\'', ..) => {
|
||||||
return Some(
|
return Some(
|
||||||
parse_string_literal(stream, state, pos, c, false, false, false).map_or_else(
|
parse_string_literal(stream, state, pos, c, false, false, false).map_or_else(
|
||||||
|(err, err_pos)| (Token::LexError(err), err_pos),
|
|(err, err_pos)| (Token::LexError(err), err_pos),
|
||||||
|(result, _)| {
|
|(result, ..)| {
|
||||||
let mut chars = result.chars();
|
let mut chars = result.chars();
|
||||||
let first = chars.next().unwrap();
|
let first = chars.next().unwrap();
|
||||||
|
|
||||||
@ -1651,20 +1651,20 @@ fn get_next_token_inner(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Braces
|
// Braces
|
||||||
('{', _) => return Some((Token::LeftBrace, start_pos)),
|
('{', ..) => return Some((Token::LeftBrace, start_pos)),
|
||||||
('}', _) => return Some((Token::RightBrace, start_pos)),
|
('}', ..) => return Some((Token::RightBrace, start_pos)),
|
||||||
|
|
||||||
// Parentheses
|
// Parentheses
|
||||||
('(', '*') => {
|
('(', '*') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::Reserved("(*".into()), start_pos));
|
return Some((Token::Reserved("(*".into()), start_pos));
|
||||||
}
|
}
|
||||||
('(', _) => return Some((Token::LeftParen, start_pos)),
|
('(', ..) => return Some((Token::LeftParen, start_pos)),
|
||||||
(')', _) => return Some((Token::RightParen, start_pos)),
|
(')', ..) => return Some((Token::RightParen, start_pos)),
|
||||||
|
|
||||||
// Indexing
|
// Indexing
|
||||||
('[', _) => return Some((Token::LeftBracket, start_pos)),
|
('[', ..) => return Some((Token::LeftBracket, start_pos)),
|
||||||
(']', _) => return Some((Token::RightBracket, start_pos)),
|
(']', ..) => return Some((Token::RightBracket, start_pos)),
|
||||||
|
|
||||||
// Map literal
|
// Map literal
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
@ -1686,7 +1686,7 @@ fn get_next_token_inner(
|
|||||||
return Some((Token::Reserved(token.into()), start_pos));
|
return Some((Token::Reserved(token.into()), start_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
('#', _) => return Some((Token::Reserved("#".into()), start_pos)),
|
('#', ..) => return Some((Token::Reserved("#".into()), start_pos)),
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
('+', '=') => {
|
('+', '=') => {
|
||||||
@ -1697,10 +1697,10 @@ fn get_next_token_inner(
|
|||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::Reserved("++".into()), start_pos));
|
return Some((Token::Reserved("++".into()), start_pos));
|
||||||
}
|
}
|
||||||
('+', _) if !state.next_token_cannot_be_unary => {
|
('+', ..) if !state.next_token_cannot_be_unary => {
|
||||||
return Some((Token::UnaryPlus, start_pos))
|
return Some((Token::UnaryPlus, start_pos))
|
||||||
}
|
}
|
||||||
('+', _) => return Some((Token::Plus, start_pos)),
|
('+', ..) => return Some((Token::Plus, start_pos)),
|
||||||
|
|
||||||
('-', '0'..='9') if !state.next_token_cannot_be_unary => negated = Some(start_pos),
|
('-', '0'..='9') if !state.next_token_cannot_be_unary => negated = Some(start_pos),
|
||||||
('-', '0'..='9') => return Some((Token::Minus, start_pos)),
|
('-', '0'..='9') => return Some((Token::Minus, start_pos)),
|
||||||
@ -1716,10 +1716,10 @@ fn get_next_token_inner(
|
|||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::Reserved("--".into()), start_pos));
|
return Some((Token::Reserved("--".into()), start_pos));
|
||||||
}
|
}
|
||||||
('-', _) if !state.next_token_cannot_be_unary => {
|
('-', ..) if !state.next_token_cannot_be_unary => {
|
||||||
return Some((Token::UnaryMinus, start_pos))
|
return Some((Token::UnaryMinus, start_pos))
|
||||||
}
|
}
|
||||||
('-', _) => return Some((Token::Minus, start_pos)),
|
('-', ..) => return Some((Token::Minus, start_pos)),
|
||||||
|
|
||||||
('*', ')') => {
|
('*', ')') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
@ -1742,7 +1742,7 @@ fn get_next_token_inner(
|
|||||||
start_pos,
|
start_pos,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
('*', _) => return Some((Token::Multiply, start_pos)),
|
('*', ..) => return Some((Token::Multiply, start_pos)),
|
||||||
|
|
||||||
// Comments
|
// Comments
|
||||||
('/', '/') => {
|
('/', '/') => {
|
||||||
@ -1819,10 +1819,10 @@ fn get_next_token_inner(
|
|||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::DivideAssign, start_pos));
|
return Some((Token::DivideAssign, start_pos));
|
||||||
}
|
}
|
||||||
('/', _) => return Some((Token::Divide, start_pos)),
|
('/', ..) => return Some((Token::Divide, start_pos)),
|
||||||
|
|
||||||
(';', _) => return Some((Token::SemiColon, start_pos)),
|
(';', ..) => return Some((Token::SemiColon, start_pos)),
|
||||||
(',', _) => return Some((Token::Comma, start_pos)),
|
(',', ..) => return Some((Token::Comma, start_pos)),
|
||||||
|
|
||||||
('.', '.') => {
|
('.', '.') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
@ -1841,7 +1841,7 @@ fn get_next_token_inner(
|
|||||||
start_pos,
|
start_pos,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
('.', _) => return Some((Token::Period, start_pos)),
|
('.', ..) => return Some((Token::Period, start_pos)),
|
||||||
|
|
||||||
('=', '=') => {
|
('=', '=') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
@ -1857,7 +1857,7 @@ fn get_next_token_inner(
|
|||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::DoubleArrow, start_pos));
|
return Some((Token::DoubleArrow, start_pos));
|
||||||
}
|
}
|
||||||
('=', _) => return Some((Token::Equals, start_pos)),
|
('=', ..) => return Some((Token::Equals, start_pos)),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
(':', ':') => {
|
(':', ':') => {
|
||||||
@ -1878,7 +1878,7 @@ fn get_next_token_inner(
|
|||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::Reserved(":;".into()), start_pos));
|
return Some((Token::Reserved(":;".into()), start_pos));
|
||||||
}
|
}
|
||||||
(':', _) => return Some((Token::Colon, start_pos)),
|
(':', ..) => return Some((Token::Colon, start_pos)),
|
||||||
|
|
||||||
('<', '=') => {
|
('<', '=') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
@ -1901,7 +1901,7 @@ fn get_next_token_inner(
|
|||||||
start_pos,
|
start_pos,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
('<', _) => return Some((Token::LessThan, start_pos)),
|
('<', ..) => return Some((Token::LessThan, start_pos)),
|
||||||
|
|
||||||
('>', '=') => {
|
('>', '=') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
@ -1920,7 +1920,7 @@ fn get_next_token_inner(
|
|||||||
start_pos,
|
start_pos,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
('>', _) => return Some((Token::GreaterThan, start_pos)),
|
('>', ..) => return Some((Token::GreaterThan, start_pos)),
|
||||||
|
|
||||||
('!', '=') => {
|
('!', '=') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
@ -1932,7 +1932,7 @@ fn get_next_token_inner(
|
|||||||
|
|
||||||
return Some((Token::NotEqualsTo, start_pos));
|
return Some((Token::NotEqualsTo, start_pos));
|
||||||
}
|
}
|
||||||
('!', _) => return Some((Token::Bang, start_pos)),
|
('!', ..) => return Some((Token::Bang, start_pos)),
|
||||||
|
|
||||||
('|', '|') => {
|
('|', '|') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
@ -1942,7 +1942,7 @@ fn get_next_token_inner(
|
|||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::OrAssign, start_pos));
|
return Some((Token::OrAssign, start_pos));
|
||||||
}
|
}
|
||||||
('|', _) => return Some((Token::Pipe, start_pos)),
|
('|', ..) => return Some((Token::Pipe, start_pos)),
|
||||||
|
|
||||||
('&', '&') => {
|
('&', '&') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
@ -1952,29 +1952,29 @@ fn get_next_token_inner(
|
|||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::AndAssign, start_pos));
|
return Some((Token::AndAssign, start_pos));
|
||||||
}
|
}
|
||||||
('&', _) => return Some((Token::Ampersand, start_pos)),
|
('&', ..) => return Some((Token::Ampersand, start_pos)),
|
||||||
|
|
||||||
('^', '=') => {
|
('^', '=') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::XOrAssign, start_pos));
|
return Some((Token::XOrAssign, start_pos));
|
||||||
}
|
}
|
||||||
('^', _) => return Some((Token::XOr, start_pos)),
|
('^', ..) => return Some((Token::XOr, start_pos)),
|
||||||
|
|
||||||
('~', _) => return Some((Token::Reserved("~".into()), start_pos)),
|
('~', ..) => return Some((Token::Reserved("~".into()), start_pos)),
|
||||||
|
|
||||||
('%', '=') => {
|
('%', '=') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::ModuloAssign, start_pos));
|
return Some((Token::ModuloAssign, start_pos));
|
||||||
}
|
}
|
||||||
('%', _) => return Some((Token::Modulo, start_pos)),
|
('%', ..) => return Some((Token::Modulo, start_pos)),
|
||||||
|
|
||||||
('@', _) => return Some((Token::Reserved("@".into()), start_pos)),
|
('@', ..) => return Some((Token::Reserved("@".into()), start_pos)),
|
||||||
|
|
||||||
('$', _) => return Some((Token::Reserved("$".into()), start_pos)),
|
('$', ..) => return Some((Token::Reserved("$".into()), start_pos)),
|
||||||
|
|
||||||
(ch, _) if ch.is_whitespace() => (),
|
(ch, ..) if ch.is_whitespace() => (),
|
||||||
|
|
||||||
(ch, _) => {
|
(ch, ..) => {
|
||||||
return Some((
|
return Some((
|
||||||
Token::LexError(LERR::UnexpectedInput(ch.to_string())),
|
Token::LexError(LERR::UnexpectedInput(ch.to_string())),
|
||||||
start_pos,
|
start_pos,
|
||||||
@ -2197,7 +2197,7 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||||||
// a verbatim string or a string with continuation encounters {EOF}.
|
// a verbatim string or a string with continuation encounters {EOF}.
|
||||||
// This is necessary to handle such cases for line-by-line parsing, but for an entire
|
// This is necessary to handle such cases for line-by-line parsing, but for an entire
|
||||||
// script it is a syntax error.
|
// script it is a syntax error.
|
||||||
Some((Token::StringConstant(_), pos)) if self.state.is_within_text_terminated_by.is_some() => {
|
Some((Token::StringConstant(..), pos)) if self.state.is_within_text_terminated_by.is_some() => {
|
||||||
self.state.is_within_text_terminated_by = None;
|
self.state.is_within_text_terminated_by = None;
|
||||||
return Some((Token::LexError(LERR::UnterminatedString), pos));
|
return Some((Token::LexError(LERR::UnterminatedString), pos));
|
||||||
}
|
}
|
||||||
@ -2232,14 +2232,14 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||||||
"'#' is not a valid symbol. Should it be '#{'?".to_string(),
|
"'#' is not a valid symbol. Should it be '#{'?".to_string(),
|
||||||
)),
|
)),
|
||||||
// Reserved keyword/operator that is custom.
|
// Reserved keyword/operator that is custom.
|
||||||
(_, true) => Token::Custom(s),
|
(.., true) => Token::Custom(s),
|
||||||
// Reserved keyword that is not custom and disabled.
|
// Reserved keyword that is not custom and disabled.
|
||||||
(token, false) if self.engine.disabled_symbols.contains(token) => {
|
(token, false) if self.engine.disabled_symbols.contains(token) => {
|
||||||
let msg = format!("reserved {} '{}' is disabled", if is_valid_identifier(token.chars()) { "keyword"} else {"symbol"}, token);
|
let msg = format!("reserved {} '{}' is disabled", if is_valid_identifier(token.chars()) { "keyword"} else {"symbol"}, token);
|
||||||
Token::LexError(LERR::ImproperSymbol(s.to_string(), msg))
|
Token::LexError(LERR::ImproperSymbol(s.to_string(), msg))
|
||||||
},
|
},
|
||||||
// Reserved keyword/operator that is not custom.
|
// Reserved keyword/operator that is not custom.
|
||||||
(_, false) => Token::Reserved(s),
|
(.., false) => Token::Reserved(s),
|
||||||
}, pos),
|
}, pos),
|
||||||
// Custom keyword
|
// Custom keyword
|
||||||
Some((Token::Identifier(s), pos)) if self.engine.custom_keywords.contains_key(&*s) => {
|
Some((Token::Identifier(s), pos)) if self.engine.custom_keywords.contains_key(&*s) => {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -120,77 +120,77 @@ impl fmt::Display for EvalAltResult {
|
|||||||
s => write!(f, "{}: {}", s, err),
|
s => write!(f, "{}: {}", s, err),
|
||||||
}?,
|
}?,
|
||||||
|
|
||||||
Self::ErrorParsing(p, _) => write!(f, "Syntax error: {}", p)?,
|
Self::ErrorParsing(p, ..) => write!(f, "Syntax error: {}", p)?,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::ErrorInFunctionCall(s, src, err, _) if crate::parser::is_anonymous_fn(s) => {
|
Self::ErrorInFunctionCall(s, src, err, ..) if crate::parser::is_anonymous_fn(s) => {
|
||||||
write!(f, "{} in call to closure", err)?;
|
write!(f, "{} in call to closure", err)?;
|
||||||
if !src.is_empty() {
|
if !src.is_empty() {
|
||||||
write!(f, " @ '{}'", src)?;
|
write!(f, " @ '{}'", src)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::ErrorInFunctionCall(s, src, err, _) => {
|
Self::ErrorInFunctionCall(s, src, err, ..) => {
|
||||||
write!(f, "{} in call to function {}", err, s)?;
|
write!(f, "{} in call to function {}", err, s)?;
|
||||||
if !src.is_empty() {
|
if !src.is_empty() {
|
||||||
write!(f, " @ '{}'", src)?;
|
write!(f, " @ '{}'", src)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::ErrorInModule(s, err, _) if s.is_empty() => {
|
Self::ErrorInModule(s, err, ..) if s.is_empty() => {
|
||||||
write!(f, "Error in module: {}", err)?
|
write!(f, "Error in module: {}", err)?
|
||||||
}
|
}
|
||||||
Self::ErrorInModule(s, err, _) => write!(f, "Error in module {}: {}", s, err)?,
|
Self::ErrorInModule(s, err, ..) => write!(f, "Error in module {}: {}", s, err)?,
|
||||||
|
|
||||||
Self::ErrorVariableExists(s, _) => write!(f, "Variable is already defined: {}", s)?,
|
Self::ErrorVariableExists(s, ..) => write!(f, "Variable is already defined: {}", s)?,
|
||||||
Self::ErrorVariableNotFound(s, _) => write!(f, "Variable not found: {}", s)?,
|
Self::ErrorVariableNotFound(s, ..) => write!(f, "Variable not found: {}", s)?,
|
||||||
Self::ErrorFunctionNotFound(s, _) => write!(f, "Function not found: {}", s)?,
|
Self::ErrorFunctionNotFound(s, ..) => write!(f, "Function not found: {}", s)?,
|
||||||
Self::ErrorModuleNotFound(s, _) => write!(f, "Module not found: {}", s)?,
|
Self::ErrorModuleNotFound(s, ..) => write!(f, "Module not found: {}", s)?,
|
||||||
Self::ErrorDataRace(s, _) => {
|
Self::ErrorDataRace(s, ..) => {
|
||||||
write!(f, "Data race detected when accessing variable: {}", s)?
|
write!(f, "Data race detected when accessing variable: {}", s)?
|
||||||
}
|
}
|
||||||
Self::ErrorDotExpr(s, _) => match s.as_str() {
|
Self::ErrorDotExpr(s, ..) => match s.as_str() {
|
||||||
"" => f.write_str("Malformed dot expression"),
|
"" => f.write_str("Malformed dot expression"),
|
||||||
s => f.write_str(s),
|
s => f.write_str(s),
|
||||||
}?,
|
}?,
|
||||||
Self::ErrorIndexingType(s, _) => write!(f, "Indexer not registered: {}", s)?,
|
Self::ErrorIndexingType(s, ..) => write!(f, "Indexer not registered: {}", s)?,
|
||||||
Self::ErrorUnboundThis(_) => f.write_str("'this' is not bound")?,
|
Self::ErrorUnboundThis(..) => f.write_str("'this' is not bound")?,
|
||||||
Self::ErrorFor(_) => f.write_str("For loop expects a type that is iterable")?,
|
Self::ErrorFor(..) => f.write_str("For loop expects a type that is iterable")?,
|
||||||
Self::ErrorTooManyOperations(_) => f.write_str("Too many operations")?,
|
Self::ErrorTooManyOperations(..) => f.write_str("Too many operations")?,
|
||||||
Self::ErrorTooManyModules(_) => f.write_str("Too many modules imported")?,
|
Self::ErrorTooManyModules(..) => f.write_str("Too many modules imported")?,
|
||||||
Self::ErrorStackOverflow(_) => f.write_str("Stack overflow")?,
|
Self::ErrorStackOverflow(..) => f.write_str("Stack overflow")?,
|
||||||
Self::ErrorTerminated(_, _) => f.write_str("Script terminated")?,
|
Self::ErrorTerminated(..) => f.write_str("Script terminated")?,
|
||||||
|
|
||||||
Self::ErrorRuntime(d, _) if d.is::<()>() => f.write_str("Runtime error")?,
|
Self::ErrorRuntime(d, ..) if d.is::<()>() => f.write_str("Runtime error")?,
|
||||||
Self::ErrorRuntime(d, _)
|
Self::ErrorRuntime(d, ..)
|
||||||
if d.read_lock::<ImmutableString>()
|
if d.read_lock::<ImmutableString>()
|
||||||
.map_or(false, |v| v.is_empty()) =>
|
.map_or(false, |v| v.is_empty()) =>
|
||||||
{
|
{
|
||||||
write!(f, "Runtime error")?
|
write!(f, "Runtime error")?
|
||||||
}
|
}
|
||||||
Self::ErrorRuntime(d, _) => write!(f, "Runtime error: {}", d)?,
|
Self::ErrorRuntime(d, ..) => write!(f, "Runtime error: {}", d)?,
|
||||||
|
|
||||||
Self::ErrorAssignmentToConstant(s, _) => write!(f, "Cannot modify constant: {}", s)?,
|
Self::ErrorAssignmentToConstant(s, ..) => write!(f, "Cannot modify constant: {}", s)?,
|
||||||
Self::ErrorMismatchOutputType(s, r, _) => match (r.as_str(), s.as_str()) {
|
Self::ErrorMismatchOutputType(s, r, ..) => match (r.as_str(), s.as_str()) {
|
||||||
("", s) => write!(f, "Output type is incorrect, expecting {}", s),
|
("", s) => write!(f, "Output type is incorrect, expecting {}", s),
|
||||||
(r, "") => write!(f, "Output type is incorrect: {}", r),
|
(r, "") => write!(f, "Output type is incorrect: {}", r),
|
||||||
(r, s) => write!(f, "Output type is incorrect: {} (expecting {})", r, s),
|
(r, s) => write!(f, "Output type is incorrect: {} (expecting {})", r, s),
|
||||||
}?,
|
}?,
|
||||||
Self::ErrorMismatchDataType(s, r, _) => match (r.as_str(), s.as_str()) {
|
Self::ErrorMismatchDataType(s, r, ..) => match (r.as_str(), s.as_str()) {
|
||||||
("", s) => write!(f, "Data type is incorrect, expecting {}", s),
|
("", s) => write!(f, "Data type is incorrect, expecting {}", s),
|
||||||
(r, "") => write!(f, "Data type is incorrect: {}", r),
|
(r, "") => write!(f, "Data type is incorrect: {}", r),
|
||||||
(r, s) => write!(f, "Data type is incorrect: {} (expecting {})", r, s),
|
(r, s) => write!(f, "Data type is incorrect: {} (expecting {})", r, s),
|
||||||
}?,
|
}?,
|
||||||
Self::ErrorArithmetic(s, _) => match s.as_str() {
|
Self::ErrorArithmetic(s, ..) => match s.as_str() {
|
||||||
"" => f.write_str("Arithmetic error"),
|
"" => f.write_str("Arithmetic error"),
|
||||||
s => f.write_str(s),
|
s => f.write_str(s),
|
||||||
}?,
|
}?,
|
||||||
|
|
||||||
Self::LoopBreak(true, _) => f.write_str("'break' not inside a loop")?,
|
Self::LoopBreak(true, ..) => f.write_str("'break' not inside a loop")?,
|
||||||
Self::LoopBreak(false, _) => f.write_str("'continue' not inside a loop")?,
|
Self::LoopBreak(false, ..) => f.write_str("'continue' not inside a loop")?,
|
||||||
|
|
||||||
Self::Return(_, _) => f.write_str("NOT AN ERROR - function returns value")?,
|
Self::Return(..) => f.write_str("NOT AN ERROR - function returns value")?,
|
||||||
|
|
||||||
Self::ErrorArrayBounds(max, index, _) => match max {
|
Self::ErrorArrayBounds(max, index, ..) => match max {
|
||||||
0 => write!(f, "Array index {} out of bounds: array is empty", index),
|
0 => write!(f, "Array index {} out of bounds: array is empty", index),
|
||||||
1 => write!(
|
1 => write!(
|
||||||
f,
|
f,
|
||||||
@ -203,7 +203,7 @@ impl fmt::Display for EvalAltResult {
|
|||||||
index, max
|
index, max
|
||||||
),
|
),
|
||||||
}?,
|
}?,
|
||||||
Self::ErrorStringBounds(max, index, _) => match max {
|
Self::ErrorStringBounds(max, index, ..) => match max {
|
||||||
0 => write!(f, "String index {} out of bounds: string is empty", index),
|
0 => write!(f, "String index {} out of bounds: string is empty", index),
|
||||||
1 => write!(
|
1 => write!(
|
||||||
f,
|
f,
|
||||||
@ -216,14 +216,14 @@ impl fmt::Display for EvalAltResult {
|
|||||||
index, max
|
index, max
|
||||||
),
|
),
|
||||||
}?,
|
}?,
|
||||||
Self::ErrorBitFieldBounds(max, index, _) => write!(
|
Self::ErrorBitFieldBounds(max, index, ..) => write!(
|
||||||
f,
|
f,
|
||||||
"Bit-field index {} out of bounds: only {} bits in the bit-field",
|
"Bit-field index {} out of bounds: only {} bits in the bit-field",
|
||||||
index, max
|
index, max
|
||||||
)?,
|
)?,
|
||||||
Self::ErrorDataTooLarge(typ, _) => write!(f, "{} exceeds maximum limit", typ)?,
|
Self::ErrorDataTooLarge(typ, ..) => write!(f, "{} exceeds maximum limit", typ)?,
|
||||||
|
|
||||||
Self::ErrorCustomSyntax(s, tokens, _) => write!(f, "{}: {}", s, tokens.join(" "))?,
|
Self::ErrorCustomSyntax(s, tokens, ..) => write!(f, "{}: {}", s, tokens.join(" "))?,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not write any position if None
|
// Do not write any position if None
|
||||||
@ -256,7 +256,7 @@ impl EvalAltResult {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_pseudo_error(&self) -> bool {
|
pub const fn is_pseudo_error(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::LoopBreak(_, _) | Self::Return(_, _) => true,
|
Self::LoopBreak(..) | Self::Return(..) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -264,58 +264,58 @@ impl EvalAltResult {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_catchable(&self) -> bool {
|
pub const fn is_catchable(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::ErrorSystem(_, _) => false,
|
Self::ErrorSystem(..) => false,
|
||||||
Self::ErrorParsing(_, _) => false,
|
Self::ErrorParsing(..) => false,
|
||||||
|
|
||||||
Self::ErrorFunctionNotFound(_, _)
|
Self::ErrorFunctionNotFound(..)
|
||||||
| Self::ErrorInFunctionCall(_, _, _, _)
|
| Self::ErrorInFunctionCall(..)
|
||||||
| Self::ErrorInModule(_, _, _)
|
| Self::ErrorInModule(..)
|
||||||
| Self::ErrorUnboundThis(_)
|
| Self::ErrorUnboundThis(..)
|
||||||
| Self::ErrorMismatchDataType(_, _, _)
|
| Self::ErrorMismatchDataType(..)
|
||||||
| Self::ErrorArrayBounds(_, _, _)
|
| Self::ErrorArrayBounds(..)
|
||||||
| Self::ErrorStringBounds(_, _, _)
|
| Self::ErrorStringBounds(..)
|
||||||
| Self::ErrorBitFieldBounds(_, _, _)
|
| Self::ErrorBitFieldBounds(..)
|
||||||
| Self::ErrorIndexingType(_, _)
|
| Self::ErrorIndexingType(..)
|
||||||
| Self::ErrorFor(_)
|
| Self::ErrorFor(..)
|
||||||
| Self::ErrorVariableExists(_, _)
|
| Self::ErrorVariableExists(..)
|
||||||
| Self::ErrorVariableNotFound(_, _)
|
| Self::ErrorVariableNotFound(..)
|
||||||
| Self::ErrorModuleNotFound(_, _)
|
| Self::ErrorModuleNotFound(..)
|
||||||
| Self::ErrorDataRace(_, _)
|
| Self::ErrorDataRace(..)
|
||||||
| Self::ErrorAssignmentToConstant(_, _)
|
| Self::ErrorAssignmentToConstant(..)
|
||||||
| Self::ErrorMismatchOutputType(_, _, _)
|
| Self::ErrorMismatchOutputType(..)
|
||||||
| Self::ErrorDotExpr(_, _)
|
| Self::ErrorDotExpr(..)
|
||||||
| Self::ErrorArithmetic(_, _)
|
| Self::ErrorArithmetic(..)
|
||||||
| Self::ErrorRuntime(_, _) => true,
|
| Self::ErrorRuntime(..) => true,
|
||||||
|
|
||||||
// Custom syntax raises errors only when they are compiled by one
|
// Custom syntax raises errors only when they are compiled by one
|
||||||
// [`Engine`][crate::Engine] and run by another, causing a mismatch.
|
// [`Engine`][crate::Engine] and run by another, causing a mismatch.
|
||||||
//
|
//
|
||||||
// Therefore, this error should not be catchable.
|
// Therefore, this error should not be catchable.
|
||||||
Self::ErrorCustomSyntax(_, _, _) => false,
|
Self::ErrorCustomSyntax(..) => false,
|
||||||
|
|
||||||
Self::ErrorTooManyOperations(_)
|
Self::ErrorTooManyOperations(..)
|
||||||
| Self::ErrorTooManyModules(_)
|
| Self::ErrorTooManyModules(..)
|
||||||
| Self::ErrorStackOverflow(_)
|
| Self::ErrorStackOverflow(..)
|
||||||
| Self::ErrorDataTooLarge(_, _)
|
| Self::ErrorDataTooLarge(..)
|
||||||
| Self::ErrorTerminated(_, _) => false,
|
| Self::ErrorTerminated(..) => false,
|
||||||
|
|
||||||
Self::LoopBreak(_, _) | Self::Return(_, _) => false,
|
Self::LoopBreak(..) | Self::Return(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is this error a system exception?
|
/// Is this error a system exception?
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_system_exception(&self) -> bool {
|
pub const fn is_system_exception(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::ErrorSystem(_, _) => true,
|
Self::ErrorSystem(..) => true,
|
||||||
Self::ErrorParsing(_, _) => true,
|
Self::ErrorParsing(..) => true,
|
||||||
|
|
||||||
Self::ErrorCustomSyntax(_, _, _)
|
Self::ErrorCustomSyntax(..)
|
||||||
| Self::ErrorTooManyOperations(_)
|
| Self::ErrorTooManyOperations(..)
|
||||||
| Self::ErrorTooManyModules(_)
|
| Self::ErrorTooManyModules(..)
|
||||||
| Self::ErrorStackOverflow(_)
|
| Self::ErrorStackOverflow(..)
|
||||||
| Self::ErrorDataTooLarge(_, _) => true,
|
| Self::ErrorDataTooLarge(..) => true,
|
||||||
|
|
||||||
Self::ErrorTerminated(_, _) => true,
|
Self::ErrorTerminated(..) => true,
|
||||||
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
@ -333,58 +333,58 @@ impl EvalAltResult {
|
|||||||
);
|
);
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Self::LoopBreak(_, _) | Self::Return(_, _) => (),
|
Self::LoopBreak(..) | Self::Return(..) => (),
|
||||||
|
|
||||||
Self::ErrorSystem(_, _)
|
Self::ErrorSystem(..)
|
||||||
| Self::ErrorParsing(_, _)
|
| Self::ErrorParsing(..)
|
||||||
| Self::ErrorUnboundThis(_)
|
| Self::ErrorUnboundThis(..)
|
||||||
| Self::ErrorFor(_)
|
| Self::ErrorFor(..)
|
||||||
| Self::ErrorArithmetic(_, _)
|
| Self::ErrorArithmetic(..)
|
||||||
| Self::ErrorTooManyOperations(_)
|
| Self::ErrorTooManyOperations(..)
|
||||||
| Self::ErrorTooManyModules(_)
|
| Self::ErrorTooManyModules(..)
|
||||||
| Self::ErrorStackOverflow(_)
|
| Self::ErrorStackOverflow(..)
|
||||||
| Self::ErrorRuntime(_, _) => (),
|
| Self::ErrorRuntime(..) => (),
|
||||||
|
|
||||||
Self::ErrorFunctionNotFound(f, _) => {
|
Self::ErrorFunctionNotFound(f, ..) => {
|
||||||
map.insert("function".into(), f.into());
|
map.insert("function".into(), f.into());
|
||||||
}
|
}
|
||||||
Self::ErrorInFunctionCall(f, s, _, _) => {
|
Self::ErrorInFunctionCall(f, s, ..) => {
|
||||||
map.insert("function".into(), f.into());
|
map.insert("function".into(), f.into());
|
||||||
map.insert("source".into(), s.into());
|
map.insert("source".into(), s.into());
|
||||||
}
|
}
|
||||||
Self::ErrorInModule(m, _, _) => {
|
Self::ErrorInModule(m, ..) => {
|
||||||
map.insert("module".into(), m.into());
|
map.insert("module".into(), m.into());
|
||||||
}
|
}
|
||||||
Self::ErrorMismatchDataType(r, a, _) | Self::ErrorMismatchOutputType(r, a, _) => {
|
Self::ErrorMismatchDataType(r, a, ..) | Self::ErrorMismatchOutputType(r, a, ..) => {
|
||||||
map.insert("requested".into(), r.into());
|
map.insert("requested".into(), r.into());
|
||||||
map.insert("actual".into(), a.into());
|
map.insert("actual".into(), a.into());
|
||||||
}
|
}
|
||||||
Self::ErrorArrayBounds(n, i, _)
|
Self::ErrorArrayBounds(n, i, ..)
|
||||||
| Self::ErrorStringBounds(n, i, _)
|
| Self::ErrorStringBounds(n, i, ..)
|
||||||
| Self::ErrorBitFieldBounds(n, i, _) => {
|
| Self::ErrorBitFieldBounds(n, i, ..) => {
|
||||||
map.insert("length".into(), (*n as INT).into());
|
map.insert("length".into(), (*n as INT).into());
|
||||||
map.insert("index".into(), (*i as INT).into());
|
map.insert("index".into(), (*i as INT).into());
|
||||||
}
|
}
|
||||||
Self::ErrorIndexingType(t, _) => {
|
Self::ErrorIndexingType(t, ..) => {
|
||||||
map.insert("type".into(), t.into());
|
map.insert("type".into(), t.into());
|
||||||
}
|
}
|
||||||
Self::ErrorVariableExists(v, _)
|
Self::ErrorVariableExists(v, ..)
|
||||||
| Self::ErrorVariableNotFound(v, _)
|
| Self::ErrorVariableNotFound(v, ..)
|
||||||
| Self::ErrorDataRace(v, _)
|
| Self::ErrorDataRace(v, ..)
|
||||||
| Self::ErrorAssignmentToConstant(v, _) => {
|
| Self::ErrorAssignmentToConstant(v, ..) => {
|
||||||
map.insert("variable".into(), v.into());
|
map.insert("variable".into(), v.into());
|
||||||
}
|
}
|
||||||
Self::ErrorModuleNotFound(m, _) => {
|
Self::ErrorModuleNotFound(m, ..) => {
|
||||||
map.insert("module".into(), m.into());
|
map.insert("module".into(), m.into());
|
||||||
}
|
}
|
||||||
Self::ErrorDotExpr(p, _) => {
|
Self::ErrorDotExpr(p, ..) => {
|
||||||
map.insert("property".into(), p.into());
|
map.insert("property".into(), p.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::ErrorDataTooLarge(t, _) => {
|
Self::ErrorDataTooLarge(t, ..) => {
|
||||||
map.insert("type".into(), t.into());
|
map.insert("type".into(), t.into());
|
||||||
}
|
}
|
||||||
Self::ErrorTerminated(t, _) => {
|
Self::ErrorTerminated(t, ..) => {
|
||||||
map.insert("token".into(), t.clone());
|
map.insert("token".into(), t.clone());
|
||||||
}
|
}
|
||||||
Self::ErrorCustomSyntax(_, tokens, _) => {
|
Self::ErrorCustomSyntax(_, tokens, _) => {
|
||||||
@ -403,40 +403,50 @@ impl EvalAltResult {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
/// Unwrap this error and get the very base error.
|
||||||
|
#[must_use]
|
||||||
|
pub fn unwrap_inner(&self) -> &Self {
|
||||||
|
match self {
|
||||||
|
Self::ErrorInFunctionCall(.., err, _) | Self::ErrorInModule(.., err, _) => {
|
||||||
|
err.unwrap_inner()
|
||||||
|
}
|
||||||
|
_ => self,
|
||||||
|
}
|
||||||
|
}
|
||||||
/// Get the [position][Position] of this error.
|
/// Get the [position][Position] of this error.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn position(&self) -> Position {
|
pub const fn position(&self) -> Position {
|
||||||
match self {
|
match self {
|
||||||
Self::ErrorSystem(_, _) => Position::NONE,
|
Self::ErrorSystem(..) => Position::NONE,
|
||||||
|
|
||||||
Self::ErrorParsing(_, pos)
|
Self::ErrorParsing(.., pos)
|
||||||
| Self::ErrorFunctionNotFound(_, pos)
|
| Self::ErrorFunctionNotFound(.., pos)
|
||||||
| Self::ErrorInFunctionCall(_, _, _, pos)
|
| Self::ErrorInFunctionCall(.., pos)
|
||||||
| Self::ErrorInModule(_, _, pos)
|
| Self::ErrorInModule(.., pos)
|
||||||
| Self::ErrorUnboundThis(pos)
|
| Self::ErrorUnboundThis(pos)
|
||||||
| Self::ErrorMismatchDataType(_, _, pos)
|
| Self::ErrorMismatchDataType(.., pos)
|
||||||
| Self::ErrorArrayBounds(_, _, pos)
|
| Self::ErrorArrayBounds(.., pos)
|
||||||
| Self::ErrorStringBounds(_, _, pos)
|
| Self::ErrorStringBounds(.., pos)
|
||||||
| Self::ErrorBitFieldBounds(_, _, pos)
|
| Self::ErrorBitFieldBounds(.., pos)
|
||||||
| Self::ErrorIndexingType(_, pos)
|
| Self::ErrorIndexingType(.., pos)
|
||||||
| Self::ErrorFor(pos)
|
| Self::ErrorFor(pos)
|
||||||
| Self::ErrorVariableExists(_, pos)
|
| Self::ErrorVariableExists(.., pos)
|
||||||
| Self::ErrorVariableNotFound(_, pos)
|
| Self::ErrorVariableNotFound(.., pos)
|
||||||
| Self::ErrorModuleNotFound(_, pos)
|
| Self::ErrorModuleNotFound(.., pos)
|
||||||
| Self::ErrorDataRace(_, pos)
|
| Self::ErrorDataRace(.., pos)
|
||||||
| Self::ErrorAssignmentToConstant(_, pos)
|
| Self::ErrorAssignmentToConstant(.., pos)
|
||||||
| Self::ErrorMismatchOutputType(_, _, pos)
|
| Self::ErrorMismatchOutputType(.., pos)
|
||||||
| Self::ErrorDotExpr(_, pos)
|
| Self::ErrorDotExpr(.., pos)
|
||||||
| Self::ErrorArithmetic(_, pos)
|
| Self::ErrorArithmetic(.., pos)
|
||||||
| Self::ErrorTooManyOperations(pos)
|
| Self::ErrorTooManyOperations(pos)
|
||||||
| Self::ErrorTooManyModules(pos)
|
| Self::ErrorTooManyModules(pos)
|
||||||
| Self::ErrorStackOverflow(pos)
|
| Self::ErrorStackOverflow(pos)
|
||||||
| Self::ErrorDataTooLarge(_, pos)
|
| Self::ErrorDataTooLarge(.., pos)
|
||||||
| Self::ErrorTerminated(_, pos)
|
| Self::ErrorTerminated(.., pos)
|
||||||
| Self::ErrorCustomSyntax(_, _, pos)
|
| Self::ErrorCustomSyntax(.., pos)
|
||||||
| Self::ErrorRuntime(_, pos)
|
| Self::ErrorRuntime(.., pos)
|
||||||
| Self::LoopBreak(_, pos)
|
| Self::LoopBreak(.., pos)
|
||||||
| Self::Return(_, pos) => *pos,
|
| Self::Return(.., pos) => *pos,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Remove the [position][Position] information from this error.
|
/// Remove the [position][Position] information from this error.
|
||||||
@ -456,36 +466,36 @@ impl EvalAltResult {
|
|||||||
/// Override the [position][Position] of this error.
|
/// Override the [position][Position] of this error.
|
||||||
pub fn set_position(&mut self, new_position: Position) -> &mut Self {
|
pub fn set_position(&mut self, new_position: Position) -> &mut Self {
|
||||||
match self {
|
match self {
|
||||||
Self::ErrorSystem(_, _) => (),
|
Self::ErrorSystem(..) => (),
|
||||||
|
|
||||||
Self::ErrorParsing(_, pos)
|
Self::ErrorParsing(.., pos)
|
||||||
| Self::ErrorFunctionNotFound(_, pos)
|
| Self::ErrorFunctionNotFound(.., pos)
|
||||||
| Self::ErrorInFunctionCall(_, _, _, pos)
|
| Self::ErrorInFunctionCall(.., pos)
|
||||||
| Self::ErrorInModule(_, _, pos)
|
| Self::ErrorInModule(.., pos)
|
||||||
| Self::ErrorUnboundThis(pos)
|
| Self::ErrorUnboundThis(pos)
|
||||||
| Self::ErrorMismatchDataType(_, _, pos)
|
| Self::ErrorMismatchDataType(.., pos)
|
||||||
| Self::ErrorArrayBounds(_, _, pos)
|
| Self::ErrorArrayBounds(.., pos)
|
||||||
| Self::ErrorStringBounds(_, _, pos)
|
| Self::ErrorStringBounds(.., pos)
|
||||||
| Self::ErrorBitFieldBounds(_, _, pos)
|
| Self::ErrorBitFieldBounds(.., pos)
|
||||||
| Self::ErrorIndexingType(_, pos)
|
| Self::ErrorIndexingType(.., pos)
|
||||||
| Self::ErrorFor(pos)
|
| Self::ErrorFor(pos)
|
||||||
| Self::ErrorVariableExists(_, pos)
|
| Self::ErrorVariableExists(.., pos)
|
||||||
| Self::ErrorVariableNotFound(_, pos)
|
| Self::ErrorVariableNotFound(.., pos)
|
||||||
| Self::ErrorModuleNotFound(_, pos)
|
| Self::ErrorModuleNotFound(.., pos)
|
||||||
| Self::ErrorDataRace(_, pos)
|
| Self::ErrorDataRace(.., pos)
|
||||||
| Self::ErrorAssignmentToConstant(_, pos)
|
| Self::ErrorAssignmentToConstant(.., pos)
|
||||||
| Self::ErrorMismatchOutputType(_, _, pos)
|
| Self::ErrorMismatchOutputType(.., pos)
|
||||||
| Self::ErrorDotExpr(_, pos)
|
| Self::ErrorDotExpr(.., pos)
|
||||||
| Self::ErrorArithmetic(_, pos)
|
| Self::ErrorArithmetic(.., pos)
|
||||||
| Self::ErrorTooManyOperations(pos)
|
| Self::ErrorTooManyOperations(pos)
|
||||||
| Self::ErrorTooManyModules(pos)
|
| Self::ErrorTooManyModules(pos)
|
||||||
| Self::ErrorStackOverflow(pos)
|
| Self::ErrorStackOverflow(pos)
|
||||||
| Self::ErrorDataTooLarge(_, pos)
|
| Self::ErrorDataTooLarge(.., pos)
|
||||||
| Self::ErrorTerminated(_, pos)
|
| Self::ErrorTerminated(.., pos)
|
||||||
| Self::ErrorCustomSyntax(_, _, pos)
|
| Self::ErrorCustomSyntax(.., pos)
|
||||||
| Self::ErrorRuntime(_, pos)
|
| Self::ErrorRuntime(.., pos)
|
||||||
| Self::LoopBreak(_, pos)
|
| Self::LoopBreak(.., pos)
|
||||||
| Self::Return(_, pos) => *pos = new_position,
|
| Self::Return(.., pos) => *pos = new_position,
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ impl fmt::Display for LexError {
|
|||||||
Self::ImproperSymbol(s, d) if d.is_empty() => {
|
Self::ImproperSymbol(s, d) if d.is_empty() => {
|
||||||
write!(f, "Invalid symbol encountered: '{}'", s)
|
write!(f, "Invalid symbol encountered: '{}'", s)
|
||||||
}
|
}
|
||||||
Self::ImproperSymbol(_, d) => f.write_str(d),
|
Self::ImproperSymbol(.., d) => f.write_str(d),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,7 +310,7 @@ impl Scope<'_> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn contains(&self, name: &str) -> bool {
|
pub fn contains(&self, name: &str) -> bool {
|
||||||
self.names.iter().any(|(key, _)| name == key)
|
self.names.iter().any(|(key, ..)| name == key)
|
||||||
}
|
}
|
||||||
/// Find an entry in the [`Scope`], starting from the last.
|
/// Find an entry in the [`Scope`], starting from the last.
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -322,7 +322,7 @@ impl Scope<'_> {
|
|||||||
.iter()
|
.iter()
|
||||||
.rev() // Always search a Scope in reverse order
|
.rev() // Always search a Scope in reverse order
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find_map(|(i, (key, _))| {
|
.find_map(|(i, (key, ..))| {
|
||||||
if name == key {
|
if name == key {
|
||||||
let index = len - 1 - i;
|
let index = len - 1 - i;
|
||||||
Some((index, self.values[index].access_mode()))
|
Some((index, self.values[index].access_mode()))
|
||||||
@ -352,8 +352,8 @@ impl Scope<'_> {
|
|||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|(_, (key, _))| name == key)
|
.find(|(.., (key, ..))| name == key)
|
||||||
.and_then(|(index, _)| self.values[len - 1 - index].flatten_clone().try_cast())
|
.and_then(|(index, ..)| self.values[len - 1 - index].flatten_clone().try_cast())
|
||||||
}
|
}
|
||||||
/// Check if the named entry in the [`Scope`] is constant.
|
/// Check if the named entry in the [`Scope`] is constant.
|
||||||
///
|
///
|
||||||
@ -374,7 +374,7 @@ impl Scope<'_> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_constant(&self, name: &str) -> Option<bool> {
|
pub fn is_constant(&self, name: &str) -> Option<bool> {
|
||||||
self.get_index(name).and_then(|(_, access)| match access {
|
self.get_index(name).and_then(|(.., access)| match access {
|
||||||
AccessMode::ReadWrite => None,
|
AccessMode::ReadWrite => None,
|
||||||
AccessMode::ReadOnly => Some(true),
|
AccessMode::ReadOnly => Some(true),
|
||||||
})
|
})
|
||||||
@ -411,7 +411,7 @@ impl Scope<'_> {
|
|||||||
value: impl Variant + Clone,
|
value: impl Variant + Clone,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
match self.get_index(name.as_ref()) {
|
match self.get_index(name.as_ref()) {
|
||||||
None | Some((_, AccessMode::ReadOnly)) => {
|
None | Some((.., AccessMode::ReadOnly)) => {
|
||||||
self.push(name, value);
|
self.push(name, value);
|
||||||
}
|
}
|
||||||
Some((index, AccessMode::ReadWrite)) => {
|
Some((index, AccessMode::ReadWrite)) => {
|
||||||
@ -453,7 +453,7 @@ impl Scope<'_> {
|
|||||||
None => {
|
None => {
|
||||||
self.push(name, value);
|
self.push(name, value);
|
||||||
}
|
}
|
||||||
Some((_, AccessMode::ReadOnly)) => panic!("variable {} is constant", name.as_ref()),
|
Some((.., AccessMode::ReadOnly)) => panic!("variable {} is constant", name.as_ref()),
|
||||||
Some((index, AccessMode::ReadWrite)) => {
|
Some((index, AccessMode::ReadWrite)) => {
|
||||||
let value_ref = self.values.get_mut(index).unwrap();
|
let value_ref = self.values.get_mut(index).unwrap();
|
||||||
*value_ref = Dynamic::from(value);
|
*value_ref = Dynamic::from(value);
|
||||||
@ -511,7 +511,7 @@ impl Scope<'_> {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn add_entry_alias(&mut self, index: usize, alias: Identifier) -> &mut Self {
|
pub(crate) fn add_entry_alias(&mut self, index: usize, alias: Identifier) -> &mut Self {
|
||||||
let (_, aliases) = self.names.get_mut(index).unwrap();
|
let (.., aliases) = self.names.get_mut(index).unwrap();
|
||||||
match aliases {
|
match aliases {
|
||||||
None => {
|
None => {
|
||||||
let mut list = StaticVec::new_const();
|
let mut list = StaticVec::new_const();
|
||||||
@ -533,7 +533,7 @@ impl Scope<'_> {
|
|||||||
self.names.iter().rev().enumerate().fold(
|
self.names.iter().rev().enumerate().fold(
|
||||||
Self::new(),
|
Self::new(),
|
||||||
|mut entries, (index, (name, alias))| {
|
|mut entries, (index, (name, alias))| {
|
||||||
if !entries.names.iter().any(|(key, _)| key == name) {
|
if !entries.names.iter().any(|(key, ..)| key == name) {
|
||||||
let orig_value = &self.values[len - 1 - index];
|
let orig_value = &self.values[len - 1 - index];
|
||||||
let mut value = orig_value.clone();
|
let mut value = orig_value.clone();
|
||||||
value.set_access_mode(orig_value.access_mode());
|
value.set_access_mode(orig_value.access_mode());
|
||||||
@ -593,7 +593,7 @@ impl Scope<'_> {
|
|||||||
self.names
|
self.names
|
||||||
.iter()
|
.iter()
|
||||||
.zip(self.values.iter())
|
.zip(self.values.iter())
|
||||||
.map(|((name, _), value)| (name.as_ref(), value.is_read_only(), value))
|
.map(|((name, ..), value)| (name.as_ref(), value.is_read_only(), value))
|
||||||
}
|
}
|
||||||
/// Remove a range of entries within the [`Scope`].
|
/// Remove a range of entries within the [`Scope`].
|
||||||
///
|
///
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
//! A helper module containing unsafe utility functions.
|
|
||||||
|
|
||||||
#[cfg(feature = "no_std")]
|
|
||||||
use std::prelude::v1::*;
|
|
||||||
use std::{
|
|
||||||
any::{Any, TypeId},
|
|
||||||
mem, ptr,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Cast a type into another type.
|
|
||||||
///
|
|
||||||
/// # Undefined Behavior
|
|
||||||
///
|
|
||||||
/// It is UB if the types are not compatible.
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn unsafe_cast<A: Any, B: Any>(a: A) -> B {
|
|
||||||
unsafe {
|
|
||||||
let ret: B = ptr::read(&a as *const _ as *const B);
|
|
||||||
// We explicitly forget the value immediately after moving out,
|
|
||||||
// removing any chance of a destructor running or value otherwise
|
|
||||||
// being used again.
|
|
||||||
mem::forget(a);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cast a type into another type.
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn unsafe_try_cast<A: Any, B: Any>(a: A) -> Option<B> {
|
|
||||||
if TypeId::of::<B>() == a.type_id() {
|
|
||||||
// SAFETY: Just checked we have the right type.
|
|
||||||
Some(unsafe_cast(a))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cast a Boxed type into another type.
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn unsafe_cast_box<X: Any, T: Any>(item: Box<X>) -> Option<T> {
|
|
||||||
// Only allow casting to the exact same type
|
|
||||||
if TypeId::of::<X>() == TypeId::of::<T>() {
|
|
||||||
// SAFETY: just checked whether we are pointing to the correct type
|
|
||||||
unsafe {
|
|
||||||
let raw: *mut dyn Any = Box::into_raw(item as Box<dyn Any>);
|
|
||||||
Some(*Box::from_raw(raw as *mut T))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
@ -330,7 +330,7 @@ fn test_call_fn_events() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"update" => engine
|
"update" => engine
|
||||||
.call_fn(scope, ast, "update", (event_data,))
|
.call_fn(scope, ast, "update", (event_data,))
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
EvalAltResult::ErrorFunctionNotFound(fn_name, _)
|
EvalAltResult::ErrorFunctionNotFound(fn_name, ..)
|
||||||
if fn_name.starts_with("update") =>
|
if fn_name.starts_with("update") =>
|
||||||
{
|
{
|
||||||
// Default implementation of 'update' event handler
|
// Default implementation of 'update' event handler
|
||||||
|
@ -48,7 +48,7 @@ fn test_closures() -> Result<(), Box<EvalAltResult>> {
|
|||||||
.compile_expression("let f = |x| {};")
|
.compile_expression("let f = |x| {};")
|
||||||
.expect_err("should error")
|
.expect_err("should error")
|
||||||
.0,
|
.0,
|
||||||
ParseErrorType::BadInput(_)
|
ParseErrorType::BadInput(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -251,7 +251,7 @@ fn test_closures_data_race() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"
|
"
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorDataRace(_, _)
|
EvalAltResult::ErrorDataRace(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -10,13 +10,13 @@ fn test_constant() -> Result<(), Box<EvalAltResult>> {
|
|||||||
*engine
|
*engine
|
||||||
.eval::<INT>("const x = 123; x = 42;")
|
.eval::<INT>("const x = 123; x = 42;")
|
||||||
.expect_err("expects error"),
|
.expect_err("expects error"),
|
||||||
EvalAltResult::ErrorParsing(ParseErrorType::AssignmentToConstant(x), _) if x == "x"
|
EvalAltResult::ErrorParsing(ParseErrorType::AssignmentToConstant(x), ..) if x == "x"
|
||||||
));
|
));
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine.run("const x = [1, 2, 3, 4, 5]; x[2] = 42;").expect_err("expects error"),
|
*engine.run("const x = [1, 2, 3, 4, 5]; x[2] = 42;").expect_err("expects error"),
|
||||||
EvalAltResult::ErrorAssignmentToConstant(x, _) if x == "x"
|
EvalAltResult::ErrorAssignmentToConstant(x, ..) if x == "x"
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -31,7 +31,7 @@ fn test_constant_scope() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine.run_with_scope(&mut scope, "x = 1").expect_err("expects error"),
|
*engine.run_with_scope(&mut scope, "x = 1").expect_err("expects error"),
|
||||||
EvalAltResult::ErrorAssignmentToConstant(x, _) if x == "x"
|
EvalAltResult::ErrorAssignmentToConstant(x, ..) if x == "x"
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -87,7 +87,7 @@ fn test_constant_mut() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"
|
"
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorAssignmentToConstant(_, _)
|
EvalAltResult::ErrorAssignmentToConstant(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
@ -120,7 +120,7 @@ fn test_constant_mut() -> Result<(), Box<EvalAltResult>> {
|
|||||||
*engine
|
*engine
|
||||||
.run_with_scope(&mut scope, "MY_NUMBER.value = 42;")
|
.run_with_scope(&mut scope, "MY_NUMBER.value = 42;")
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorAssignmentToConstant(_, _)
|
EvalAltResult::ErrorAssignmentToConstant(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -81,7 +81,7 @@ fn test_custom_syntax() -> Result<(), Box<EvalAltResult>> {
|
|||||||
*engine
|
*engine
|
||||||
.run("let foo = (exec [x<<15] -> { x += 2 } while x < 42) * 10;")
|
.run("let foo = (exec [x<<15] -> { x += 2 } while x < 42) * 10;")
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorRuntime(_, _)
|
EvalAltResult::ErrorRuntime(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -38,7 +38,7 @@ fn test_max_string_size() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"#
|
"#
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorDataTooLarge(_, _)
|
EvalAltResult::ErrorDataTooLarge(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
@ -52,7 +52,7 @@ fn test_max_string_size() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"#
|
"#
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorDataTooLarge(_, _)
|
EvalAltResult::ErrorDataTooLarge(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
engine.set_max_string_size(0);
|
engine.set_max_string_size(0);
|
||||||
@ -98,7 +98,7 @@ fn test_max_array_size() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"
|
"
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorDataTooLarge(_, _)
|
EvalAltResult::ErrorDataTooLarge(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
@ -131,7 +131,7 @@ fn test_max_array_size() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"
|
"
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorDataTooLarge(_, _)
|
EvalAltResult::ErrorDataTooLarge(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
@ -143,7 +143,7 @@ fn test_max_array_size() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"
|
"
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorDataTooLarge(_, _)
|
EvalAltResult::ErrorDataTooLarge(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
@ -169,7 +169,7 @@ fn test_max_array_size() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"
|
"
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorDataTooLarge(_, _)
|
EvalAltResult::ErrorDataTooLarge(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -191,7 +191,7 @@ fn test_max_array_size() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"
|
"
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorDataTooLarge(_, _)
|
EvalAltResult::ErrorDataTooLarge(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
@ -204,7 +204,7 @@ fn test_max_array_size() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"
|
"
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorDataTooLarge(_, _)
|
EvalAltResult::ErrorDataTooLarge(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
@ -218,7 +218,7 @@ fn test_max_array_size() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"
|
"
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorDataTooLarge(_, _)
|
EvalAltResult::ErrorDataTooLarge(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
engine.set_max_array_size(0);
|
engine.set_max_array_size(0);
|
||||||
@ -282,7 +282,7 @@ fn test_max_map_size() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"
|
"
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorDataTooLarge(_, _)
|
EvalAltResult::ErrorDataTooLarge(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
@ -295,7 +295,7 @@ fn test_max_map_size() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"
|
"
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorDataTooLarge(_, _)
|
EvalAltResult::ErrorDataTooLarge(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
@ -307,7 +307,7 @@ fn test_max_map_size() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"
|
"
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorDataTooLarge(_, _)
|
EvalAltResult::ErrorDataTooLarge(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
@ -320,7 +320,7 @@ fn test_max_map_size() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"
|
"
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorDataTooLarge(_, _)
|
EvalAltResult::ErrorDataTooLarge(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
engine.set_max_map_size(0);
|
engine.set_max_map_size(0);
|
||||||
|
@ -171,7 +171,7 @@ fn test_eval_disabled() -> Result<(), Box<EvalAltResult>> {
|
|||||||
.compile(r#"eval("40 + 2")"#)
|
.compile(r#"eval("40 + 2")"#)
|
||||||
.expect_err("should error")
|
.expect_err("should error")
|
||||||
.0,
|
.0,
|
||||||
ParseErrorType::BadInput(LexError::ImproperSymbol(err, _)) if err == "eval"
|
ParseErrorType::BadInput(LexError::ImproperSymbol(err, ..)) if err == "eval"
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -73,8 +73,8 @@ fn test_fn_ptr() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"#
|
"#
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorInFunctionCall(fn_name, _, err, _)
|
EvalAltResult::ErrorInFunctionCall(fn_name, _, err, ..)
|
||||||
if fn_name == "foo" && matches!(*err, EvalAltResult::ErrorUnboundThis(_))
|
if fn_name == "foo" && matches!(*err, EvalAltResult::ErrorUnboundThis(..))
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -92,8 +92,8 @@ fn test_functions_global_module() -> Result<(), Box<EvalAltResult>> {
|
|||||||
foo()
|
foo()
|
||||||
}
|
}
|
||||||
").expect_err("should error"),
|
").expect_err("should error"),
|
||||||
EvalAltResult::ErrorInFunctionCall(_, _, err, _)
|
EvalAltResult::ErrorInFunctionCall(.., err, _)
|
||||||
if matches!(&*err, EvalAltResult::ErrorVariableNotFound(v, _) if v == "global::ANSWER")
|
if matches!(&*err, EvalAltResult::ErrorVariableNotFound(v, ..) if v == "global::ANSWER")
|
||||||
));
|
));
|
||||||
|
|
||||||
engine.register_result_fn(
|
engine.register_result_fn(
|
||||||
@ -110,8 +110,8 @@ fn test_functions_global_module() -> Result<(), Box<EvalAltResult>> {
|
|||||||
global::LOCAL_VALUE
|
global::LOCAL_VALUE
|
||||||
});
|
});
|
||||||
").expect_err("should error"),
|
").expect_err("should error"),
|
||||||
EvalAltResult::ErrorInFunctionCall(_, _, err, _)
|
EvalAltResult::ErrorInFunctionCall(.., err, _)
|
||||||
if matches!(&*err, EvalAltResult::ErrorVariableNotFound(v, _) if v == "global::LOCAL_VALUE")
|
if matches!(&*err, EvalAltResult::ErrorVariableNotFound(v, ..) if v == "global::LOCAL_VALUE")
|
||||||
));
|
));
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
@ -170,7 +170,7 @@ fn test_function_pointers() -> Result<(), Box<EvalAltResult>> {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine.eval::<INT>(r#"let f = Fn("abc"); f.call(0)"#).expect_err("should error"),
|
*engine.eval::<INT>(r#"let f = Fn("abc"); f.call(0)"#).expect_err("should error"),
|
||||||
EvalAltResult::ErrorFunctionNotFound(f, _) if f.starts_with("abc (")
|
EvalAltResult::ErrorFunctionNotFound(f, ..) if f.starts_with("abc (")
|
||||||
));
|
));
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
@ -249,7 +249,7 @@ fn test_internal_fn_bang() -> Result<(), Box<EvalAltResult>> {
|
|||||||
)
|
)
|
||||||
.expect_err("should error")
|
.expect_err("should error")
|
||||||
.0,
|
.0,
|
||||||
ParseErrorType::MalformedCapture(_)
|
ParseErrorType::MalformedCapture(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -53,7 +53,7 @@ b`: 1}; y["a\nb"]
|
|||||||
*engine
|
*engine
|
||||||
.eval::<INT>("let y = #{`a${1}`: 1}; y.a1")
|
.eval::<INT>("let y = #{`a${1}`: 1}; y.a1")
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorParsing(ParseErrorType::PropertyExpected, _)
|
EvalAltResult::ErrorParsing(ParseErrorType::PropertyExpected, ..)
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(engine.eval::<bool>(r#"let y = #{a: 1, b: 2, c: 3}; "c" in y"#)?);
|
assert!(engine.eval::<bool>(r#"let y = #{a: 1, b: 2, c: 3}; "c" in y"#)?);
|
||||||
@ -205,7 +205,7 @@ fn test_map_json() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine.parse_json(" 123", true).expect_err("should error"),
|
*engine.parse_json(" 123", true).expect_err("should error"),
|
||||||
EvalAltResult::ErrorParsing(ParseErrorType::MissingToken(token, _), _)
|
EvalAltResult::ErrorParsing(ParseErrorType::MissingToken(token, ..), ..)
|
||||||
if token == "{"
|
if token == "{"
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -37,37 +37,37 @@ fn test_math() -> Result<(), Box<EvalAltResult>> {
|
|||||||
*engine
|
*engine
|
||||||
.eval::<INT>("abs(-9223372036854775808)")
|
.eval::<INT>("abs(-9223372036854775808)")
|
||||||
.expect_err("expects negation overflow"),
|
.expect_err("expects negation overflow"),
|
||||||
EvalAltResult::ErrorArithmetic(_, _)
|
EvalAltResult::ErrorArithmetic(..)
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine
|
*engine
|
||||||
.eval::<INT>("9223372036854775807 + 1")
|
.eval::<INT>("9223372036854775807 + 1")
|
||||||
.expect_err("expects overflow"),
|
.expect_err("expects overflow"),
|
||||||
EvalAltResult::ErrorArithmetic(_, _)
|
EvalAltResult::ErrorArithmetic(..)
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine
|
*engine
|
||||||
.eval::<INT>("-9223372036854775808 - 1")
|
.eval::<INT>("-9223372036854775808 - 1")
|
||||||
.expect_err("expects underflow"),
|
.expect_err("expects underflow"),
|
||||||
EvalAltResult::ErrorArithmetic(_, _)
|
EvalAltResult::ErrorArithmetic(..)
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine
|
*engine
|
||||||
.eval::<INT>("9223372036854775807 * 9223372036854775807")
|
.eval::<INT>("9223372036854775807 * 9223372036854775807")
|
||||||
.expect_err("expects overflow"),
|
.expect_err("expects overflow"),
|
||||||
EvalAltResult::ErrorArithmetic(_, _)
|
EvalAltResult::ErrorArithmetic(..)
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine
|
*engine
|
||||||
.eval::<INT>("9223372036854775807 / 0")
|
.eval::<INT>("9223372036854775807 / 0")
|
||||||
.expect_err("expects division by zero"),
|
.expect_err("expects division by zero"),
|
||||||
EvalAltResult::ErrorArithmetic(_, _)
|
EvalAltResult::ErrorArithmetic(..)
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine
|
*engine
|
||||||
.eval::<INT>("9223372036854775807 % 0")
|
.eval::<INT>("9223372036854775807 % 0")
|
||||||
.expect_err("expects division by zero"),
|
.expect_err("expects division by zero"),
|
||||||
EvalAltResult::ErrorArithmetic(_, _)
|
EvalAltResult::ErrorArithmetic(..)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,31 +77,31 @@ fn test_math() -> Result<(), Box<EvalAltResult>> {
|
|||||||
*engine
|
*engine
|
||||||
.eval::<INT>("2147483647 + 1")
|
.eval::<INT>("2147483647 + 1")
|
||||||
.expect_err("expects overflow"),
|
.expect_err("expects overflow"),
|
||||||
EvalAltResult::ErrorArithmetic(_, _)
|
EvalAltResult::ErrorArithmetic(..)
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine
|
*engine
|
||||||
.eval::<INT>("-2147483648 - 1")
|
.eval::<INT>("-2147483648 - 1")
|
||||||
.expect_err("expects underflow"),
|
.expect_err("expects underflow"),
|
||||||
EvalAltResult::ErrorArithmetic(_, _)
|
EvalAltResult::ErrorArithmetic(..)
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine
|
*engine
|
||||||
.eval::<INT>("2147483647 * 2147483647")
|
.eval::<INT>("2147483647 * 2147483647")
|
||||||
.expect_err("expects overflow"),
|
.expect_err("expects overflow"),
|
||||||
EvalAltResult::ErrorArithmetic(_, _)
|
EvalAltResult::ErrorArithmetic(..)
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine
|
*engine
|
||||||
.eval::<INT>("2147483647 / 0")
|
.eval::<INT>("2147483647 / 0")
|
||||||
.expect_err("expects division by zero"),
|
.expect_err("expects division by zero"),
|
||||||
EvalAltResult::ErrorArithmetic(_, _)
|
EvalAltResult::ErrorArithmetic(..)
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine
|
*engine
|
||||||
.eval::<INT>("2147483647 % 0")
|
.eval::<INT>("2147483647 % 0")
|
||||||
.expect_err("expects division by zero"),
|
.expect_err("expects division by zero"),
|
||||||
EvalAltResult::ErrorArithmetic(_, _)
|
EvalAltResult::ErrorArithmetic(..)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ fn test_mismatched_op() {
|
|||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine.eval::<INT>(r#""hello, " + "world!""#).expect_err("expects error"),
|
*engine.eval::<INT>(r#""hello, " + "world!""#).expect_err("expects error"),
|
||||||
EvalAltResult::ErrorMismatchOutputType(need, actual, _) if need == std::any::type_name::<INT>() && actual == "string"
|
EvalAltResult::ErrorMismatchOutputType(need, actual, ..) if need == std::any::type_name::<INT>() && actual == "string"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,18 +35,18 @@ fn test_mismatched_op_custom_type() -> Result<(), Box<EvalAltResult>> {
|
|||||||
let y = new_ts();
|
let y = new_ts();
|
||||||
x == y
|
x == y
|
||||||
").expect_err("should error"),
|
").expect_err("should error"),
|
||||||
EvalAltResult::ErrorFunctionNotFound(f, _) if f == "== (TestStruct, TestStruct)"));
|
EvalAltResult::ErrorFunctionNotFound(f, ..) if f == "== (TestStruct, TestStruct)"));
|
||||||
|
|
||||||
assert!(!engine.eval::<bool>("new_ts() == 42")?);
|
assert!(!engine.eval::<bool>("new_ts() == 42")?);
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine.eval::<INT>("60 + new_ts()").expect_err("should error"),
|
*engine.eval::<INT>("60 + new_ts()").expect_err("should error"),
|
||||||
EvalAltResult::ErrorFunctionNotFound(f, _) if f == format!("+ ({}, TestStruct)", std::any::type_name::<INT>())
|
EvalAltResult::ErrorFunctionNotFound(f, ..) if f == format!("+ ({}, TestStruct)", std::any::type_name::<INT>())
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine.eval::<TestStruct>("42").expect_err("should error"),
|
*engine.eval::<TestStruct>("42").expect_err("should error"),
|
||||||
EvalAltResult::ErrorMismatchOutputType(need, actual, _)
|
EvalAltResult::ErrorMismatchOutputType(need, actual, ..)
|
||||||
if need == "TestStruct" && actual == std::any::type_name::<INT>()
|
if need == "TestStruct" && actual == std::any::type_name::<INT>()
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -214,7 +214,7 @@ fn test_module_resolver() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"#
|
"#
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorTooManyModules(_)
|
EvalAltResult::ErrorTooManyModules(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
@ -237,7 +237,7 @@ fn test_module_resolver() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"#
|
"#
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorInFunctionCall(fn_name, _, _, _) if fn_name == "foo"
|
EvalAltResult::ErrorInFunctionCall(fn_name, _, ..) if fn_name == "foo"
|
||||||
));
|
));
|
||||||
|
|
||||||
engine.set_max_modules(1000);
|
engine.set_max_modules(1000);
|
||||||
@ -369,7 +369,7 @@ fn test_module_from_ast() -> Result<(), Box<EvalAltResult>> {
|
|||||||
*engine
|
*engine
|
||||||
.run(r#"import "testing" as ttt; ttt::hidden()"#)
|
.run(r#"import "testing" as ttt; ttt::hidden()"#)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorFunctionNotFound(fn_name, _) if fn_name == "ttt::hidden ()"
|
EvalAltResult::ErrorFunctionNotFound(fn_name, ..) if fn_name == "ttt::hidden ()"
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -381,13 +381,13 @@ fn test_module_export() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
engine.compile("let x = 10; { export x; }").expect_err("should error"),
|
engine.compile("let x = 10; { export x; }").expect_err("should error"),
|
||||||
ParseError(x, _) if *x == ParseErrorType::WrongExport
|
ParseError(x, ..) if *x == ParseErrorType::WrongExport
|
||||||
));
|
));
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
engine.compile("fn abc(x) { export x; }").expect_err("should error"),
|
engine.compile("fn abc(x) { export x; }").expect_err("should error"),
|
||||||
ParseError(x, _) if *x == ParseErrorType::WrongExport
|
ParseError(x, ..) if *x == ParseErrorType::WrongExport
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -19,7 +19,7 @@ fn test_max_operations() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine.run("for x in 0..500 {}").expect_err("should error"),
|
*engine.run("for x in 0..500 {}").expect_err("should error"),
|
||||||
EvalAltResult::ErrorTooManyOperations(_)
|
EvalAltResult::ErrorTooManyOperations(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
engine.set_max_operations(0);
|
engine.set_max_operations(0);
|
||||||
@ -44,7 +44,7 @@ fn test_max_operations_literal() -> Result<(), Box<EvalAltResult>> {
|
|||||||
*engine
|
*engine
|
||||||
.run("[1, 2, 3, 4, 5, 6, 7, 8, 9]")
|
.run("[1, 2, 3, 4, 5, 6, 7, 8, 9]")
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorTooManyOperations(_)
|
EvalAltResult::ErrorTooManyOperations(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
@ -55,7 +55,7 @@ fn test_max_operations_literal() -> Result<(), Box<EvalAltResult>> {
|
|||||||
*engine
|
*engine
|
||||||
.run("#{a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9}")
|
.run("#{a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9}")
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorTooManyOperations(_)
|
EvalAltResult::ErrorTooManyOperations(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -111,7 +111,7 @@ fn test_max_operations_functions() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorTooManyOperations(_)
|
EvalAltResult::ErrorTooManyOperations(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -138,7 +138,7 @@ fn test_max_operations_eval() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"#
|
"#
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorInFunctionCall(_, _, err, _) if matches!(*err, EvalAltResult::ErrorTooManyOperations(_))
|
EvalAltResult::ErrorInFunctionCall(.., err, _) if matches!(*err, EvalAltResult::ErrorTooManyOperations(..))
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -163,7 +163,7 @@ fn test_max_operations_progress() -> Result<(), Box<EvalAltResult>> {
|
|||||||
*engine
|
*engine
|
||||||
.run("for x in 0..500 {}")
|
.run("for x in 0..500 {}")
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorTerminated(x, _) if x.as_int()? == 42
|
EvalAltResult::ErrorTerminated(x, ..) if x.as_int()? == 42
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -27,12 +27,12 @@ fn test_ops_other_number_types() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine.eval_with_scope::<bool>(&mut scope, "x == 42").expect_err("should error"),
|
*engine.eval_with_scope::<bool>(&mut scope, "x == 42").expect_err("should error"),
|
||||||
EvalAltResult::ErrorFunctionNotFound(f, _) if f.starts_with("== (u16,")
|
EvalAltResult::ErrorFunctionNotFound(f, ..) if f.starts_with("== (u16,")
|
||||||
));
|
));
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine.eval_with_scope::<bool>(&mut scope, "x == 42.0").expect_err("should error"),
|
*engine.eval_with_scope::<bool>(&mut scope, "x == 42.0").expect_err("should error"),
|
||||||
EvalAltResult::ErrorFunctionNotFound(f, _) if f.starts_with("== (u16,")
|
EvalAltResult::ErrorFunctionNotFound(f, ..) if f.starts_with("== (u16,")
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(!engine.eval_with_scope::<bool>(&mut scope, r#"x == "hello""#)?);
|
assert!(!engine.eval_with_scope::<bool>(&mut scope, r#"x == "hello""#)?);
|
||||||
|
@ -93,7 +93,7 @@ fn test_plugins_package() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
matches!(*engine.run("const A = [1, 2, 3]; A.test(42);").expect_err("should error"),
|
matches!(*engine.run("const A = [1, 2, 3]; A.test(42);").expect_err("should error"),
|
||||||
EvalAltResult::ErrorAssignmentToConstant(x, _) if x == "array")
|
EvalAltResult::ErrorAssignmentToConstant(x, ..) if x == "array")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ fn test_stack_overflow_fn_calls() -> Result<(), Box<EvalAltResult>> {
|
|||||||
max + 1
|
max + 1
|
||||||
))
|
))
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorStackOverflow(_)
|
EvalAltResult::ErrorStackOverflow(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -117,7 +117,7 @@ fn test_string_mut() -> Result<(), Box<EvalAltResult>> {
|
|||||||
assert_eq!(engine.eval::<INT>(r#"bar("hello")"#)?, 5);
|
assert_eq!(engine.eval::<INT>(r#"bar("hello")"#)?, 5);
|
||||||
assert!(
|
assert!(
|
||||||
matches!(*engine.eval::<INT>(r#"baz("hello")"#).expect_err("should error"),
|
matches!(*engine.eval::<INT>(r#"baz("hello")"#).expect_err("should error"),
|
||||||
EvalAltResult::ErrorFunctionNotFound(f, _) if f == "baz (&str | ImmutableString | String)"
|
EvalAltResult::ErrorFunctionNotFound(f, ..) if f == "baz (&str | ImmutableString | String)"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -6,12 +6,12 @@ fn test_throw() {
|
|||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine.run("if true { throw 42 }").expect_err("expects error"),
|
*engine.run("if true { throw 42 }").expect_err("expects error"),
|
||||||
EvalAltResult::ErrorRuntime(s, _) if s.as_int().unwrap() == 42
|
EvalAltResult::ErrorRuntime(s, ..) if s.as_int().unwrap() == 42
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine.run(r#"throw"#).expect_err("expects error"),
|
*engine.run(r#"throw"#).expect_err("expects error"),
|
||||||
EvalAltResult::ErrorRuntime(s, _) if s.is::<()>()
|
EvalAltResult::ErrorRuntime(s, ..) if s.is::<()>()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ fn test_try_catch() -> Result<(), Box<EvalAltResult>> {
|
|||||||
*engine
|
*engine
|
||||||
.run("try { 42/0; } catch { throw; }")
|
.run("try { 42/0; } catch { throw; }")
|
||||||
.expect_err("expects error"),
|
.expect_err("expects error"),
|
||||||
EvalAltResult::ErrorArithmetic(_, _)
|
EvalAltResult::ErrorArithmetic(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -115,7 +115,7 @@ fn test_var_resolver() -> Result<(), Box<EvalAltResult>> {
|
|||||||
assert_eq!(engine.eval_with_scope::<INT>(&mut scope, "chameleon")?, 1);
|
assert_eq!(engine.eval_with_scope::<INT>(&mut scope, "chameleon")?, 1);
|
||||||
assert!(
|
assert!(
|
||||||
matches!(*engine.eval_with_scope::<INT>(&mut scope, "DO_NOT_USE").expect_err("should error"),
|
matches!(*engine.eval_with_scope::<INT>(&mut scope, "DO_NOT_USE").expect_err("should error"),
|
||||||
EvalAltResult::ErrorVariableNotFound(n, _) if n == "DO_NOT_USE")
|
EvalAltResult::ErrorVariableNotFound(n, ..) if n == "DO_NOT_USE")
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
Loading…
Reference in New Issue
Block a user