Merge pull request #202 from schungx/master
Eliminate compilation warnings.
This commit is contained in:
commit
5450f66278
@ -73,7 +73,7 @@ Licensed under either:
|
|||||||
* [Apache License, Version 2.0](https://github.com/jonathandturner/rhai/blob/master/LICENSE-APACHE.txt), or
|
* [Apache License, Version 2.0](https://github.com/jonathandturner/rhai/blob/master/LICENSE-APACHE.txt), or
|
||||||
* [MIT license](https://github.com/jonathandturner/rhai/blob/master/LICENSE-MIT.txt)
|
* [MIT license](https://github.com/jonathandturner/rhai/blob/master/LICENSE-MIT.txt)
|
||||||
|
|
||||||
at your option.
|
at your choice.
|
||||||
|
|
||||||
Unless explicitly stated otherwise, any contribution intentionally submitted
|
Unless explicitly stated otherwise, any contribution intentionally submitted
|
||||||
for inclusion in this crate, as defined in the Apache-2.0 license, shall
|
for inclusion in this crate, as defined in the Apache-2.0 license, shall
|
||||||
|
@ -5,8 +5,9 @@ The Rhai Scripting Language
|
|||||||
1. [Features](about/features.md)
|
1. [Features](about/features.md)
|
||||||
2. [Supported Targets and Builds](about/targets.md)
|
2. [Supported Targets and Builds](about/targets.md)
|
||||||
3. [What Rhai Isn't](about/non-design.md)
|
3. [What Rhai Isn't](about/non-design.md)
|
||||||
4. [Related Resources](about/related.md)
|
4. [Licensing](about/license.md)
|
||||||
3. [Getting Started](start/index.md)
|
5. [Related Resources](about/related.md)
|
||||||
|
2. [Getting Started](start/index.md)
|
||||||
1. [Online Playground](start/playground.md)
|
1. [Online Playground](start/playground.md)
|
||||||
2. [Install the Rhai Crate](start/install.md)
|
2. [Install the Rhai Crate](start/install.md)
|
||||||
3. [Optional Features](start/features.md)
|
3. [Optional Features](start/features.md)
|
||||||
@ -18,14 +19,14 @@ The Rhai Scripting Language
|
|||||||
5. [Examples](start/examples/index.md)
|
5. [Examples](start/examples/index.md)
|
||||||
1. [Rust](start/examples/rust.md)
|
1. [Rust](start/examples/rust.md)
|
||||||
2. [Scripts](start/examples/scripts.md)
|
2. [Scripts](start/examples/scripts.md)
|
||||||
4. [Using the `Engine`](engine/index.md)
|
3. [Using the `Engine`](engine/index.md)
|
||||||
1. [Hello World in Rhai - Evaluate a Script](engine/hello-world.md)
|
1. [Hello World in Rhai - Evaluate a Script](engine/hello-world.md)
|
||||||
2. [Compile a Script to AST for Repeated Evaluations](engine/compile.md)
|
2. [Compile to AST for Repeated Evaluations](engine/compile.md)
|
||||||
3. [Call a Rhai Function from Rust](engine/call-fn.md)
|
3. [Call a Rhai Function from Rust](engine/call-fn.md)
|
||||||
4. [Create a Rust Anonymous Function from a Rhai Function](engine/func.md)
|
4. [Create a Rust Anonymous Function from a Rhai Function](engine/func.md)
|
||||||
5. [Evaluate Expressions Only](engine/expressions.md)
|
5. [Evaluate Expressions Only](engine/expressions.md)
|
||||||
6. [Raw Engine](engine/raw.md)
|
6. [Raw Engine](engine/raw.md)
|
||||||
5. [Extend Rhai with Rust](rust/index.md)
|
4. [Extend Rhai with Rust](rust/index.md)
|
||||||
1. [Traits](rust/traits.md)
|
1. [Traits](rust/traits.md)
|
||||||
2. [Register a Rust Function](rust/functions.md)
|
2. [Register a Rust Function](rust/functions.md)
|
||||||
1. [String Parameters in Rust Functions](rust/strings.md)
|
1. [String Parameters in Rust Functions](rust/strings.md)
|
||||||
@ -43,7 +44,7 @@ The Rhai Scripting Language
|
|||||||
4. [Printing Custom Types](rust/print-custom.md)
|
4. [Printing Custom Types](rust/print-custom.md)
|
||||||
9. [Scope - Initializing and Maintaining State](rust/scope.md)
|
9. [Scope - Initializing and Maintaining State](rust/scope.md)
|
||||||
10. [Engine Configuration Options](rust/options.md)
|
10. [Engine Configuration Options](rust/options.md)
|
||||||
6. [Rhai Language Reference](language/index.md)
|
5. [Rhai Language Reference](language/index.md)
|
||||||
1. [Comments](language/comments.md)
|
1. [Comments](language/comments.md)
|
||||||
2. [Values and Types](language/values-and-types.md)
|
2. [Values and Types](language/values-and-types.md)
|
||||||
1. [Dynamic Values](language/dynamic.md)
|
1. [Dynamic Values](language/dynamic.md)
|
||||||
@ -64,28 +65,29 @@ The Rhai Scripting Language
|
|||||||
5. [Variables](language/variables.md)
|
5. [Variables](language/variables.md)
|
||||||
6. [Constants](language/constants.md)
|
6. [Constants](language/constants.md)
|
||||||
7. [Logic Operators](language/logic.md)
|
7. [Logic Operators](language/logic.md)
|
||||||
8. [If Statement](language/if.md)
|
8. [Other Operators](language/other-op.md)
|
||||||
9. [While Loop](language/while.md)
|
9. [If Statement](language/if.md)
|
||||||
10. [Loop Statement](language/loop.md)
|
10. [While Loop](language/while.md)
|
||||||
11. [For Loop](language/for.md)
|
11. [Loop Statement](language/loop.md)
|
||||||
12. [Return Values](language/return.md)
|
12. [For Loop](language/for.md)
|
||||||
13. [Throw Exception on Error](language/throw.md)
|
13. [Return Values](language/return.md)
|
||||||
14. [Functions](language/functions.md)
|
14. [Throw Exception on Error](language/throw.md)
|
||||||
|
15. [Functions](language/functions.md)
|
||||||
1. [Call Method as Function](language/method.md)
|
1. [Call Method as Function](language/method.md)
|
||||||
2. [Overloading](language/overload.md)
|
2. [Overloading](language/overload.md)
|
||||||
3. [Namespaces](language/fn-namespaces.md)
|
3. [Namespaces](language/fn-namespaces.md)
|
||||||
4. [Function Pointers](language/fn-ptr.md)
|
4. [Function Pointers](language/fn-ptr.md)
|
||||||
5. [Anonymous Functions](language/fn-anon.md)
|
5. [Anonymous Functions](language/fn-anon.md)
|
||||||
6. [Currying](language/fn-curry.md)
|
6. [Currying](language/fn-curry.md)
|
||||||
15. [Print and Debug](language/print-debug.md)
|
16. [Print and Debug](language/print-debug.md)
|
||||||
16. [Modules](language/modules/index.md)
|
17. [Modules](language/modules/index.md)
|
||||||
1. [Export Variables, Functions and Sub-Modules](language/modules/export.md)
|
1. [Export Variables, Functions and Sub-Modules](language/modules/export.md)
|
||||||
2. [Import Modules](language/modules/import.md)
|
2. [Import Modules](language/modules/import.md)
|
||||||
3. [Create from Rust](rust/modules/index.md)
|
3. [Create from Rust](rust/modules/index.md)
|
||||||
4. [Create from AST](language/modules/ast.md)
|
4. [Create from AST](language/modules/ast.md)
|
||||||
5. [Module Resolvers](rust/modules/resolvers.md)
|
5. [Module Resolvers](rust/modules/resolvers.md)
|
||||||
1. [Custom Implementation](rust/modules/imp-resolver.md)
|
1. [Custom Implementation](rust/modules/imp-resolver.md)
|
||||||
7. [Safety and Protection](safety/index.md)
|
6. [Safety and Protection](safety/index.md)
|
||||||
1. [Checked Arithmetic](safety/checked.md)
|
1. [Checked Arithmetic](safety/checked.md)
|
||||||
2. [Sand-Boxing](safety/sandbox.md)
|
2. [Sand-Boxing](safety/sandbox.md)
|
||||||
3. [Maximum Length of Strings](safety/max-string-size.md)
|
3. [Maximum Length of Strings](safety/max-string-size.md)
|
||||||
@ -96,7 +98,7 @@ The Rhai Scripting Language
|
|||||||
7. [Maximum Number of Modules](safety/max-modules.md)
|
7. [Maximum Number of Modules](safety/max-modules.md)
|
||||||
8. [Maximum Call Stack Depth](safety/max-call-stack.md)
|
8. [Maximum Call Stack Depth](safety/max-call-stack.md)
|
||||||
9. [Maximum Statement Depth](safety/max-stmt-depth.md)
|
9. [Maximum Statement Depth](safety/max-stmt-depth.md)
|
||||||
8. [Advanced Topics](advanced.md)
|
7. [Advanced Topics](advanced.md)
|
||||||
1. [Object-Oriented Programming (OOP)](language/oop.md)
|
1. [Object-Oriented Programming (OOP)](language/oop.md)
|
||||||
2. [Serialization/Deserialization of `Dynamic` with `serde`](rust/serde.md)
|
2. [Serialization/Deserialization of `Dynamic` with `serde`](rust/serde.md)
|
||||||
3. [Script Optimization](engine/optimize/index.md)
|
3. [Script Optimization](engine/optimize/index.md)
|
||||||
@ -112,7 +114,7 @@ The Rhai Scripting Language
|
|||||||
2. [Custom Operators](engine/custom-op.md)
|
2. [Custom Operators](engine/custom-op.md)
|
||||||
3. [Extending with Custom Syntax](engine/custom-syntax.md)
|
3. [Extending with Custom Syntax](engine/custom-syntax.md)
|
||||||
6. [Eval Statement](language/eval.md)
|
6. [Eval Statement](language/eval.md)
|
||||||
9. [Appendix](appendix/index.md)
|
8. [Appendix](appendix/index.md)
|
||||||
1. [Keywords](appendix/keywords.md)
|
1. [Keywords](appendix/keywords.md)
|
||||||
2. [Operators and Symbols](appendix/operators.md)
|
2. [Operators and Symbols](appendix/operators.md)
|
||||||
3. [Literals](appendix/literals.md)
|
3. [Literals](appendix/literals.md)
|
||||||
|
@ -7,6 +7,9 @@ Rhai is an embedded scripting language and evaluation engine for Rust that gives
|
|||||||
to add scripting to any application.
|
to add scripting to any application.
|
||||||
|
|
||||||
|
|
||||||
This Book is for version {{version}} of Rhai.
|
Versions
|
||||||
|
--------
|
||||||
|
|
||||||
|
This Book is for version **{{version}}** of Rhai.
|
||||||
|
|
||||||
For the latest development version, see [here]({{rootUrl}}/vnext/).
|
For the latest development version, see [here]({{rootUrl}}/vnext/).
|
||||||
|
16
doc/src/about/license.md
Normal file
16
doc/src/about/license.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
Licensing
|
||||||
|
=========
|
||||||
|
|
||||||
|
{{#include ../links.md}}
|
||||||
|
|
||||||
|
Rhai is licensed under either:
|
||||||
|
|
||||||
|
* [Apache License, Version 2.0]({{repoHome}}/LICENSE-APACHE.txt), or
|
||||||
|
|
||||||
|
* [MIT license]({{repoHome}}/LICENSE-MIT.txt)
|
||||||
|
|
||||||
|
at your choice.
|
||||||
|
|
||||||
|
Unless explicitly stated otherwise, any contribution intentionally submitted for inclusion in this crate,
|
||||||
|
as defined in the Apache-2.0 license, shall be dual-licensed as above,
|
||||||
|
without any additional terms or conditions.
|
@ -18,21 +18,38 @@ It doesn't attempt to be a new language. For example:
|
|||||||
|
|
||||||
* No first-class functions - Code your functions in Rust instead, and register them with Rhai.
|
* No first-class functions - Code your functions in Rust instead, and register them with Rhai.
|
||||||
|
|
||||||
There is, however, support for simple [function pointers] allowing runtime dispatch by function name.
|
There is, however, support for simple [function pointers] to allow runtime dispatch by function name.
|
||||||
|
|
||||||
* No garbage collection - this should be expected, so...
|
* No garbage collection - this should be expected, so...
|
||||||
|
|
||||||
* No closures - do your closure magic in Rust instead; [turn a Rhai scripted function into a Rust closure]({{rootUrl}}/engine/call-fn.md).
|
* No closures - do your closure magic in Rust instead; [turn a Rhai scripted function into a Rust closure]({{rootUrl}}/engine/call-fn.md).
|
||||||
|
|
||||||
|
But you can [curry][currying] a [function pointer] with arguments to simulate it somewhat.
|
||||||
|
|
||||||
* No byte-codes/JIT - Rhai has an AST-walking interpreter which will not win any speed races. The purpose of Rhai is not
|
* No byte-codes/JIT - Rhai has an AST-walking interpreter which will not win any speed races. The purpose of Rhai is not
|
||||||
to be extremely _fast_, but to make it as easy as possible to integrate with native Rust applications.
|
to be extremely _fast_, but to make it as easy as possible to integrate with native Rust applications.
|
||||||
|
|
||||||
|
|
||||||
|
Do Not Write The Next 4D VR Game in Rhai
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
Due to this intended usage, Rhai deliberately keeps the language simple and small by omitting advanced language features
|
Due to this intended usage, Rhai deliberately keeps the language simple and small by omitting advanced language features
|
||||||
such as classes, inheritance, first-class functions, closures, concurrency, byte-codes, JIT etc.
|
such as classes, inheritance, first-class functions, closures, concurrency, byte-codes, JIT etc.
|
||||||
|
|
||||||
Avoid the temptation to write full-fledge application logic entirely in Rhai - that use case is best fulfilled by
|
Avoid the temptation to write full-fledge application logic entirely in Rhai - that use case is best fulfilled by
|
||||||
more complete languages such as JavaScript or Lua.
|
more complete languages such as JavaScript or Lua.
|
||||||
|
|
||||||
Therefore, in actual practice, it is usually best to expose a Rust API into Rhai for scripts to call.
|
|
||||||
All your core functionalities should be in Rust.
|
Thin Dynamic Wrapper Layer Over Rust Code
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
In actual practice, it is usually best to expose a Rust API into Rhai for scripts to call.
|
||||||
|
|
||||||
|
All the core functionalities should be written in Rust, with Rhai being the dynamic _control_ layer.
|
||||||
|
|
||||||
This is similar to some dynamic languages where most of the core functionalities reside in a C/C++ standard library.
|
This is similar to some dynamic languages where most of the core functionalities reside in a C/C++ standard library.
|
||||||
|
|
||||||
|
Another similar scenario is a web front-end driving back-end services written in a systems language.
|
||||||
|
In this case, JavaScript takes the role of Rhai while the back-end language, well... it can actually also be Rust.
|
||||||
|
Except that Rhai integrates with Rust _much_ more tightly, removing the need for interfaces such
|
||||||
|
as XHR calls and payload encoding such as JSON.
|
||||||
|
@ -5,7 +5,7 @@ Advanced Topics
|
|||||||
|
|
||||||
This section covers advanced features such as:
|
This section covers advanced features such as:
|
||||||
|
|
||||||
* Simulated [Object Oriented Programming][OOP].
|
* Simulated [Object Oriented Programming (OOP)][OOP].
|
||||||
|
|
||||||
* [`serde`] integration.
|
* [`serde`] integration.
|
||||||
|
|
||||||
@ -13,4 +13,6 @@ This section covers advanced features such as:
|
|||||||
|
|
||||||
* [Domain-Specific Languages][DSL].
|
* [Domain-Specific Languages][DSL].
|
||||||
|
|
||||||
|
* Low-level [function registration API]({{rootUrl}}/rust/register-raw.md)
|
||||||
|
|
||||||
* The dreaded (or beloved for those with twisted tastes) [`eval`] statement.
|
* The dreaded (or beloved for those with twisted tastes) [`eval`] statement.
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
"version": "0.18.0",
|
"version": "0.18.0",
|
||||||
|
"repoHome": "https://github.com/jonathandturner/rhai/blob/master",
|
||||||
|
"repoTree": "https://github.com/jonathandturner/rhai/tree/master",
|
||||||
"rootUrl": "",
|
"rootUrl": "",
|
||||||
"rootUrlX": "/rhai",
|
"rootUrlX": "/rhai",
|
||||||
"rootUrlXX": "/rhai/vnext"
|
"rootUrlXX": "/rhai/vnext"
|
||||||
|
@ -22,19 +22,31 @@ fn main() -> Result<(), Box<EvalAltResult>>
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`rhai::EvalAltResult` is a Rust `enum` containing all errors encountered during the parsing or evaluation process.
|
Evaluate a script file directly:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// 'eval_file' takes a 'PathBuf'
|
||||||
|
let result = engine.eval_file::<i64>("hello_world.rhai".into())?;
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Evaluate a Script
|
Error Type
|
||||||
----------------
|
----------
|
||||||
|
|
||||||
The type parameter is used to specify the type of the return value, which _must_ match the actual type or an error is returned.
|
`rhai::EvalAltResult` is the standard Rhai error type, which is a Rust `enum` containing all errors encountered
|
||||||
Rhai is very strict here.
|
during the parsing or evaluation process.
|
||||||
|
|
||||||
Use [`Dynamic`] for uncertain return types.
|
|
||||||
|
Return Type
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The type parameter for `Engine::eval` is used to specify the type of the return value,
|
||||||
|
which _must_ match the actual type or an error is returned. Rhai is very strict here.
|
||||||
|
|
||||||
There are two ways to specify the return type - _turbofish_ notation, or type inference.
|
There are two ways to specify the return type - _turbofish_ notation, or type inference.
|
||||||
|
|
||||||
|
Use [`Dynamic`] for uncertain return types.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let result = engine.eval::<i64>("40 + 2")?; // return type is i64, specified using 'turbofish' notation
|
let result = engine.eval::<i64>("40 + 2")?; // return type is i64, specified using 'turbofish' notation
|
||||||
|
|
||||||
@ -46,9 +58,3 @@ let result: Dynamic = engine.eval("boo()")?; // use 'Dynamic' if you're not s
|
|||||||
|
|
||||||
let result = engine.eval::<String>("40 + 2")?; // returns an error because the actual return type is i64, not String
|
let result = engine.eval::<String>("40 + 2")?; // returns an error because the actual return type is i64, not String
|
||||||
```
|
```
|
||||||
|
|
||||||
Evaluate a script file directly:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
let result = engine.eval_file::<i64>("hello_world.rhai".into())?; // 'eval_file' takes a 'PathBuf'
|
|
||||||
```
|
|
||||||
|
@ -10,7 +10,10 @@ In many controlled embedded environments, however, these may not be needed and u
|
|||||||
application code storage space.
|
application code storage space.
|
||||||
|
|
||||||
Use `Engine::new_raw` to create a _raw_ `Engine`, in which only a minimal set of
|
Use `Engine::new_raw` to create a _raw_ `Engine`, in which only a minimal set of
|
||||||
basic arithmetic and logical operators are supported.
|
basic arithmetic and logical operators are supported (see below).
|
||||||
|
|
||||||
|
To add more functionalities to a _raw_ `Engine`, load [packages] into it.
|
||||||
|
|
||||||
|
|
||||||
Built-in Operators
|
Built-in Operators
|
||||||
------------------
|
------------------
|
||||||
@ -20,7 +23,7 @@ Built-in Operators
|
|||||||
| `+`, | `+=` | `INT`, `FLOAT` (if not [`no_float`]), `ImmutableString` |
|
| `+`, | `+=` | `INT`, `FLOAT` (if not [`no_float`]), `ImmutableString` |
|
||||||
| `-`, `*`, `/`, `%`, `~`, | `-=`, `*=`, `/=`, `%=`, `~=` | `INT`, `FLOAT` (if not [`no_float`]) |
|
| `-`, `*`, `/`, `%`, `~`, | `-=`, `*=`, `/=`, `%=`, `~=` | `INT`, `FLOAT` (if not [`no_float`]) |
|
||||||
| `<<`, `>>`, `^`, | `<<=`, `>>=`, `^=` | `INT` |
|
| `<<`, `>>`, `^`, | `<<=`, `>>=`, `^=` | `INT` |
|
||||||
| `&`, `|`, | `&=`, `|=` | `INT`, `bool` |
|
| `&`, <code>\|</code>, | `&=`, <code>\|=</code> | `INT`, `bool` |
|
||||||
| `&&`, `||` | | `bool` |
|
| `&&`, <code>\|\|</code> | | `bool` |
|
||||||
| `==`, `!=` | | `INT`, `FLOAT` (if not [`no_float`]), `bool`, `char`, `()`, `ImmutableString` |
|
| `==`, `!=` | | `INT`, `FLOAT` (if not [`no_float`]), `bool`, `char`, `()`, `ImmutableString` |
|
||||||
| `>`, `>=`, `<`, `<=` | | `INT`, `FLOAT` (if not [`no_float`]), `char`, `()`, `ImmutableString` |
|
| `>`, `>=`, `<`, `<=` | | `INT`, `FLOAT` (if not [`no_float`]), `char`, `()`, `ImmutableString` |
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
{{#include ../links.md}}
|
{{#include ../links.md}}
|
||||||
|
|
||||||
Iterating through a range or an [array] is provided by the `for` ... `in` loop.
|
Iterating through a range or an [array], or any type with a registered _iterator_,
|
||||||
|
is provided by the `for` ... `in` loop.
|
||||||
|
|
||||||
Like C, `continue` can be used to skip to the next iteration, by-passing all following statements;
|
Like C, `continue` can be used to skip to the next iteration, by-passing all following statements;
|
||||||
`break` can be used to break out of the loop unconditionally.
|
`break` can be used to break out of the loop unconditionally.
|
||||||
|
@ -19,6 +19,9 @@ if foo(x) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Braces Are Mandatory
|
||||||
|
--------------------
|
||||||
|
|
||||||
Unlike C, the condition expression does _not_ need to be enclosed in parentheses '`(`' .. '`)`', but
|
Unlike C, the condition expression does _not_ need to be enclosed in parentheses '`(`' .. '`)`', but
|
||||||
all branches of the `if` statement must be enclosed within braces '`{`' .. '`}`',
|
all branches of the `if` statement must be enclosed within braces '`{`' .. '`}`',
|
||||||
even when there is only one statement inside the branch.
|
even when there is only one statement inside the branch.
|
||||||
|
@ -65,42 +65,3 @@ a() | b(); // both a() and b() are evaluated
|
|||||||
|
|
||||||
a() & b(); // both a() and b() are evaluated
|
a() & b(); // both a() and b() are evaluated
|
||||||
```
|
```
|
||||||
|
|
||||||
Compound Assignment Operators
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
```rust
|
|
||||||
let number = 9;
|
|
||||||
|
|
||||||
number += 8; // number = number + 8
|
|
||||||
|
|
||||||
number -= 7; // number = number - 7
|
|
||||||
|
|
||||||
number *= 6; // number = number * 6
|
|
||||||
|
|
||||||
number /= 5; // number = number / 5
|
|
||||||
|
|
||||||
number %= 4; // number = number % 4
|
|
||||||
|
|
||||||
number ~= 3; // number = number ~ 3
|
|
||||||
|
|
||||||
number <<= 2; // number = number << 2
|
|
||||||
|
|
||||||
number >>= 1; // number = number >> 1
|
|
||||||
|
|
||||||
number &= 0x00ff; // number = number & 0x00ff;
|
|
||||||
|
|
||||||
number |= 0x00ff; // number = number | 0x00ff;
|
|
||||||
|
|
||||||
number ^= 0x00ff; // number = number ^ 0x00ff;
|
|
||||||
```
|
|
||||||
|
|
||||||
The `+=` operator can also be used to build [strings]:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
let my_str = "abc";
|
|
||||||
my_str += "ABC";
|
|
||||||
my_str += 12345;
|
|
||||||
|
|
||||||
my_str == "abcABC12345"
|
|
||||||
```
|
|
||||||
|
@ -4,8 +4,8 @@ Call Method as Function
|
|||||||
{{#include ../links.md}}
|
{{#include ../links.md}}
|
||||||
|
|
||||||
|
|
||||||
First `&mut` Reference Parameter
|
First `&mut` Parameter
|
||||||
-------------------------------
|
----------------------
|
||||||
|
|
||||||
Property [getters/setters] and [methods][custom types] in a Rust custom type registered with the [`Engine`] can be called
|
Property [getters/setters] and [methods][custom types] in a Rust custom type registered with the [`Engine`] can be called
|
||||||
just like a regular function. In fact, like Rust, property getters/setters and object methods
|
just like a regular function. In fact, like Rust, property getters/setters and object methods
|
||||||
@ -37,19 +37,20 @@ array[0].update(); // <- call in method-call style will update 'a'
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Encouraged Usage
|
`&mut` is Efficient
|
||||||
----------------
|
------------------
|
||||||
|
|
||||||
Using a `&mut` first parameter is highly encouraged when using types that are expensive to clone,
|
Using a `&mut` first parameter is highly encouraged when using types that are expensive to clone,
|
||||||
even when the intention is not to mutate that argument, because it avoids cloning that argument value.
|
even when the intention is not to mutate that argument, because it avoids cloning that argument value.
|
||||||
|
|
||||||
For primary types that are cheap to clone, including `ImmutableString`, this is not necessary.
|
For primary types that are cheap to clone (e.g. those that implement `Copy`),
|
||||||
|
including `ImmutableString`, this is not necessary.
|
||||||
|
|
||||||
|
|
||||||
Avoid `&mut ImmutableString`
|
Avoid `&mut ImmutableString`
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
`ImmutableString`, Rhai internal [string] type, is an exception.
|
`ImmutableString`, Rhai's internal [string] type, is an exception.
|
||||||
|
|
||||||
`ImmutableString` is cheap to clone, but expensive to take a mutable reference (because the underlying
|
`ImmutableString` is cheap to clone, but expensive to take a mutable reference (because the underlying
|
||||||
string must be cloned to make a private copy).
|
string must be cloned to make a private copy).
|
||||||
|
66
doc/src/language/other-op.md
Normal file
66
doc/src/language/other-op.md
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
Other Operators
|
||||||
|
===============
|
||||||
|
|
||||||
|
{{#include ../links.md}}
|
||||||
|
|
||||||
|
|
||||||
|
Compound Assignment Operators
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let number = 9;
|
||||||
|
|
||||||
|
number += 8; // number = number + 8
|
||||||
|
|
||||||
|
number -= 7; // number = number - 7
|
||||||
|
|
||||||
|
number *= 6; // number = number * 6
|
||||||
|
|
||||||
|
number /= 5; // number = number / 5
|
||||||
|
|
||||||
|
number %= 4; // number = number % 4
|
||||||
|
|
||||||
|
number ~= 3; // number = number ~ 3
|
||||||
|
|
||||||
|
number <<= 2; // number = number << 2
|
||||||
|
|
||||||
|
number >>= 1; // number = number >> 1
|
||||||
|
|
||||||
|
number &= 0x00ff; // number = number & 0x00ff;
|
||||||
|
|
||||||
|
number |= 0x00ff; // number = number | 0x00ff;
|
||||||
|
|
||||||
|
number ^= 0x00ff; // number = number ^ 0x00ff;
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
The Flexible `+=`
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The `+=` operator can also be used to build [strings]:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let my_str = "abc";
|
||||||
|
my_str += "ABC";
|
||||||
|
my_str += 12345;
|
||||||
|
|
||||||
|
my_str == "abcABC12345"
|
||||||
|
```
|
||||||
|
|
||||||
|
It may also be used to concatenate [arrays]:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let my_array = [1, 2, 3];
|
||||||
|
my_array += [4, 5];
|
||||||
|
|
||||||
|
my_array == [1, 2, 3, 4, 5];
|
||||||
|
```
|
||||||
|
|
||||||
|
or mix two [object maps] together:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let my_obj = #{a:1, b:2};
|
||||||
|
my_obj += #{c:3, d:4, e:5};
|
||||||
|
|
||||||
|
my_obj.len() == 5;
|
||||||
|
```
|
@ -66,8 +66,8 @@ let mut engine = Engine::new();
|
|||||||
engine.register_type::<TestStruct>();
|
engine.register_type::<TestStruct>();
|
||||||
```
|
```
|
||||||
|
|
||||||
Methods on Custom Type
|
Methods on The Custom Type
|
||||||
---------------------
|
-------------------------
|
||||||
|
|
||||||
To use native custom types, methods and functions in Rhai scripts, simply register them
|
To use native custom types, methods and functions in Rhai scripts, simply register them
|
||||||
using one of the `Engine::register_XXX` API.
|
using one of the `Engine::register_XXX` API.
|
||||||
|
@ -11,8 +11,8 @@ see [fallible functions]({{rootUrl}}/rust/fallible.md)).
|
|||||||
|
|
||||||
```rust
|
```rust
|
||||||
use rhai::{Dynamic, Engine, EvalAltResult, ImmutableString};
|
use rhai::{Dynamic, Engine, EvalAltResult, ImmutableString};
|
||||||
use rhai::RegisterFn; // use 'RegisterFn' trait for 'register_fn'
|
use rhai::RegisterFn; // use 'RegisterFn' trait for 'register_fn'
|
||||||
use rhai::RegisterResultFn; // use 'RegisterResultFn' trait for 'register_result_fn'
|
use rhai::RegisterResultFn; // use 'RegisterResultFn' trait for 'register_result_fn'
|
||||||
|
|
||||||
// Normal function that returns a standard type
|
// Normal function that returns a standard type
|
||||||
// Remember to use 'ImmutableString' and not 'String'
|
// Remember to use 'ImmutableString' and not 'String'
|
||||||
@ -26,7 +26,7 @@ fn add_len_str(x: i64, s: &str) -> i64 {
|
|||||||
|
|
||||||
// Function that returns a 'Dynamic' value - must return a 'Result'
|
// Function that returns a 'Dynamic' value - must return a 'Result'
|
||||||
fn get_any_value() -> Result<Dynamic, Box<EvalAltResult>> {
|
fn get_any_value() -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
Ok((42_i64).into()) // standard types can use 'into()'
|
Ok((42_i64).into()) // standard types can use 'into()'
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
@ -30,7 +30,7 @@ impl ModuleResolver for MyModuleResolver {
|
|||||||
&self,
|
&self,
|
||||||
engine: &Engine, // reference to the current 'Engine'
|
engine: &Engine, // reference to the current 'Engine'
|
||||||
path: &str, // the module path
|
path: &str, // the module path
|
||||||
pos: Position, // location of the 'import' statement
|
pos: Position, // position of the 'import' statement
|
||||||
) -> Result<Module, Box<EvalAltResult>> {
|
) -> Result<Module, Box<EvalAltResult>> {
|
||||||
// Check module path.
|
// Check module path.
|
||||||
if is_valid_module_path(path) {
|
if is_valid_module_path(path) {
|
||||||
|
@ -12,7 +12,9 @@ fn to_int(num) {
|
|||||||
print("Ha! Gotcha! " + num);
|
print("Ha! Gotcha! " + num);
|
||||||
}
|
}
|
||||||
|
|
||||||
print(to_int(123)); // what happens?
|
let x = (123).to_int();
|
||||||
|
|
||||||
|
print(x); // what happens?
|
||||||
```
|
```
|
||||||
|
|
||||||
A registered native Rust function, in turn, overrides any built-in function of the
|
A registered native Rust function, in turn, overrides any built-in function of the
|
||||||
|
@ -37,8 +37,8 @@ Use `ImmutableString`
|
|||||||
Internally, Rhai uses _immutable_ [strings] instead of the Rust `String` type. This is mainly to avoid excessive
|
Internally, Rhai uses _immutable_ [strings] instead of the Rust `String` type. This is mainly to avoid excessive
|
||||||
cloning when passing function arguments.
|
cloning when passing function arguments.
|
||||||
|
|
||||||
The encapsulated immutable string type is `ImmutableString`. It is cheap to clone (just an `Rc` or `Arc` reference
|
Rhai's internal string type is `ImmutableString` (basically `Rc<String>` or `Arc<String>` depending on the [`sync`] feature).
|
||||||
count increment depending on the [`sync`] feature).
|
It is cheap to clone, but expensive to modify (a new copy of the string must be made in order to change it).
|
||||||
|
|
||||||
Therefore, functions taking `String` parameters should use `ImmutableString` or `&str` (which maps to `ImmutableString`)
|
Therefore, functions taking `String` parameters should use `ImmutableString` or `&str` (which maps to `ImmutableString`)
|
||||||
for the best performance with Rhai.
|
for the best performance with Rhai.
|
||||||
|
@ -5,17 +5,17 @@ Rust Examples
|
|||||||
|
|
||||||
A number of examples can be found in the `examples` directory:
|
A number of examples can be found in the `examples` directory:
|
||||||
|
|
||||||
| Example | Description |
|
| Example | Description |
|
||||||
| ---------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| [`arrays_and_structs`](https://github.com/jonathandturner/rhai/tree/master/examples/arrays_and_structs.rs) | Shows how to register a custom Rust type and using [arrays] on it. |
|
| [`arrays_and_structs`]({{repoTree}}/examples/arrays_and_structs.rs) | Shows how to register a custom Rust type and using [arrays] on it. |
|
||||||
| [`custom_types_and_methods`](https://github.com/jonathandturner/rhai/tree/master/examples/custom_types_and_methods.rs) | Shows how to register a custom Rust type and methods for it. |
|
| [`custom_types_and_methods`]({{repoTree}}/examples/custom_types_and_methods.rs) | Shows how to register a custom Rust type and methods for it. |
|
||||||
| [`hello`](https://github.com/jonathandturner/rhai/tree/master/examples/hello.rs) | Simple example that evaluates an expression and prints the result. |
|
| [`hello`]({{repoTree}}/examples/hello.rs) | Simple example that evaluates an expression and prints the result. |
|
||||||
| [`reuse_scope`](https://github.com/jonathandturner/rhai/tree/master/examples/reuse_scope.rs) | Evaluates two pieces of code in separate runs, but using a common [`Scope`]. |
|
| [`reuse_scope`]({{repoTree}}/examples/reuse_scope.rs) | Evaluates two pieces of code in separate runs, but using a common [`Scope`]. |
|
||||||
| [`rhai_runner`](https://github.com/jonathandturner/rhai/tree/master/examples/rhai_runner.rs) | Runs each filename passed to it as a Rhai script. |
|
| [`rhai_runner`]({{repoTree}}/examples/rhai_runner.rs) | Runs each filename passed to it as a Rhai script. |
|
||||||
| [`serde`](https://github.com/jonathandturner/rhai/tree/master/examples/serde.rs) | Example to serialize and deserialize Rust types with [`serde`](https://crates.io/crates/serde).<br/>The [`serde`] feature is required to run. |
|
| [`serde`]({{repoTree}}/examples/serde.rs) | Example to serialize and deserialize Rust types with [`serde`](https://crates.io/crates/serde).<br/>The [`serde`] feature is required to run. |
|
||||||
| [`simple_fn`](https://github.com/jonathandturner/rhai/tree/master/examples/simple_fn.rs) | Shows how to register a simple function. |
|
| [`simple_fn`]({{repoTree}}/examples/simple_fn.rs) | Shows how to register a simple function. |
|
||||||
| [`strings`](https://github.com/jonathandturner/rhai/tree/master/examples/strings.rs) | Shows different ways to register functions taking string arguments. |
|
| [`strings`]({{repoTree}}/examples/strings.rs) | Shows different ways to register functions taking string arguments. |
|
||||||
| [`repl`](https://github.com/jonathandturner/rhai/tree/master/examples/repl.rs) | A simple REPL, interactively evaluate statements from stdin. |
|
| [`repl`]({{repoTree}}/examples/repl.rs) | A simple REPL, interactively evaluate statements from stdin. |
|
||||||
|
|
||||||
The `repl` example is a particularly good one as it allows one to interactively try out Rhai's
|
The `repl` example is a particularly good one as it allows one to interactively try out Rhai's
|
||||||
language features in a standard REPL (**R**ead-**E**val-**P**rint **L**oop).
|
language features in a standard REPL (**R**ead-**E**val-**P**rint **L**oop).
|
||||||
@ -35,9 +35,9 @@ cargo run --example {example_name}
|
|||||||
|
|
||||||
To illustrate `no-std` builds, a number of sample applications are available under the `no_std` directory:
|
To illustrate `no-std` builds, a number of sample applications are available under the `no_std` directory:
|
||||||
|
|
||||||
| Sample | Description | Optimization | Allocator | Panics |
|
| Sample | Description | Optimization | Allocator | Panics |
|
||||||
| --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | :----------: | :-----------------------------------------------: | :----: |
|
| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | :----------: | :-----------------------------------------------: | :----: |
|
||||||
| [`no_std_test`](https://github.com/jonathandturner/rhai/tree/master/no_std/no_std_test) | Bare-bones test application that evaluates a Rhai expression and sets the result as the return value. | Size | [`wee_alloc`](https://crates.io/crates/wee_alloc) | Abort |
|
| [`no_std_test`]({{repoTree}}/no_std/no_std_test) | Bare-bones test application that evaluates a Rhai expression and sets the result as the return value. | Size | [`wee_alloc`](https://crates.io/crates/wee_alloc) | Abort |
|
||||||
|
|
||||||
`cargo run` cannot be used to run a `no-std` sample. It must first be built:
|
`cargo run` cannot be used to run a `no-std` sample. It must first be built:
|
||||||
|
|
||||||
|
@ -8,25 +8,25 @@ Language Feature Scripts
|
|||||||
|
|
||||||
There are also a number of examples scripts that showcase Rhai's features, all in the `scripts` directory:
|
There are also a number of examples scripts that showcase Rhai's features, all in the `scripts` directory:
|
||||||
|
|
||||||
| Script | Description |
|
| Script | Description |
|
||||||
| -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
| ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
||||||
| [`array.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/array.rhai) | [Arrays] |
|
| [`array.rhai`]({{repoTree}}/scripts/array.rhai) | [Arrays] |
|
||||||
| [`assignment.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/assignment.rhai) | Variable declarations |
|
| [`assignment.rhai`]({{repoTree}}/scripts/assignment.rhai) | Variable declarations |
|
||||||
| [`comments.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/comments.rhai) | Just comments |
|
| [`comments.rhai`]({{repoTree}}/scripts/comments.rhai) | Just comments |
|
||||||
| [`for1.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/for1.rhai) | [`for`]({{rootUrl}}/language/for.md) loops |
|
| [`for1.rhai`]({{repoTree}}/scripts/for1.rhai) | [`for`]({{rootUrl}}/language/for.md) loops |
|
||||||
| [`for2.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/for2.rhai) | [`for`]({{rootUrl}}/language/for.md) loops on [arrays] |
|
| [`for2.rhai`]({{repoTree}}/scripts/for2.rhai) | [`for`]({{rootUrl}}/language/for.md) loops on [arrays] |
|
||||||
| [`function_decl1.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/function_decl1.rhai) | A [function] without parameters |
|
| [`function_decl1.rhai`]({{repoTree}}/scripts/function_decl1.rhai) | A [function] without parameters |
|
||||||
| [`function_decl2.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/function_decl2.rhai) | A [function] with two parameters |
|
| [`function_decl2.rhai`]({{repoTree}}/scripts/function_decl2.rhai) | A [function] with two parameters |
|
||||||
| [`function_decl3.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/function_decl3.rhai) | A [function] with many parameters |
|
| [`function_decl3.rhai`]({{repoTree}}/scripts/function_decl3.rhai) | A [function] with many parameters |
|
||||||
| [`if1.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/if1.rhai) | [`if`]({{rootUrl}}/language/if.md) example |
|
| [`if1.rhai`]({{repoTree}}/scripts/if1.rhai) | [`if`]({{rootUrl}}/language/if.md) example |
|
||||||
| [`loop.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/loop.rhai) | Count-down [`loop`]({{rootUrl}}/language/loop.md) in Rhai, emulating a `do` .. `while` loop |
|
| [`loop.rhai`]({{repoTree}}/scripts/loop.rhai) | Count-down [`loop`]({{rootUrl}}/language/loop.md) in Rhai, emulating a `do` .. `while` loop |
|
||||||
| [`oop.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/oop.rhai) | Simulate [object-oriented programming (OOP)][OOP] |
|
| [`oop.rhai`]({{repoTree}}/scripts/oop.rhai) | Simulate [object-oriented programming (OOP)][OOP] |
|
||||||
| [`op1.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/op1.rhai) | Just simple addition |
|
| [`op1.rhai`]({{repoTree}}/scripts/op1.rhai) | Just simple addition |
|
||||||
| [`op2.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/op2.rhai) | Simple addition and multiplication |
|
| [`op2.rhai`]({{repoTree}}/scripts/op2.rhai) | Simple addition and multiplication |
|
||||||
| [`op3.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/op3.rhai) | Change evaluation order with parenthesis |
|
| [`op3.rhai`]({{repoTree}}/scripts/op3.rhai) | Change evaluation order with parenthesis |
|
||||||
| [`string.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/string.rhai) | [String] operations |
|
| [`string.rhai`]({{repoTree}}/scripts/string.rhai) | [String] operations |
|
||||||
| [`strings_map.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/strings_map.rhai) | [String] and [object map] operations |
|
| [`strings_map.rhai`]({{repoTree}}/scripts/strings_map.rhai) | [String] and [object map] operations |
|
||||||
| [`while.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/while.rhai) | [`while`]({{rootUrl}}/language/while.md) loop |
|
| [`while.rhai`]({{repoTree}}/scripts/while.rhai) | [`while`]({{rootUrl}}/language/while.md) loop |
|
||||||
|
|
||||||
|
|
||||||
Benchmark Scripts
|
Benchmark Scripts
|
||||||
@ -34,12 +34,12 @@ Benchmark Scripts
|
|||||||
|
|
||||||
The following scripts are for benchmarking the speed of Rhai:
|
The following scripts are for benchmarking the speed of Rhai:
|
||||||
|
|
||||||
| Scripts | Description |
|
| Scripts | Description |
|
||||||
| ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------- |
|
| --------------------------------------------------------- | --------------------------------------------------------------------------------------- |
|
||||||
| [`speed_test.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/speed_test.rhai) | A simple application to measure the speed of Rhai's interpreter (1 million iterations). |
|
| [`speed_test.rhai`]({{repoTree}}/scripts/speed_test.rhai) | A simple application to measure the speed of Rhai's interpreter (1 million iterations). |
|
||||||
| [`primes.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/primes.rhai) | Use Sieve of Eratosthenes to find all primes smaller than a limit. |
|
| [`primes.rhai`]({{repoTree}}/scripts/primes.rhai) | Use Sieve of Eratosthenes to find all primes smaller than a limit. |
|
||||||
| [`fibonacci.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/fibonacci.rhai) | Calculate the n-th Fibonacci number using a really dumb algorithm. |
|
| [`fibonacci.rhai`]({{repoTree}}/scripts/fibonacci.rhai) | Calculate the n-th Fibonacci number using a really dumb algorithm. |
|
||||||
| [`mat_mul.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/mat_mul.rhai) | Matrix multiplication test to measure the speed of multi-dimensional array access. |
|
| [`mat_mul.rhai`]({{repoTree}}/scripts/mat_mul.rhai) | Matrix multiplication test to measure the speed of multi-dimensional array access. |
|
||||||
|
|
||||||
|
|
||||||
Running Example Scripts
|
Running Example Scripts
|
||||||
|
@ -25,7 +25,7 @@ more control over what a script can (or cannot) do.
|
|||||||
| `no_module` | Disable loading external [modules]. |
|
| `no_module` | Disable loading external [modules]. |
|
||||||
| `no_std` | Build for `no-std`. Notice that additional dependencies will be pulled in to replace `std` features. |
|
| `no_std` | Build for `no-std`. Notice that additional dependencies will be pulled in to replace `std` features. |
|
||||||
| `serde` | Enable serialization/deserialization via [`serde`]. Notice that the [`serde`](https://crates.io/crates/serde) crate will be pulled in together with its dependencies. |
|
| `serde` | Enable serialization/deserialization via [`serde`]. Notice that the [`serde`](https://crates.io/crates/serde) crate will be pulled in together with its dependencies. |
|
||||||
| `internals` | Expose internal data structures (e.g. [`AST`] nodes) and enable defining [custom syntax]. Beware that Rhai internals are volatile and may change from version to version. |
|
| `internals` | Expose internal data structures (e.g. [`AST`] nodes). Beware that Rhai internals are volatile and may change from version to version. |
|
||||||
|
|
||||||
|
|
||||||
Example
|
Example
|
||||||
@ -46,7 +46,7 @@ rhai = { version = "{{version}}", features = [ "sync", "unchecked", "only_i32",
|
|||||||
```
|
```
|
||||||
|
|
||||||
The resulting scripting engine supports only the `i32` integer numeral type (and no others like `u32`, `i16` or `i64`),
|
The resulting scripting engine supports only the `i32` integer numeral type (and no others like `u32`, `i16` or `i64`),
|
||||||
no floating-point, is `Send + Sync` (so it can be safely used across threads), does not support defining [functions]
|
no floating-point, is `Send + Sync` (so it can be safely used across threads), and does not support defining [functions]
|
||||||
nor loading external [modules].
|
nor loading external [modules].
|
||||||
|
|
||||||
This configuration is perfect for an expression parser in a 32-bit embedded system without floating-point hardware.
|
This configuration is perfect for an expression parser in a 32-bit embedded system without floating-point hardware.
|
||||||
|
@ -6,7 +6,7 @@ version = "0.1.0"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
authors = ["Stephen Chung"]
|
authors = ["Stephen Chung"]
|
||||||
description = "no-std test application"
|
description = "no-std test application"
|
||||||
homepage = "https://github.com/jonathandturner/rhai/tree/master/no_std/no_std_test"
|
homepage = "https://github.com/jonathandturner/rhai/tree/no_std/no_std_test"
|
||||||
repository = "https://github.com/jonathandturner/rhai"
|
repository = "https://github.com/jonathandturner/rhai"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -16,12 +16,16 @@ use crate::engine::Map;
|
|||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::{type_name, Any, TypeId},
|
any::{type_name, Any, TypeId},
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
collections::HashMap,
|
|
||||||
fmt,
|
fmt,
|
||||||
string::String,
|
string::String,
|
||||||
vec::Vec,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
use crate::stdlib::collections::HashMap;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
use crate::stdlib::vec::Vec;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use crate::stdlib::time::Instant;
|
use crate::stdlib::time::Instant;
|
||||||
|
19
src/api.rs
19
src/api.rs
@ -1,30 +1,33 @@
|
|||||||
//! Module that defines the extern API of `Engine`.
|
//! Module that defines the extern API of `Engine`.
|
||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::engine::{make_getter, make_setter, Engine, Imports, State, FN_IDX_GET, FN_IDX_SET};
|
use crate::engine::{Engine, Imports, State};
|
||||||
use crate::error::ParseError;
|
use crate::error::ParseError;
|
||||||
use crate::fn_args::FuncArgs;
|
|
||||||
use crate::fn_native::{IteratorFn, SendSync};
|
use crate::fn_native::{IteratorFn, SendSync};
|
||||||
use crate::fn_register::RegisterFn;
|
|
||||||
use crate::module::{FuncReturn, Module};
|
use crate::module::{FuncReturn, Module};
|
||||||
use crate::optimize::{optimize_into_ast, OptimizationLevel};
|
use crate::optimize::{optimize_into_ast, OptimizationLevel};
|
||||||
use crate::parser::AST;
|
use crate::parser::AST;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use crate::token::{lex, Position};
|
use crate::token::{lex, Position};
|
||||||
use crate::utils::StaticVec;
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
use crate::engine::{FN_IDX_GET, FN_IDX_SET};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
use crate::engine::Map;
|
use crate::{
|
||||||
|
engine::{make_getter, make_setter, Map},
|
||||||
|
fn_register::RegisterFn,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::engine::get_script_function_by_signature;
|
use crate::{engine::get_script_function_by_signature, fn_args::FuncArgs, utils::StaticVec};
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::{type_name, TypeId},
|
any::{type_name, TypeId},
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
mem,
|
mem,
|
||||||
string::{String, ToString},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
@ -293,7 +296,7 @@ impl Engine {
|
|||||||
self.type_names
|
self.type_names
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.insert(type_name::<T>().to_string(), name.to_string());
|
.insert(type_name::<T>().into(), name.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
274
src/engine.rs
274
src/engine.rs
@ -1,13 +1,13 @@
|
|||||||
//! Main module defining the script evaluation `Engine`.
|
//! Main module defining the script evaluation `Engine`.
|
||||||
|
|
||||||
use crate::any::{map_std_type_name, Dynamic, Union, Variant};
|
use crate::any::{map_std_type_name, Dynamic, Union};
|
||||||
use crate::calc_fn_hash;
|
use crate::calc_fn_hash;
|
||||||
use crate::fn_call::run_builtin_op_assignment;
|
use crate::fn_call::run_builtin_op_assignment;
|
||||||
use crate::fn_native::{CallableFunction, Callback, FnPtr};
|
use crate::fn_native::{CallableFunction, Callback, FnPtr};
|
||||||
use crate::module::{resolvers, Module, ModuleRef, ModuleResolver};
|
use crate::module::{Module, ModuleRef};
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::packages::{Package, PackagesCollection, StandardPackage};
|
use crate::packages::{Package, PackagesCollection, StandardPackage};
|
||||||
use crate::parser::{Expr, FnAccess, ImmutableString, ReturnType, ScriptFnDef, Stmt};
|
use crate::parser::{Expr, ReturnType, Stmt};
|
||||||
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||||
@ -15,8 +15,23 @@ use crate::syntax::{CustomSyntax, EvalContext};
|
|||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
use crate::utils::StaticVec;
|
use crate::utils::StaticVec;
|
||||||
|
|
||||||
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
|
use crate::any::Variant;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
use crate::parser::{FnAccess, ScriptFnDef};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
use crate::module::ModuleResolver;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_std"))]
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
use crate::module::resolvers;
|
||||||
|
|
||||||
|
#[cfg(any(not(feature = "no_object"), not(feature = "no_module")))]
|
||||||
|
use crate::utils::ImmutableString;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::TypeId,
|
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
@ -26,6 +41,9 @@ use crate::stdlib::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
use crate::stdlib::any::TypeId;
|
||||||
|
|
||||||
/// Variable-sized array of `Dynamic` values.
|
/// Variable-sized array of `Dynamic` values.
|
||||||
///
|
///
|
||||||
/// Not available under the `no_index` feature.
|
/// Not available under the `no_index` feature.
|
||||||
@ -66,13 +84,6 @@ pub const MAX_EXPR_DEPTH: usize = 128;
|
|||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 32;
|
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 32;
|
||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
|
||||||
pub const MAX_CALL_STACK_DEPTH: usize = usize::MAX;
|
|
||||||
#[cfg(feature = "unchecked")]
|
|
||||||
pub const MAX_EXPR_DEPTH: usize = 0;
|
|
||||||
#[cfg(feature = "unchecked")]
|
|
||||||
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 0;
|
|
||||||
|
|
||||||
pub const KEYWORD_PRINT: &str = "print";
|
pub const KEYWORD_PRINT: &str = "print";
|
||||||
pub const KEYWORD_DEBUG: &str = "debug";
|
pub const KEYWORD_DEBUG: &str = "debug";
|
||||||
pub const KEYWORD_TYPE_OF: &str = "type_of";
|
pub const KEYWORD_TYPE_OF: &str = "type_of";
|
||||||
@ -82,16 +93,22 @@ pub const KEYWORD_FN_PTR_CALL: &str = "call";
|
|||||||
pub const KEYWORD_FN_PTR_CURRY: &str = "curry";
|
pub const KEYWORD_FN_PTR_CURRY: &str = "curry";
|
||||||
pub const KEYWORD_THIS: &str = "this";
|
pub const KEYWORD_THIS: &str = "this";
|
||||||
pub const FN_TO_STRING: &str = "to_string";
|
pub const FN_TO_STRING: &str = "to_string";
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub const FN_GET: &str = "get$";
|
pub const FN_GET: &str = "get$";
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub const FN_SET: &str = "set$";
|
pub const FN_SET: &str = "set$";
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub const FN_IDX_GET: &str = "index$get$";
|
pub const FN_IDX_GET: &str = "index$get$";
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub const FN_IDX_SET: &str = "index$set$";
|
pub const FN_IDX_SET: &str = "index$set$";
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub const FN_ANONYMOUS: &str = "anon$";
|
pub const FN_ANONYMOUS: &str = "anon$";
|
||||||
pub const MARKER_EXPR: &str = "$expr$";
|
pub const MARKER_EXPR: &str = "$expr$";
|
||||||
pub const MARKER_BLOCK: &str = "$block$";
|
pub const MARKER_BLOCK: &str = "$block$";
|
||||||
pub const MARKER_IDENT: &str = "$ident$";
|
pub const MARKER_IDENT: &str = "$ident$";
|
||||||
|
|
||||||
/// A type specifying the method of chaining.
|
/// A type specifying the method of chaining.
|
||||||
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||||
pub enum ChainType {
|
pub enum ChainType {
|
||||||
None,
|
None,
|
||||||
@ -100,6 +117,7 @@ pub enum ChainType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A type that encapsulates a mutation target for an expression with side effects.
|
/// A type that encapsulates a mutation target for an expression with side effects.
|
||||||
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Target<'a> {
|
pub enum Target<'a> {
|
||||||
/// The target is a mutable reference to a `Dynamic` value somewhere.
|
/// The target is a mutable reference to a `Dynamic` value somewhere.
|
||||||
@ -108,15 +126,19 @@ pub enum Target<'a> {
|
|||||||
Value(Dynamic),
|
Value(Dynamic),
|
||||||
/// The target is a character inside a String.
|
/// The target is a character inside a String.
|
||||||
/// This is necessary because directly pointing to a char inside a String is impossible.
|
/// This is necessary because directly pointing to a char inside a String is impossible.
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
StringChar(&'a mut Dynamic, usize, Dynamic),
|
StringChar(&'a mut Dynamic, usize, Dynamic),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
impl Target<'_> {
|
impl Target<'_> {
|
||||||
/// Is the `Target` a reference pointing to other data?
|
/// Is the `Target` a reference pointing to other data?
|
||||||
pub fn is_ref(&self) -> bool {
|
pub fn is_ref(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Ref(_) => true,
|
Self::Ref(_) => true,
|
||||||
Self::Value(_) | Self::StringChar(_, _, _) => false,
|
Self::Value(_) => false,
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
Self::StringChar(_, _, _) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is the `Target` an owned value?
|
/// Is the `Target` an owned value?
|
||||||
@ -124,22 +146,26 @@ impl Target<'_> {
|
|||||||
match self {
|
match self {
|
||||||
Self::Ref(_) => false,
|
Self::Ref(_) => false,
|
||||||
Self::Value(_) => true,
|
Self::Value(_) => true,
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
Self::StringChar(_, _, _) => false,
|
Self::StringChar(_, _, _) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is the `Target` a specific type?
|
/// Is the `Target` a specific type?
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn is<T: Variant + Clone>(&self) -> bool {
|
pub fn is<T: Variant + Clone>(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Target::Ref(r) => r.is::<T>(),
|
Target::Ref(r) => r.is::<T>(),
|
||||||
Target::Value(r) => r.is::<T>(),
|
Target::Value(r) => r.is::<T>(),
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
Target::StringChar(_, _, _) => TypeId::of::<T>() == TypeId::of::<char>(),
|
Target::StringChar(_, _, _) => TypeId::of::<T>() == TypeId::of::<char>(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Get the value of the `Target` as a `Dynamic`, cloning a referenced value if necessary.
|
/// Get the value of the `Target` as a `Dynamic`, cloning a referenced value if necessary.
|
||||||
pub fn clone_into_dynamic(self) -> Dynamic {
|
pub fn clone_into_dynamic(self) -> Dynamic {
|
||||||
match self {
|
match self {
|
||||||
Self::Ref(r) => r.clone(), // Referenced value is cloned
|
Self::Ref(r) => r.clone(), // Referenced value is cloned
|
||||||
Self::Value(v) => v, // Owned value is simply taken
|
Self::Value(v) => v, // Owned value is simply taken
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
Self::StringChar(_, _, ch) => ch, // Character is taken
|
Self::StringChar(_, _, ch) => ch, // Character is taken
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,6 +174,7 @@ impl Target<'_> {
|
|||||||
match self {
|
match self {
|
||||||
Self::Ref(r) => *r,
|
Self::Ref(r) => *r,
|
||||||
Self::Value(ref mut r) => r,
|
Self::Value(ref mut r) => r,
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
Self::StringChar(_, _, ref mut r) => r,
|
Self::StringChar(_, _, ref mut r) => r,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -161,6 +188,7 @@ impl Target<'_> {
|
|||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
Self::StringChar(Dynamic(Union::Str(ref mut s)), index, _) => {
|
Self::StringChar(Dynamic(Union::Str(ref mut s)), index, _) => {
|
||||||
// Replace the character at the specified index position
|
// Replace the character at the specified index position
|
||||||
let new_ch = new_val
|
let new_ch = new_val
|
||||||
@ -176,18 +204,21 @@ impl Target<'_> {
|
|||||||
*s = chars.iter().collect::<String>().into();
|
*s = chars.iter().collect::<String>().into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
Self::StringChar(_, _, _) => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
impl<'a> From<&'a mut Dynamic> for Target<'a> {
|
impl<'a> From<&'a mut Dynamic> for Target<'a> {
|
||||||
fn from(value: &'a mut Dynamic) -> Self {
|
fn from(value: &'a mut Dynamic) -> Self {
|
||||||
Self::Ref(value)
|
Self::Ref(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
impl<T: Into<Dynamic>> From<T> for Target<'_> {
|
impl<T: Into<Dynamic>> From<T> for Target<'_> {
|
||||||
fn from(value: T) -> Self {
|
fn from(value: T) -> Self {
|
||||||
Self::Value(value.into())
|
Self::Value(value.into())
|
||||||
@ -249,6 +280,34 @@ pub fn get_script_function_by_signature<'a>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// [INTERNALS] A type containing all the limits imposed by the `Engine`.
|
||||||
|
/// Exported under the `internals` feature only.
|
||||||
|
///
|
||||||
|
/// ## WARNING
|
||||||
|
///
|
||||||
|
/// This type is volatile and may change.
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
pub struct Limits {
|
||||||
|
/// Maximum levels of call-stack to prevent infinite recursion.
|
||||||
|
///
|
||||||
|
/// Defaults to 16 for debug builds and 128 for non-debug builds.
|
||||||
|
pub max_call_stack_depth: usize,
|
||||||
|
/// Maximum depth of statements/expressions at global level.
|
||||||
|
pub max_expr_depth: usize,
|
||||||
|
/// Maximum depth of statements/expressions in functions.
|
||||||
|
pub max_function_expr_depth: usize,
|
||||||
|
/// Maximum number of operations allowed to run.
|
||||||
|
pub max_operations: u64,
|
||||||
|
/// Maximum number of modules allowed to load.
|
||||||
|
pub max_modules: usize,
|
||||||
|
/// Maximum length of a string.
|
||||||
|
pub max_string_size: usize,
|
||||||
|
/// Maximum length of an array.
|
||||||
|
pub max_array_size: usize,
|
||||||
|
/// Maximum number of properties in a map.
|
||||||
|
pub max_map_size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
/// Rhai main scripting engine.
|
/// Rhai main scripting engine.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@ -275,6 +334,7 @@ pub struct Engine {
|
|||||||
pub(crate) packages: PackagesCollection,
|
pub(crate) packages: PackagesCollection,
|
||||||
|
|
||||||
/// A module resolution service.
|
/// A module resolution service.
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub(crate) module_resolver: Option<Box<dyn ModuleResolver>>,
|
pub(crate) module_resolver: Option<Box<dyn ModuleResolver>>,
|
||||||
|
|
||||||
/// A hashmap mapping type names to pretty-print names.
|
/// A hashmap mapping type names to pretty-print names.
|
||||||
@ -296,24 +356,10 @@ pub struct Engine {
|
|||||||
|
|
||||||
/// Optimize the AST after compilation.
|
/// Optimize the AST after compilation.
|
||||||
pub(crate) optimization_level: OptimizationLevel,
|
pub(crate) optimization_level: OptimizationLevel,
|
||||||
/// Maximum levels of call-stack to prevent infinite recursion.
|
|
||||||
///
|
/// Max limits.
|
||||||
/// Defaults to 16 for debug builds and 128 for non-debug builds.
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub(crate) max_call_stack_depth: usize,
|
pub(crate) limits: Limits,
|
||||||
/// Maximum depth of statements/expressions at global level.
|
|
||||||
pub(crate) max_expr_depth: usize,
|
|
||||||
/// Maximum depth of statements/expressions in functions.
|
|
||||||
pub(crate) max_function_expr_depth: usize,
|
|
||||||
/// Maximum number of operations allowed to run.
|
|
||||||
pub(crate) max_operations: u64,
|
|
||||||
/// Maximum number of modules allowed to load.
|
|
||||||
pub(crate) max_modules: usize,
|
|
||||||
/// Maximum length of a string.
|
|
||||||
pub(crate) max_string_size: usize,
|
|
||||||
/// Maximum length of an array.
|
|
||||||
pub(crate) max_array_size: usize,
|
|
||||||
/// Maximum number of properties in a map.
|
|
||||||
pub(crate) max_map_size: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Engine {
|
impl fmt::Debug for Engine {
|
||||||
@ -338,7 +384,8 @@ impl Default for Engine {
|
|||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
module_resolver: Some(Box::new(resolvers::FileModuleResolver::new())),
|
module_resolver: Some(Box::new(resolvers::FileModuleResolver::new())),
|
||||||
#[cfg(any(feature = "no_module", feature = "no_std", target_arch = "wasm32",))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
#[cfg(any(feature = "no_std", target_arch = "wasm32",))]
|
||||||
module_resolver: None,
|
module_resolver: None,
|
||||||
|
|
||||||
type_names: None,
|
type_names: None,
|
||||||
@ -360,14 +407,17 @@ impl Default for Engine {
|
|||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
optimization_level: OptimizationLevel::Simple,
|
optimization_level: OptimizationLevel::Simple,
|
||||||
|
|
||||||
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
#[cfg(not(feature = "unchecked"))]
|
||||||
max_expr_depth: MAX_EXPR_DEPTH,
|
limits: Limits {
|
||||||
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
||||||
max_operations: 0,
|
max_expr_depth: MAX_EXPR_DEPTH,
|
||||||
max_modules: usize::MAX,
|
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
||||||
max_string_size: 0,
|
max_operations: 0,
|
||||||
max_array_size: 0,
|
max_modules: usize::MAX,
|
||||||
max_map_size: 0,
|
max_string_size: 0,
|
||||||
|
max_array_size: 0,
|
||||||
|
max_map_size: 0,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
engine.load_package(StandardPackage::new().get());
|
engine.load_package(StandardPackage::new().get());
|
||||||
@ -377,20 +427,24 @@ impl Default for Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Make getter function
|
/// Make getter function
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
#[inline(always)]
|
||||||
pub fn make_getter(id: &str) -> String {
|
pub fn make_getter(id: &str) -> String {
|
||||||
format!("{}{}", FN_GET, id)
|
format!("{}{}", FN_GET, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make setter function
|
/// Make setter function
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
#[inline(always)]
|
||||||
pub fn make_setter(id: &str) -> String {
|
pub fn make_setter(id: &str) -> String {
|
||||||
format!("{}{}", FN_SET, id)
|
format!("{}{}", FN_SET, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print/debug to stdout
|
/// Print/debug to stdout
|
||||||
fn default_print(s: &str) {
|
fn default_print(_s: &str) {
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
println!("{}", s);
|
println!("{}", _s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Search for a module within an imports stack.
|
/// Search for a module within an imports stack.
|
||||||
@ -546,6 +600,8 @@ impl Engine {
|
|||||||
|
|
||||||
packages: Default::default(),
|
packages: Default::default(),
|
||||||
global_module: Default::default(),
|
global_module: Default::default(),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
module_resolver: None,
|
module_resolver: None,
|
||||||
|
|
||||||
type_names: None,
|
type_names: None,
|
||||||
@ -563,19 +619,23 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
optimization_level: OptimizationLevel::Simple,
|
optimization_level: OptimizationLevel::Simple,
|
||||||
|
|
||||||
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
#[cfg(not(feature = "unchecked"))]
|
||||||
max_expr_depth: MAX_EXPR_DEPTH,
|
limits: Limits {
|
||||||
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
||||||
max_operations: 0,
|
max_expr_depth: MAX_EXPR_DEPTH,
|
||||||
max_modules: usize::MAX,
|
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
||||||
max_string_size: 0,
|
max_operations: 0,
|
||||||
max_array_size: 0,
|
max_modules: usize::MAX,
|
||||||
max_map_size: 0,
|
max_string_size: 0,
|
||||||
|
max_array_size: 0,
|
||||||
|
max_map_size: 0,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Chain-evaluate a dot/index chain.
|
/// Chain-evaluate a dot/index chain.
|
||||||
/// Position in `EvalAltResult` is `None` and must be set afterwards.
|
/// Position in `EvalAltResult` is `None` and must be set afterwards.
|
||||||
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
fn eval_dot_index_chain_helper(
|
fn eval_dot_index_chain_helper(
|
||||||
&self,
|
&self,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
@ -586,7 +646,7 @@ impl Engine {
|
|||||||
idx_values: &mut StaticVec<Dynamic>,
|
idx_values: &mut StaticVec<Dynamic>,
|
||||||
chain_type: ChainType,
|
chain_type: ChainType,
|
||||||
level: usize,
|
level: usize,
|
||||||
mut new_val: Option<Dynamic>,
|
mut _new_val: Option<Dynamic>,
|
||||||
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||||
if chain_type == ChainType::None {
|
if chain_type == ChainType::None {
|
||||||
panic!();
|
panic!();
|
||||||
@ -618,18 +678,19 @@ impl Engine {
|
|||||||
|
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state, lib, this_ptr, obj_ptr, expr, idx_values, next_chain, level,
|
state, lib, this_ptr, obj_ptr, expr, idx_values, next_chain, level,
|
||||||
new_val,
|
_new_val,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.new_position(*pos))
|
.map_err(|err| err.new_position(*pos))
|
||||||
}
|
}
|
||||||
// xxx[rhs] = new_val
|
// xxx[rhs] = new_val
|
||||||
_ if new_val.is_some() => {
|
_ if _new_val.is_some() => {
|
||||||
let mut new_val = new_val.unwrap();
|
let mut new_val = _new_val.unwrap();
|
||||||
let mut idx_val2 = idx_val.clone();
|
let mut idx_val2 = idx_val.clone();
|
||||||
|
|
||||||
match self.get_indexed_mut(state, lib, target, idx_val, pos, true, level) {
|
match self.get_indexed_mut(state, lib, target, idx_val, pos, true, level) {
|
||||||
// Indexed value is an owned value - the only possibility is an indexer
|
// Indexed value is an owned value - the only possibility is an indexer
|
||||||
// Try to call an index setter
|
// Try to call an index setter
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
Ok(obj_ptr) if obj_ptr.is_value() => {
|
Ok(obj_ptr) if obj_ptr.is_value() => {
|
||||||
let args = &mut [target.as_mut(), &mut idx_val2, &mut new_val];
|
let args = &mut [target.as_mut(), &mut idx_val2, &mut new_val];
|
||||||
|
|
||||||
@ -639,9 +700,7 @@ impl Engine {
|
|||||||
)
|
)
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
// If there is no index setter, no need to set it back because the indexer is read-only
|
// If there is no index setter, no need to set it back because the indexer is read-only
|
||||||
EvalAltResult::ErrorFunctionNotFound(s, _)
|
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||||
if s == FN_IDX_SET =>
|
|
||||||
{
|
|
||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
}
|
}
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
@ -655,6 +714,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
Err(err) => match *err {
|
Err(err) => match *err {
|
||||||
// No index getter - try to call an index setter
|
// No index getter - try to call an index setter
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
EvalAltResult::ErrorIndexingType(_, _) => {
|
EvalAltResult::ErrorIndexingType(_, _) => {
|
||||||
let args = &mut [target.as_mut(), &mut idx_val2, &mut new_val];
|
let args = &mut [target.as_mut(), &mut idx_val2, &mut new_val];
|
||||||
|
|
||||||
@ -686,13 +746,13 @@ impl Engine {
|
|||||||
// xxx.module::fn_name(...) - syntax error
|
// xxx.module::fn_name(...) - syntax error
|
||||||
Expr::FnCall(_) => unreachable!(),
|
Expr::FnCall(_) => unreachable!(),
|
||||||
// {xxx:map}.id = ???
|
// {xxx:map}.id = ???
|
||||||
Expr::Property(x) if target.is::<Map>() && new_val.is_some() => {
|
Expr::Property(x) if target.is::<Map>() && _new_val.is_some() => {
|
||||||
let ((prop, _, _), pos) = x.as_ref();
|
let ((prop, _, _), pos) = x.as_ref();
|
||||||
let index = prop.clone().into();
|
let index = prop.clone().into();
|
||||||
let mut val =
|
let mut val =
|
||||||
self.get_indexed_mut(state, lib, target, index, *pos, true, level)?;
|
self.get_indexed_mut(state, lib, target, index, *pos, true, level)?;
|
||||||
|
|
||||||
val.set_value(new_val.unwrap())
|
val.set_value(_new_val.unwrap())
|
||||||
.map_err(|err| err.new_position(rhs.position()))?;
|
.map_err(|err| err.new_position(rhs.position()))?;
|
||||||
Ok((Default::default(), true))
|
Ok((Default::default(), true))
|
||||||
}
|
}
|
||||||
@ -706,9 +766,9 @@ impl Engine {
|
|||||||
Ok((val.clone_into_dynamic(), false))
|
Ok((val.clone_into_dynamic(), false))
|
||||||
}
|
}
|
||||||
// xxx.id = ???
|
// xxx.id = ???
|
||||||
Expr::Property(x) if new_val.is_some() => {
|
Expr::Property(x) if _new_val.is_some() => {
|
||||||
let ((_, _, setter), pos) = x.as_ref();
|
let ((_, _, setter), pos) = x.as_ref();
|
||||||
let mut args = [target.as_mut(), new_val.as_mut().unwrap()];
|
let mut args = [target.as_mut(), _new_val.as_mut().unwrap()];
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
state, lib, setter, true, 0, &mut args, is_ref, true, None, level,
|
state, lib, setter, true, 0, &mut args, is_ref, true, None, level,
|
||||||
)
|
)
|
||||||
@ -750,7 +810,7 @@ impl Engine {
|
|||||||
|
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state, lib, this_ptr, &mut val, expr, idx_values, next_chain, level,
|
state, lib, this_ptr, &mut val, expr, idx_values, next_chain, level,
|
||||||
new_val,
|
_new_val,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.new_position(*pos))
|
.map_err(|err| err.new_position(*pos))
|
||||||
}
|
}
|
||||||
@ -777,7 +837,7 @@ impl Engine {
|
|||||||
let (result, may_be_changed) = self
|
let (result, may_be_changed) = self
|
||||||
.eval_dot_index_chain_helper(
|
.eval_dot_index_chain_helper(
|
||||||
state, lib, this_ptr, target, expr, idx_values, next_chain,
|
state, lib, this_ptr, target, expr, idx_values, next_chain,
|
||||||
level, new_val,
|
level, _new_val,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.new_position(*pos))?;
|
.map_err(|err| err.new_position(*pos))?;
|
||||||
|
|
||||||
@ -812,7 +872,7 @@ impl Engine {
|
|||||||
|
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state, lib, this_ptr, target, expr, idx_values, next_chain,
|
state, lib, this_ptr, target, expr, idx_values, next_chain,
|
||||||
level, new_val,
|
level, _new_val,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.new_position(*pos))
|
.map_err(|err| err.new_position(*pos))
|
||||||
}
|
}
|
||||||
@ -835,6 +895,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a dot/index chain.
|
/// Evaluate a dot/index chain.
|
||||||
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
fn eval_dot_index_chain(
|
fn eval_dot_index_chain(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
@ -911,6 +972,7 @@ impl Engine {
|
|||||||
/// Any spill-overs are stored in `more`, which is dynamic.
|
/// Any spill-overs are stored in `more`, which is dynamic.
|
||||||
/// The fixed length array is used to avoid an allocation in the overwhelming cases of just a few levels of indexing.
|
/// The fixed length array is used to avoid an allocation in the overwhelming cases of just a few levels of indexing.
|
||||||
/// The total number of values is returned.
|
/// The total number of values is returned.
|
||||||
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
fn eval_indexed_chain(
|
fn eval_indexed_chain(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
@ -981,26 +1043,30 @@ impl Engine {
|
|||||||
|
|
||||||
/// Get the value at the indexed position of a base type
|
/// Get the value at the indexed position of a base type
|
||||||
/// Position in `EvalAltResult` may be None and should be set afterwards.
|
/// Position in `EvalAltResult` may be None and should be set afterwards.
|
||||||
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
fn get_indexed_mut<'a>(
|
fn get_indexed_mut<'a>(
|
||||||
&self,
|
&self,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
_lib: &Module,
|
||||||
target: &'a mut Target,
|
target: &'a mut Target,
|
||||||
mut idx: Dynamic,
|
mut _idx: Dynamic,
|
||||||
idx_pos: Position,
|
idx_pos: Position,
|
||||||
create: bool,
|
_create: bool,
|
||||||
level: usize,
|
_level: usize,
|
||||||
) -> Result<Target<'a>, Box<EvalAltResult>> {
|
) -> Result<Target<'a>, Box<EvalAltResult>> {
|
||||||
self.inc_operations(state)?;
|
self.inc_operations(state)?;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
let is_ref = target.is_ref();
|
let is_ref = target.is_ref();
|
||||||
|
|
||||||
let val = target.as_mut();
|
let val = target.as_mut();
|
||||||
|
|
||||||
match val {
|
match val {
|
||||||
#[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()
|
||||||
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_pos))?;
|
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_pos))?;
|
||||||
|
|
||||||
@ -1022,14 +1088,14 @@ 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]
|
||||||
Ok(if create {
|
Ok(if _create {
|
||||||
let index = idx
|
let index = _idx
|
||||||
.take_immutable_string()
|
.take_immutable_string()
|
||||||
.map_err(|_| EvalAltResult::ErrorStringIndexExpr(idx_pos))?;
|
.map_err(|_| EvalAltResult::ErrorStringIndexExpr(idx_pos))?;
|
||||||
|
|
||||||
map.entry(index).or_insert(Default::default()).into()
|
map.entry(index).or_insert(Default::default()).into()
|
||||||
} else {
|
} else {
|
||||||
let index = idx
|
let index = _idx
|
||||||
.downcast_ref::<ImmutableString>()
|
.downcast_ref::<ImmutableString>()
|
||||||
.ok_or_else(|| EvalAltResult::ErrorStringIndexExpr(idx_pos))?;
|
.ok_or_else(|| EvalAltResult::ErrorStringIndexExpr(idx_pos))?;
|
||||||
|
|
||||||
@ -1043,7 +1109,7 @@ impl Engine {
|
|||||||
Dynamic(Union::Str(s)) => {
|
Dynamic(Union::Str(s)) => {
|
||||||
// val_string[idx]
|
// val_string[idx]
|
||||||
let chars_len = s.chars().count();
|
let chars_len = s.chars().count();
|
||||||
let index = idx
|
let index = _idx
|
||||||
.as_int()
|
.as_int()
|
||||||
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_pos))?;
|
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_pos))?;
|
||||||
|
|
||||||
@ -1064,9 +1130,9 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
_ => {
|
_ => {
|
||||||
let type_name = val.type_name();
|
let type_name = val.type_name();
|
||||||
let args = &mut [val, &mut idx];
|
let args = &mut [val, &mut _idx];
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
state, lib, FN_IDX_GET, true, 0, args, is_ref, true, None, level,
|
state, _lib, FN_IDX_GET, true, 0, args, is_ref, true, None, _level,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| v.into())
|
.map(|(v, _)| v.into())
|
||||||
.map_err(|err| match *err {
|
.map_err(|err| match *err {
|
||||||
@ -1077,7 +1143,7 @@ impl Engine {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(any(feature = "no_index", feature = "no_object"))]
|
||||||
_ => Err(Box::new(EvalAltResult::ErrorIndexingType(
|
_ => Err(Box::new(EvalAltResult::ErrorIndexingType(
|
||||||
self.map_type_name(val.type_name()).into(),
|
self.map_type_name(val.type_name()).into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
@ -1254,7 +1320,7 @@ impl Engine {
|
|||||||
let mut rhs_val =
|
let mut rhs_val =
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)?;
|
self.eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)?;
|
||||||
|
|
||||||
let new_val = Some(if op.is_empty() {
|
let _new_val = Some(if op.is_empty() {
|
||||||
// Normal assignment
|
// Normal assignment
|
||||||
rhs_val
|
rhs_val
|
||||||
} else {
|
} else {
|
||||||
@ -1277,7 +1343,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(_) => {
|
Expr::Index(_) => {
|
||||||
self.eval_dot_index_chain(
|
self.eval_dot_index_chain(
|
||||||
scope, mods, state, lib, this_ptr, lhs_expr, level, new_val,
|
scope, mods, state, lib, this_ptr, lhs_expr, level, _new_val,
|
||||||
)?;
|
)?;
|
||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
}
|
}
|
||||||
@ -1285,7 +1351,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Dot(_) => {
|
Expr::Dot(_) => {
|
||||||
self.eval_dot_index_chain(
|
self.eval_dot_index_chain(
|
||||||
scope, mods, state, lib, this_ptr, lhs_expr, level, new_val,
|
scope, mods, state, lib, this_ptr, lhs_expr, level, _new_val,
|
||||||
)?;
|
)?;
|
||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
}
|
}
|
||||||
@ -1641,19 +1707,20 @@ impl Engine {
|
|||||||
Stmt::Const(_) => unreachable!(),
|
Stmt::Const(_) => unreachable!(),
|
||||||
|
|
||||||
// Import statement
|
// Import statement
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Stmt::Import(x) => {
|
Stmt::Import(x) => {
|
||||||
let (expr, (name, pos)) = x.as_ref();
|
let (expr, (name, _pos)) = x.as_ref();
|
||||||
|
|
||||||
// Guard against too many modules
|
// Guard against too many modules
|
||||||
if state.modules >= self.max_modules {
|
#[cfg(not(feature = "unchecked"))]
|
||||||
return Err(Box::new(EvalAltResult::ErrorTooManyModules(*pos)));
|
if state.modules >= self.limits.max_modules {
|
||||||
|
return Err(Box::new(EvalAltResult::ErrorTooManyModules(*_pos)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(path) = self
|
if let Some(path) = self
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, &expr, level)?
|
.eval_expr(scope, mods, state, lib, this_ptr, &expr, level)?
|
||||||
.try_cast::<ImmutableString>()
|
.try_cast::<ImmutableString>()
|
||||||
{
|
{
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
if let Some(resolver) = &self.module_resolver {
|
if let Some(resolver) = &self.module_resolver {
|
||||||
let mut module = resolver.resolve(self, &path, expr.position())?;
|
let mut module = resolver.resolve(self, &path, expr.position())?;
|
||||||
module.index_all_sub_modules();
|
module.index_all_sub_modules();
|
||||||
@ -1668,15 +1735,13 @@ impl Engine {
|
|||||||
expr.position(),
|
expr.position(),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "no_module")]
|
|
||||||
Ok(Default::default())
|
|
||||||
} else {
|
} else {
|
||||||
Err(Box::new(EvalAltResult::ErrorImportExpr(expr.position())))
|
Err(Box::new(EvalAltResult::ErrorImportExpr(expr.position())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export statement
|
// Export statement
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Stmt::Export(list) => {
|
Stmt::Export(list) => {
|
||||||
for ((id, id_pos), rename) in list.iter() {
|
for ((id, id_pos), rename) in list.iter() {
|
||||||
// Mark scope variables as public
|
// Mark scope variables as public
|
||||||
@ -1698,8 +1763,18 @@ impl Engine {
|
|||||||
.map_err(|err| err.new_position(stmt.position()))
|
.map_err(|err| err.new_position(stmt.position()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "unchecked")]
|
||||||
|
#[inline(always)]
|
||||||
|
fn check_data_size(
|
||||||
|
&self,
|
||||||
|
result: Result<Dynamic, Box<EvalAltResult>>,
|
||||||
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/// Check a result to ensure that the data size is within allowable limit.
|
/// Check a result to ensure that the data size is within allowable limit.
|
||||||
/// Position in `EvalAltResult` may be None and should be set afterwards.
|
/// Position in `EvalAltResult` may be None and should be set afterwards.
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
fn check_data_size(
|
fn check_data_size(
|
||||||
&self,
|
&self,
|
||||||
result: Result<Dynamic, Box<EvalAltResult>>,
|
result: Result<Dynamic, Box<EvalAltResult>>,
|
||||||
@ -1708,7 +1783,8 @@ impl Engine {
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
// If no data size limits, just return
|
// If no data size limits, just return
|
||||||
if self.max_string_size + self.max_array_size + self.max_map_size == 0 {
|
if self.limits.max_string_size + self.limits.max_array_size + self.limits.max_map_size == 0
|
||||||
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1768,37 +1844,37 @@ impl Engine {
|
|||||||
// Simply return all errors
|
// Simply return all errors
|
||||||
Err(_) => return result,
|
Err(_) => return result,
|
||||||
// String with limit
|
// String with limit
|
||||||
Ok(Dynamic(Union::Str(_))) if self.max_string_size > 0 => (),
|
Ok(Dynamic(Union::Str(_))) if self.limits.max_string_size > 0 => (),
|
||||||
// Array with limit
|
// Array with limit
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Ok(Dynamic(Union::Array(_))) if self.max_array_size > 0 => (),
|
Ok(Dynamic(Union::Array(_))) if self.limits.max_array_size > 0 => (),
|
||||||
// Map with limit
|
// Map with limit
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Ok(Dynamic(Union::Map(_))) if self.max_map_size > 0 => (),
|
Ok(Dynamic(Union::Map(_))) if self.limits.max_map_size > 0 => (),
|
||||||
// Everything else is simply returned
|
// Everything else is simply returned
|
||||||
Ok(_) => return result,
|
Ok(_) => return result,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (arr, map, s) = calc_size(result.as_ref().unwrap());
|
let (arr, map, s) = calc_size(result.as_ref().unwrap());
|
||||||
|
|
||||||
if s > self.max_string_size {
|
if s > self.limits.max_string_size {
|
||||||
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
||||||
"Length of string".to_string(),
|
"Length of string".to_string(),
|
||||||
self.max_string_size,
|
self.limits.max_string_size,
|
||||||
s,
|
s,
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)))
|
||||||
} else if arr > self.max_array_size {
|
} else if arr > self.limits.max_array_size {
|
||||||
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
||||||
"Size of array".to_string(),
|
"Size of array".to_string(),
|
||||||
self.max_array_size,
|
self.limits.max_array_size,
|
||||||
arr,
|
arr,
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)))
|
||||||
} else if map > self.max_map_size {
|
} else if map > self.limits.max_map_size {
|
||||||
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
||||||
"Number of properties in object map".to_string(),
|
"Number of properties in object map".to_string(),
|
||||||
self.max_map_size,
|
self.limits.max_map_size,
|
||||||
map,
|
map,
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)))
|
||||||
@ -1814,7 +1890,7 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
// Guard against too many operations
|
// Guard against too many operations
|
||||||
if self.max_operations > 0 && state.operations > self.max_operations {
|
if self.limits.max_operations > 0 && state.operations > self.limits.max_operations {
|
||||||
return Err(Box::new(EvalAltResult::ErrorTooManyOperations(
|
return Err(Box::new(EvalAltResult::ErrorTooManyOperations(
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
)));
|
||||||
|
@ -22,11 +22,10 @@ macro_rules! impl_args {
|
|||||||
fn into_vec(self) -> StaticVec<Dynamic> {
|
fn into_vec(self) -> StaticVec<Dynamic> {
|
||||||
let ($($p,)*) = self;
|
let ($($p,)*) = self;
|
||||||
|
|
||||||
#[allow(unused_mut)]
|
let mut _v = StaticVec::new();
|
||||||
let mut v = StaticVec::new();
|
$(_v.push($p.into_dynamic());)*
|
||||||
$(v.push($p.into_dynamic());)*
|
|
||||||
|
|
||||||
v
|
_v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,26 +3,34 @@
|
|||||||
use crate::any::Dynamic;
|
use crate::any::Dynamic;
|
||||||
use crate::calc_fn_hash;
|
use crate::calc_fn_hash;
|
||||||
use crate::engine::{
|
use crate::engine::{
|
||||||
search_imports, search_namespace, search_scope_only, Engine, Imports, State, Target, FN_GET,
|
search_imports, search_namespace, search_scope_only, Engine, Imports, State, KEYWORD_DEBUG,
|
||||||
FN_IDX_GET, FN_IDX_SET, FN_SET, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR,
|
KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_PRINT,
|
||||||
KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
KEYWORD_TYPE_OF,
|
||||||
};
|
};
|
||||||
use crate::error::ParseErrorType;
|
use crate::error::ParseErrorType;
|
||||||
use crate::fn_native::{FnCallArgs, FnPtr};
|
use crate::fn_native::{FnCallArgs, FnPtr};
|
||||||
use crate::module::{Module, ModuleRef};
|
use crate::module::{Module, ModuleRef};
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::parser::{Expr, ImmutableString, ScriptFnDef, AST, INT};
|
use crate::parser::{Expr, ImmutableString, AST, INT};
|
||||||
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
use crate::scope::Scope;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
use crate::utils::StaticVec;
|
use crate::utils::StaticVec;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
use crate::{
|
||||||
|
parser::ScriptFnDef, r#unsafe::unsafe_cast_var_name_to_lifetime,
|
||||||
|
scope::EntryType as ScopeEntryType,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use crate::parser::FLOAT;
|
use crate::parser::FLOAT;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
use crate::engine::{FN_IDX_GET, FN_IDX_SET};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
use crate::engine::Map;
|
use crate::engine::{Map, Target, FN_GET, FN_SET};
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::{type_name, TypeId},
|
any::{type_name, TypeId},
|
||||||
@ -36,20 +44,22 @@ use crate::stdlib::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Extract the property name from a getter function name.
|
/// Extract the property name from a getter function name.
|
||||||
fn extract_prop_from_getter(fn_name: &str) -> Option<&str> {
|
#[inline(always)]
|
||||||
|
fn extract_prop_from_getter(_fn_name: &str) -> Option<&str> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
if fn_name.starts_with(FN_GET) {
|
if _fn_name.starts_with(FN_GET) {
|
||||||
return Some(&fn_name[FN_GET.len()..]);
|
return Some(&_fn_name[FN_GET.len()..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract the property name from a setter function name.
|
/// Extract the property name from a setter function name.
|
||||||
fn extract_prop_from_setter(fn_name: &str) -> Option<&str> {
|
#[inline(always)]
|
||||||
|
fn extract_prop_from_setter(_fn_name: &str) -> Option<&str> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
if fn_name.starts_with(FN_SET) {
|
if _fn_name.starts_with(FN_SET) {
|
||||||
return Some(&fn_name[FN_SET.len()..]);
|
return Some(&_fn_name[FN_SET.len()..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
@ -106,17 +116,17 @@ impl Engine {
|
|||||||
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
|
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
|
||||||
pub(crate) fn call_fn_raw(
|
pub(crate) fn call_fn_raw(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut Scope,
|
_scope: &mut Scope,
|
||||||
mods: &mut Imports,
|
_mods: &mut Imports,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
lib: &Module,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
(hash_fn, hash_script): (u64, u64),
|
(hash_fn, hash_script): (u64, u64),
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
is_ref: bool,
|
is_ref: bool,
|
||||||
is_method: bool,
|
_is_method: bool,
|
||||||
def_val: Option<bool>,
|
def_val: Option<bool>,
|
||||||
level: usize,
|
_level: usize,
|
||||||
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||||
self.inc_operations(state)?;
|
self.inc_operations(state)?;
|
||||||
|
|
||||||
@ -125,7 +135,7 @@ impl Engine {
|
|||||||
// Check for stack overflow
|
// Check for stack overflow
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if level > self.max_call_stack_depth {
|
if _level > self.limits.max_call_stack_depth {
|
||||||
return Err(Box::new(
|
return Err(Box::new(
|
||||||
EvalAltResult::ErrorStackOverflow(Position::none()),
|
EvalAltResult::ErrorStackOverflow(Position::none()),
|
||||||
));
|
));
|
||||||
@ -151,7 +161,7 @@ impl Engine {
|
|||||||
|
|
||||||
if let Some(func) = func {
|
if let Some(func) = func {
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
let need_normalize = is_ref && (func.is_pure() || (func.is_script() && !is_method));
|
let need_normalize = is_ref && (func.is_pure() || (func.is_script() && !_is_method));
|
||||||
#[cfg(feature = "no_function")]
|
#[cfg(feature = "no_function")]
|
||||||
let need_normalize = is_ref && func.is_pure();
|
let need_normalize = is_ref && func.is_pure();
|
||||||
|
|
||||||
@ -164,25 +174,25 @@ impl Engine {
|
|||||||
let fn_def = func.get_fn_def();
|
let fn_def = func.get_fn_def();
|
||||||
|
|
||||||
// Method call of script function - map first argument to `this`
|
// Method call of script function - map first argument to `this`
|
||||||
return if is_method {
|
return if _is_method {
|
||||||
let (first, rest) = args.split_at_mut(1);
|
let (first, rest) = args.split_at_mut(1);
|
||||||
Ok((
|
Ok((
|
||||||
self.call_script_fn(
|
self.call_script_fn(
|
||||||
scope,
|
_scope,
|
||||||
mods,
|
_mods,
|
||||||
state,
|
state,
|
||||||
lib,
|
lib,
|
||||||
&mut Some(first[0]),
|
&mut Some(first[0]),
|
||||||
fn_name,
|
fn_name,
|
||||||
fn_def,
|
fn_def,
|
||||||
rest,
|
rest,
|
||||||
level,
|
_level,
|
||||||
)?,
|
)?,
|
||||||
false,
|
false,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
let result = self.call_script_fn(
|
let result = self.call_script_fn(
|
||||||
scope, mods, state, lib, &mut None, fn_name, fn_def, args, level,
|
_scope, _mods, state, lib, &mut None, fn_name, fn_def, args, _level,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Restore the original reference
|
// Restore the original reference
|
||||||
@ -256,6 +266,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// index getter function not found?
|
// index getter function not found?
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
if fn_name == FN_IDX_GET && args.len() == 2 {
|
if fn_name == FN_IDX_GET && args.len() == 2 {
|
||||||
return Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
return Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
||||||
format!(
|
format!(
|
||||||
@ -268,6 +279,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// index setter function not found?
|
// index setter function not found?
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
if fn_name == FN_IDX_SET {
|
if fn_name == FN_IDX_SET {
|
||||||
return Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
return Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
||||||
format!(
|
format!(
|
||||||
@ -305,6 +317,7 @@ impl Engine {
|
|||||||
/// Function call arguments may be _consumed_ when the function requires them to be passed by value.
|
/// Function call arguments may be _consumed_ when the function requires them to be passed by value.
|
||||||
/// All function arguments not in the first position are always passed by value and thus consumed.
|
/// All function arguments not in the first position are always passed by value and thus consumed.
|
||||||
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
|
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub(crate) fn call_script_fn(
|
pub(crate) fn call_script_fn(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
@ -486,6 +499,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Call a dot method.
|
/// Call a dot method.
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub(crate) fn make_method_call(
|
pub(crate) fn make_method_call(
|
||||||
&self,
|
&self,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
@ -506,9 +520,9 @@ impl Engine {
|
|||||||
// Get a reference to the mutation target Dynamic
|
// Get a reference to the mutation target Dynamic
|
||||||
let obj = target.as_mut();
|
let obj = target.as_mut();
|
||||||
let mut idx = idx_val.cast::<StaticVec<Dynamic>>();
|
let mut idx = idx_val.cast::<StaticVec<Dynamic>>();
|
||||||
let mut fn_name = name.as_ref();
|
let mut _fn_name = name.as_ref();
|
||||||
|
|
||||||
let (result, updated) = if fn_name == KEYWORD_FN_PTR_CALL && obj.is::<FnPtr>() {
|
let (result, updated) = if _fn_name == KEYWORD_FN_PTR_CALL && obj.is::<FnPtr>() {
|
||||||
// FnPtr call
|
// FnPtr call
|
||||||
let fn_ptr = obj.downcast_ref::<FnPtr>().unwrap();
|
let fn_ptr = obj.downcast_ref::<FnPtr>().unwrap();
|
||||||
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
|
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
|
||||||
@ -527,7 +541,7 @@ impl Engine {
|
|||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
state, lib, fn_name, *native, hash, args, false, false, *def_val, level,
|
state, lib, fn_name, *native, hash, args, false, false, *def_val, level,
|
||||||
)
|
)
|
||||||
} else if fn_name == KEYWORD_FN_PTR_CALL && idx.len() > 0 && idx[0].is::<FnPtr>() {
|
} else if _fn_name == KEYWORD_FN_PTR_CALL && idx.len() > 0 && idx[0].is::<FnPtr>() {
|
||||||
// FnPtr call on object
|
// FnPtr call on object
|
||||||
let fn_ptr = idx.remove(0).cast::<FnPtr>();
|
let fn_ptr = idx.remove(0).cast::<FnPtr>();
|
||||||
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
|
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
|
||||||
@ -546,7 +560,7 @@ impl Engine {
|
|||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
state, lib, &fn_name, *native, hash, args, is_ref, true, *def_val, level,
|
state, lib, &fn_name, *native, hash, args, is_ref, true, *def_val, level,
|
||||||
)
|
)
|
||||||
} else if fn_name == KEYWORD_FN_PTR_CURRY && obj.is::<FnPtr>() {
|
} else if _fn_name == KEYWORD_FN_PTR_CURRY && obj.is::<FnPtr>() {
|
||||||
// Curry call
|
// Curry call
|
||||||
let fn_ptr = obj.downcast_ref::<FnPtr>().unwrap();
|
let fn_ptr = obj.downcast_ref::<FnPtr>().unwrap();
|
||||||
Ok((
|
Ok((
|
||||||
@ -563,19 +577,20 @@ impl Engine {
|
|||||||
false,
|
false,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
let redirected;
|
let redirected;
|
||||||
let mut hash = *hash;
|
let mut _hash = *hash;
|
||||||
|
|
||||||
// Check if it is a map method call in OOP style
|
// Check if it is a map method call in OOP style
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
if let Some(map) = obj.downcast_ref::<Map>() {
|
if let Some(map) = obj.downcast_ref::<Map>() {
|
||||||
if let Some(val) = map.get(fn_name) {
|
if let Some(val) = map.get(_fn_name) {
|
||||||
if let Some(f) = val.downcast_ref::<FnPtr>() {
|
if let Some(f) = val.downcast_ref::<FnPtr>() {
|
||||||
// Remap the function name
|
// Remap the function name
|
||||||
redirected = f.get_fn_name().clone();
|
redirected = f.get_fn_name().clone();
|
||||||
fn_name = &redirected;
|
_fn_name = &redirected;
|
||||||
// Recalculate the hash based on the new function name
|
// Recalculate the hash based on the new function name
|
||||||
hash = calc_fn_hash(empty(), fn_name, idx.len(), empty());
|
_hash = calc_fn_hash(empty(), _fn_name, idx.len(), empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -585,7 +600,7 @@ impl Engine {
|
|||||||
let args = arg_values.as_mut();
|
let args = arg_values.as_mut();
|
||||||
|
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
state, lib, fn_name, *native, hash, args, is_ref, true, *def_val, level,
|
state, lib, _fn_name, *native, _hash, args, is_ref, true, *def_val, level,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.map_err(|err| err.new_position(*pos))?;
|
.map_err(|err| err.new_position(*pos))?;
|
||||||
@ -864,10 +879,22 @@ impl Engine {
|
|||||||
EvalAltResult::ErrorFunctionNotFound(_, _) if def_val.is_some() => {
|
EvalAltResult::ErrorFunctionNotFound(_, _) if def_val.is_some() => {
|
||||||
Ok(def_val.unwrap().into())
|
Ok(def_val.unwrap().into())
|
||||||
}
|
}
|
||||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
EvalAltResult::ErrorFunctionNotFound(_, pos) => {
|
||||||
Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
||||||
format!("{}{}", modules, name),
|
format!(
|
||||||
Position::none(),
|
"{}{} ({})",
|
||||||
|
modules,
|
||||||
|
name,
|
||||||
|
args.iter()
|
||||||
|
.map(|a| if a.is::<ImmutableString>() {
|
||||||
|
"&str | ImmutableString | String"
|
||||||
|
} else {
|
||||||
|
self.map_type_name((*a).type_name())
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
),
|
||||||
|
pos,
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
|
@ -2,16 +2,23 @@
|
|||||||
|
|
||||||
use crate::any::Dynamic;
|
use crate::any::Dynamic;
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::module::{FuncReturn, Module};
|
use crate::module::Module;
|
||||||
use crate::parser::ScriptFnDef;
|
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::{is_valid_identifier, Position};
|
use crate::token::{is_valid_identifier, Position};
|
||||||
use crate::utils::{ImmutableString, StaticVec};
|
use crate::utils::ImmutableString;
|
||||||
use crate::Scope;
|
|
||||||
|
|
||||||
use crate::stdlib::{
|
#[cfg(not(feature = "no_function"))]
|
||||||
boxed::Box, convert::TryFrom, fmt, mem, rc::Rc, string::String, sync::Arc, vec::Vec,
|
use crate::{module::FuncReturn, parser::ScriptFnDef, scope::Scope, utils::StaticVec};
|
||||||
};
|
|
||||||
|
use crate::stdlib::{boxed::Box, convert::TryFrom, fmt, string::String, vec::Vec};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
use crate::stdlib::mem;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "sync"))]
|
||||||
|
use crate::stdlib::rc::Rc;
|
||||||
|
#[cfg(feature = "sync")]
|
||||||
|
use crate::stdlib::sync::Arc;
|
||||||
|
|
||||||
/// Trait that maps to `Send + Sync` only under the `sync` feature.
|
/// Trait that maps to `Send + Sync` only under the `sync` feature.
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
@ -82,12 +89,17 @@ impl FnPtr {
|
|||||||
|
|
||||||
/// Call the function pointer with curried arguments (if any).
|
/// Call the function pointer with curried arguments (if any).
|
||||||
///
|
///
|
||||||
|
/// The function must be a script-defined function. It cannot be a Rust function.
|
||||||
|
///
|
||||||
|
/// To call a Rust function, just call it directly in Rust!
|
||||||
|
///
|
||||||
/// ## WARNING
|
/// ## WARNING
|
||||||
///
|
///
|
||||||
/// All the arguments are _consumed_, meaning that they're replaced by `()`.
|
/// All the arguments are _consumed_, meaning that they're replaced by `()`.
|
||||||
/// This is to avoid unnecessarily cloning the arguments.
|
/// This is to avoid unnecessarily cloning the arguments.
|
||||||
/// Do not use the arguments after this call. If they are needed afterwards,
|
/// Do not use the arguments after this call. If they are needed afterwards,
|
||||||
/// clone them _before_ calling this function.
|
/// clone them _before_ calling this function.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub fn call_dynamic(
|
pub fn call_dynamic(
|
||||||
&self,
|
&self,
|
||||||
engine: &Engine,
|
engine: &Engine,
|
||||||
|
@ -133,12 +133,11 @@ macro_rules! make_func {
|
|||||||
Box::new(move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
Box::new(move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
||||||
// The arguments are assumed to be of the correct number and types!
|
// The arguments are assumed to be of the correct number and types!
|
||||||
|
|
||||||
#[allow(unused_variables, unused_mut)]
|
let mut _drain = args.iter_mut();
|
||||||
let mut drain = args.iter_mut();
|
|
||||||
$(
|
$(
|
||||||
// Downcast every element, panic in case of a type mismatch (which shouldn't happen).
|
// Downcast every element, panic in case of a type mismatch (which shouldn't happen).
|
||||||
// Call the user-supplied function using ($convert) to access it either by value or by reference.
|
// Call the user-supplied function using ($convert) to access it either by value or by reference.
|
||||||
let $par = ($convert)(drain.next().unwrap());
|
let $par = ($convert)(_drain.next().unwrap());
|
||||||
)*
|
)*
|
||||||
|
|
||||||
// Call the function with each parameter value
|
// Call the function with each parameter value
|
||||||
|
@ -170,7 +170,7 @@ pub use parser::{CustomExpr, Expr, FloatWrapper, ReturnType, ScriptFnDef, Stmt};
|
|||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[deprecated(note = "this type is volatile and may change")]
|
#[deprecated(note = "this type is volatile and may change")]
|
||||||
pub use engine::{Imports, State as EvalState};
|
pub use engine::{Imports, Limits, State as EvalState};
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[deprecated(note = "this type is volatile and may change")]
|
#[deprecated(note = "this type is volatile and may change")]
|
||||||
|
@ -2,22 +2,33 @@
|
|||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::calc_fn_hash;
|
use crate::calc_fn_hash;
|
||||||
use crate::engine::{make_getter, make_setter, Engine, Imports, FN_IDX_GET, FN_IDX_SET};
|
use crate::engine::Engine;
|
||||||
use crate::fn_native::{CallableFunction as Func, FnCallArgs, IteratorFn, SendSync, Shared};
|
use crate::fn_native::{CallableFunction as Func, FnCallArgs, IteratorFn, SendSync};
|
||||||
use crate::parser::{
|
use crate::parser::{FnAccess, FnAccess::Public};
|
||||||
FnAccess,
|
|
||||||
FnAccess::{Private, Public},
|
|
||||||
ScriptFnDef, AST,
|
|
||||||
};
|
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::{Entry as ScopeEntry, Scope};
|
|
||||||
use crate::token::{Position, Token};
|
use crate::token::{Position, Token};
|
||||||
use crate::utils::{StaticVec, StraightHasherBuilder};
|
use crate::utils::{StaticVec, StraightHasherBuilder};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
use crate::{fn_native::Shared, parser::ScriptFnDef};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
use crate::{
|
||||||
|
engine::Imports,
|
||||||
|
parser::AST,
|
||||||
|
scope::{Entry as ScopeEntry, Scope},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
use crate::engine::{FN_IDX_GET, FN_IDX_SET};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
use crate::engine::{make_getter, make_setter};
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
cell::RefCell,
|
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt, format,
|
fmt, format,
|
||||||
iter::empty,
|
iter::empty,
|
||||||
@ -25,11 +36,16 @@ use crate::stdlib::{
|
|||||||
num::NonZeroUsize,
|
num::NonZeroUsize,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
vec,
|
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
#[cfg(not(feature = "sync"))]
|
||||||
|
use crate::stdlib::cell::RefCell;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_std"))]
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
use crate::stdlib::sync::RwLock;
|
use crate::stdlib::sync::RwLock;
|
||||||
|
|
||||||
@ -738,6 +754,8 @@ impl Module {
|
|||||||
/// });
|
/// });
|
||||||
/// assert!(module.contains_fn(hash));
|
/// assert!(module.contains_fn(hash));
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone>(
|
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
func: impl Fn(&mut A, B, C) -> FuncReturn<()> + SendSync + 'static,
|
func: impl Fn(&mut A, B, C) -> FuncReturn<()> + SendSync + 'static,
|
||||||
@ -781,6 +799,8 @@ impl Module {
|
|||||||
/// assert!(module.contains_fn(hash_get));
|
/// assert!(module.contains_fn(hash_get));
|
||||||
/// assert!(module.contains_fn(hash_set));
|
/// assert!(module.contains_fn(hash_set));
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub fn set_indexer_get_set_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
pub fn set_indexer_get_set_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
getter: impl Fn(&mut A, B) -> FuncReturn<T> + SendSync + 'static,
|
getter: impl Fn(&mut A, B) -> FuncReturn<T> + SendSync + 'static,
|
||||||
@ -909,11 +929,11 @@ impl Module {
|
|||||||
self.merge_filtered(other, |_, _, _| true)
|
self.merge_filtered(other, |_, _, _| true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Merge another module into this module, with only selected functions based on a filter predicate.
|
/// Merge another module into this module, with only selected script-defined functions based on a filter predicate.
|
||||||
pub(crate) fn merge_filtered(
|
pub(crate) fn merge_filtered(
|
||||||
&mut self,
|
&mut self,
|
||||||
other: &Self,
|
other: &Self,
|
||||||
filter: impl Fn(FnAccess, &str, usize) -> bool,
|
_filter: impl Fn(FnAccess, &str, usize) -> bool,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.variables
|
self.variables
|
||||||
.extend(other.variables.iter().map(|(k, v)| (k.clone(), v.clone())));
|
.extend(other.variables.iter().map(|(k, v)| (k.clone(), v.clone())));
|
||||||
@ -924,7 +944,7 @@ impl Module {
|
|||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, (_, _, _, v))| match v {
|
.filter(|(_, (_, _, _, v))| match v {
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Func::Script(ref f) => filter(f.access, f.name.as_str(), f.params.len()),
|
Func::Script(ref f) => _filter(f.access, f.name.as_str(), f.params.len()),
|
||||||
_ => true,
|
_ => true,
|
||||||
})
|
})
|
||||||
.map(|(&k, v)| (k, v.clone())),
|
.map(|(&k, v)| (k, v.clone())),
|
||||||
@ -975,6 +995,7 @@ impl Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get an iterator to the functions in the module.
|
/// Get an iterator to the functions in the module.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub(crate) fn iter_fn(
|
pub(crate) fn iter_fn(
|
||||||
&self,
|
&self,
|
||||||
) -> impl Iterator<Item = &(String, FnAccess, StaticVec<TypeId>, Func)> {
|
) -> impl Iterator<Item = &(String, FnAccess, StaticVec<TypeId>, Func)> {
|
||||||
@ -1038,6 +1059,7 @@ impl Module {
|
|||||||
|
|
||||||
/// Scan through all the sub-modules in the module build an index of all
|
/// Scan through all the sub-modules in the module build an index of all
|
||||||
/// variables and external Rust functions via hashing.
|
/// variables and external Rust functions via hashing.
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub(crate) fn index_all_sub_modules(&mut self) {
|
pub(crate) fn index_all_sub_modules(&mut self) {
|
||||||
// Collect a particular module.
|
// Collect a particular module.
|
||||||
fn index_module<'a>(
|
fn index_module<'a>(
|
||||||
@ -1063,8 +1085,8 @@ impl Module {
|
|||||||
for (name, access, params, func) in module.functions.values() {
|
for (name, access, params, func) in module.functions.values() {
|
||||||
match access {
|
match access {
|
||||||
// Private functions are not exported
|
// Private functions are not exported
|
||||||
Private => continue,
|
FnAccess::Private => continue,
|
||||||
Public => (),
|
FnAccess::Public => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
@ -1100,10 +1122,13 @@ impl Module {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut variables = Vec::new();
|
let mut qualifiers: Vec<_> = Default::default();
|
||||||
let mut functions = Vec::new();
|
let mut variables: Vec<_> = Default::default();
|
||||||
|
let mut functions: Vec<_> = Default::default();
|
||||||
|
|
||||||
index_module(self, &mut vec!["root"], &mut variables, &mut functions);
|
qualifiers.push("root");
|
||||||
|
|
||||||
|
index_module(self, &mut qualifiers, &mut variables, &mut functions);
|
||||||
|
|
||||||
self.all_variables = variables.into_iter().collect();
|
self.all_variables = variables.into_iter().collect();
|
||||||
self.all_functions = functions.into_iter().collect();
|
self.all_functions = functions.into_iter().collect();
|
||||||
|
@ -6,11 +6,14 @@ use crate::engine::{
|
|||||||
Engine, Imports, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
Engine, Imports, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
||||||
};
|
};
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
use crate::parser::{map_dynamic_to_expr, Expr, ReturnType, ScriptFnDef, Stmt, AST};
|
use crate::parser::{map_dynamic_to_expr, Expr, ScriptFnDef, Stmt, AST};
|
||||||
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
|
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
|
||||||
use crate::token::is_valid_identifier;
|
use crate::token::is_valid_identifier;
|
||||||
use crate::utils::StaticVec;
|
use crate::utils::StaticVec;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
use crate::parser::ReturnType;
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
use crate::parser::CustomExpr;
|
use crate::parser::CustomExpr;
|
||||||
|
|
||||||
@ -249,6 +252,7 @@ fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
|
|||||||
// let id;
|
// let id;
|
||||||
stmt @ Stmt::Let(_) => stmt,
|
stmt @ Stmt::Let(_) => stmt,
|
||||||
// import expr as id;
|
// import expr as id;
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Stmt::Import(x) => Stmt::Import(Box::new((optimize_expr(x.0, state), x.1))),
|
Stmt::Import(x) => Stmt::Import(Box::new((optimize_expr(x.0, state), x.1))),
|
||||||
// { block }
|
// { block }
|
||||||
Stmt::Block(x) => {
|
Stmt::Block(x) => {
|
||||||
@ -290,6 +294,7 @@ fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
|
|||||||
match expr {
|
match expr {
|
||||||
Stmt::Let(x) if x.1.is_none() => removed = true,
|
Stmt::Let(x) if x.1.is_none() => removed = true,
|
||||||
Stmt::Let(x) if x.1.is_some() => removed = x.1.unwrap().is_pure(),
|
Stmt::Let(x) if x.1.is_some() => removed = x.1.unwrap().is_pure(),
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Stmt::Import(x) => removed = x.0.is_pure(),
|
Stmt::Import(x) => removed = x.0.is_pure(),
|
||||||
_ => {
|
_ => {
|
||||||
result.push(expr);
|
result.push(expr);
|
||||||
@ -345,8 +350,11 @@ fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
|
|||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
Stmt::Noop(pos)
|
Stmt::Noop(pos)
|
||||||
}
|
}
|
||||||
// Only one let/import statement - leave it alone
|
// Only one let statement - leave it alone
|
||||||
[Stmt::Let(_)] | [Stmt::Import(_)] => Stmt::Block(Box::new((result.into(), pos))),
|
[Stmt::Let(_)] => Stmt::Block(Box::new((result.into(), pos))),
|
||||||
|
// Only one import statement - leave it alone
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
[Stmt::Import(_)] => Stmt::Block(Box::new((result.into(), pos))),
|
||||||
// Only one statement - promote
|
// Only one statement - promote
|
||||||
[_] => {
|
[_] => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
@ -557,16 +565,16 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
|
|||||||
// First search in functions lib (can override built-in)
|
// First search in functions lib (can override built-in)
|
||||||
// Cater for both normal function call style and method call style (one additional arguments)
|
// Cater for both normal function call style and method call style (one additional arguments)
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
let has_script_fn = state.lib.iter_fn().find(|(_, _, _, f)| {
|
let _has_script_fn = state.lib.iter_fn().find(|(_, _, _, f)| {
|
||||||
if !f.is_script() { return false; }
|
if !f.is_script() { return false; }
|
||||||
let fn_def = f.get_fn_def();
|
let fn_def = f.get_fn_def();
|
||||||
fn_def.name.as_str() == name && (args.len()..=args.len() + 1).contains(&fn_def.params.len())
|
fn_def.name.as_str() == name && (args.len()..=args.len() + 1).contains(&fn_def.params.len())
|
||||||
}).is_some();
|
}).is_some();
|
||||||
|
|
||||||
#[cfg(feature = "no_function")]
|
#[cfg(feature = "no_function")]
|
||||||
const has_script_fn: bool = false;
|
let _has_script_fn: bool = false;
|
||||||
|
|
||||||
if has_script_fn {
|
if _has_script_fn {
|
||||||
// A script-defined function overrides the built-in function - do not make the call
|
// A script-defined function overrides the built-in function - do not make the call
|
||||||
x.3 = x.3.into_iter().map(|a| optimize_expr(a, state)).collect();
|
x.3 = x.3.into_iter().map(|a| optimize_expr(a, state)).collect();
|
||||||
return Expr::FnCall(x);
|
return Expr::FnCall(x);
|
||||||
@ -686,7 +694,9 @@ fn optimize(
|
|||||||
// Keep all variable declarations at this level
|
// Keep all variable declarations at this level
|
||||||
// and always keep the last return value
|
// and always keep the last return value
|
||||||
let keep = match stmt {
|
let keep = match stmt {
|
||||||
Stmt::Let(_) | Stmt::Import(_) => true,
|
Stmt::Let(_) => true,
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
Stmt::Import(_) => true,
|
||||||
_ => i == num_statements - 1,
|
_ => i == num_statements - 1,
|
||||||
};
|
};
|
||||||
optimize_stmt(stmt, &mut state, keep)
|
optimize_stmt(stmt, &mut state, keep)
|
||||||
@ -721,7 +731,7 @@ pub fn optimize_into_ast(
|
|||||||
engine: &Engine,
|
engine: &Engine,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
statements: Vec<Stmt>,
|
statements: Vec<Stmt>,
|
||||||
functions: Vec<ScriptFnDef>,
|
_functions: Vec<ScriptFnDef>,
|
||||||
level: OptimizationLevel,
|
level: OptimizationLevel,
|
||||||
) -> AST {
|
) -> AST {
|
||||||
#[cfg(feature = "no_optimize")]
|
#[cfg(feature = "no_optimize")]
|
||||||
@ -735,7 +745,7 @@ pub fn optimize_into_ast(
|
|||||||
// We only need the script library's signatures for optimization purposes
|
// We only need the script library's signatures for optimization purposes
|
||||||
let mut lib2 = Module::new();
|
let mut lib2 = Module::new();
|
||||||
|
|
||||||
functions
|
_functions
|
||||||
.iter()
|
.iter()
|
||||||
.map(|fn_def| {
|
.map(|fn_def| {
|
||||||
ScriptFnDef {
|
ScriptFnDef {
|
||||||
@ -751,7 +761,7 @@ pub fn optimize_into_ast(
|
|||||||
lib2.set_script_fn(fn_def);
|
lib2.set_script_fn(fn_def);
|
||||||
});
|
});
|
||||||
|
|
||||||
functions
|
_functions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|mut fn_def| {
|
.map(|mut fn_def| {
|
||||||
let pos = fn_def.body.position();
|
let pos = fn_def.body.position();
|
||||||
@ -782,7 +792,7 @@ pub fn optimize_into_ast(
|
|||||||
module.set_script_fn(fn_def);
|
module.set_script_fn(fn_def);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
functions.into_iter().for_each(|fn_def| {
|
_functions.into_iter().for_each(|fn_def| {
|
||||||
module.set_script_fn(fn_def);
|
module.set_script_fn(fn_def);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::module::FuncReturn;
|
use crate::module::FuncReturn;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
use crate::result::EvalAltResult;
|
|
||||||
use crate::token::Position;
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
use crate::{result::EvalAltResult, token::Position};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use crate::parser::FLOAT;
|
use crate::parser::FLOAT;
|
||||||
@ -11,19 +12,25 @@ use crate::parser::FLOAT;
|
|||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use num_traits::*;
|
use num_traits::*;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
use num_traits::{
|
use num_traits::{
|
||||||
identities::Zero, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl,
|
identities::Zero, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl,
|
||||||
CheckedShr, CheckedSub,
|
CheckedShr, CheckedSub,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::ops::{BitAnd, BitOr, BitXor};
|
||||||
boxed::Box,
|
|
||||||
fmt::Display,
|
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
|
||||||
format,
|
use crate::stdlib::ops::{Add, Div, Mul, Neg, Rem, Sub};
|
||||||
ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub},
|
|
||||||
};
|
#[cfg(feature = "unchecked")]
|
||||||
|
use crate::stdlib::ops::{Shl, Shr};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
use crate::stdlib::{boxed::Box, fmt::Display, format};
|
||||||
|
|
||||||
// Checked add
|
// Checked add
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub(crate) fn add<T: Display + CheckedAdd>(x: T, y: T) -> FuncReturn<T> {
|
pub(crate) fn add<T: Display + CheckedAdd>(x: T, y: T) -> FuncReturn<T> {
|
||||||
x.checked_add(&y).ok_or_else(|| {
|
x.checked_add(&y).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
Box::new(EvalAltResult::ErrorArithmetic(
|
||||||
@ -33,6 +40,7 @@ pub(crate) fn add<T: Display + CheckedAdd>(x: T, y: T) -> FuncReturn<T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Checked subtract
|
// Checked subtract
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub(crate) fn sub<T: Display + CheckedSub>(x: T, y: T) -> FuncReturn<T> {
|
pub(crate) fn sub<T: Display + CheckedSub>(x: T, y: T) -> FuncReturn<T> {
|
||||||
x.checked_sub(&y).ok_or_else(|| {
|
x.checked_sub(&y).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
Box::new(EvalAltResult::ErrorArithmetic(
|
||||||
@ -42,6 +50,7 @@ pub(crate) fn sub<T: Display + CheckedSub>(x: T, y: T) -> FuncReturn<T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Checked multiply
|
// Checked multiply
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub(crate) fn mul<T: Display + CheckedMul>(x: T, y: T) -> FuncReturn<T> {
|
pub(crate) fn mul<T: Display + CheckedMul>(x: T, y: T) -> FuncReturn<T> {
|
||||||
x.checked_mul(&y).ok_or_else(|| {
|
x.checked_mul(&y).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
Box::new(EvalAltResult::ErrorArithmetic(
|
||||||
@ -51,6 +60,7 @@ pub(crate) fn mul<T: Display + CheckedMul>(x: T, y: T) -> FuncReturn<T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Checked divide
|
// Checked divide
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub(crate) fn div<T>(x: T, y: T) -> FuncReturn<T>
|
pub(crate) fn div<T>(x: T, y: T) -> FuncReturn<T>
|
||||||
where
|
where
|
||||||
T: Display + CheckedDiv + PartialEq + Zero,
|
T: Display + CheckedDiv + PartialEq + Zero,
|
||||||
@ -71,6 +81,7 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Checked negative - e.g. -(i32::MIN) will overflow i32::MAX
|
// Checked negative - e.g. -(i32::MIN) will overflow i32::MAX
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub(crate) fn neg<T: Display + CheckedNeg>(x: T) -> FuncReturn<T> {
|
pub(crate) fn neg<T: Display + CheckedNeg>(x: T) -> FuncReturn<T> {
|
||||||
x.checked_neg().ok_or_else(|| {
|
x.checked_neg().ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
Box::new(EvalAltResult::ErrorArithmetic(
|
||||||
@ -80,6 +91,7 @@ pub(crate) fn neg<T: Display + CheckedNeg>(x: T) -> FuncReturn<T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Checked absolute
|
// Checked absolute
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub(crate) fn abs<T: Display + CheckedNeg + PartialOrd + Zero>(x: T) -> FuncReturn<T> {
|
pub(crate) fn abs<T: Display + CheckedNeg + PartialOrd + Zero>(x: T) -> FuncReturn<T> {
|
||||||
// FIX - We don't use Signed::abs() here because, contrary to documentation, it panics
|
// FIX - We don't use Signed::abs() here because, contrary to documentation, it panics
|
||||||
// when the number is ::MIN instead of returning ::MIN itself.
|
// when the number is ::MIN instead of returning ::MIN itself.
|
||||||
@ -95,26 +107,32 @@ pub(crate) fn abs<T: Display + CheckedNeg + PartialOrd + Zero>(x: T) -> FuncRetu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Unchecked add - may panic on overflow
|
// Unchecked add - may panic on overflow
|
||||||
|
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
|
||||||
fn add_u<T: Add>(x: T, y: T) -> FuncReturn<<T as Add>::Output> {
|
fn add_u<T: Add>(x: T, y: T) -> FuncReturn<<T as Add>::Output> {
|
||||||
Ok(x + y)
|
Ok(x + y)
|
||||||
}
|
}
|
||||||
// Unchecked subtract - may panic on underflow
|
// Unchecked subtract - may panic on underflow
|
||||||
|
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
|
||||||
fn sub_u<T: Sub>(x: T, y: T) -> FuncReturn<<T as Sub>::Output> {
|
fn sub_u<T: Sub>(x: T, y: T) -> FuncReturn<<T as Sub>::Output> {
|
||||||
Ok(x - y)
|
Ok(x - y)
|
||||||
}
|
}
|
||||||
// Unchecked multiply - may panic on overflow
|
// Unchecked multiply - may panic on overflow
|
||||||
|
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
|
||||||
fn mul_u<T: Mul>(x: T, y: T) -> FuncReturn<<T as Mul>::Output> {
|
fn mul_u<T: Mul>(x: T, y: T) -> FuncReturn<<T as Mul>::Output> {
|
||||||
Ok(x * y)
|
Ok(x * y)
|
||||||
}
|
}
|
||||||
// Unchecked divide - may panic when dividing by zero
|
// Unchecked divide - may panic when dividing by zero
|
||||||
|
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
|
||||||
fn div_u<T: Div>(x: T, y: T) -> FuncReturn<<T as Div>::Output> {
|
fn div_u<T: Div>(x: T, y: T) -> FuncReturn<<T as Div>::Output> {
|
||||||
Ok(x / y)
|
Ok(x / y)
|
||||||
}
|
}
|
||||||
// Unchecked negative - may panic on overflow
|
// Unchecked negative - may panic on overflow
|
||||||
|
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
|
||||||
fn neg_u<T: Neg>(x: T) -> FuncReturn<<T as Neg>::Output> {
|
fn neg_u<T: Neg>(x: T) -> FuncReturn<<T as Neg>::Output> {
|
||||||
Ok(-x)
|
Ok(-x)
|
||||||
}
|
}
|
||||||
// Unchecked absolute - may panic on overflow
|
// Unchecked absolute - may panic on overflow
|
||||||
|
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
|
||||||
fn abs_u<T>(x: T) -> FuncReturn<<T as Neg>::Output>
|
fn abs_u<T>(x: T) -> FuncReturn<<T as Neg>::Output>
|
||||||
where
|
where
|
||||||
T: Neg + PartialOrd + Default + Into<<T as Neg>::Output>,
|
T: Neg + PartialOrd + Default + Into<<T as Neg>::Output>,
|
||||||
@ -137,6 +155,7 @@ fn binary_xor<T: BitXor>(x: T, y: T) -> FuncReturn<<T as BitXor>::Output> {
|
|||||||
Ok(x ^ y)
|
Ok(x ^ y)
|
||||||
}
|
}
|
||||||
// Checked left-shift
|
// Checked left-shift
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub(crate) fn shl<T: Display + CheckedShl>(x: T, y: INT) -> FuncReturn<T> {
|
pub(crate) fn shl<T: Display + CheckedShl>(x: T, y: INT) -> FuncReturn<T> {
|
||||||
// Cannot shift by a negative number of bits
|
// Cannot shift by a negative number of bits
|
||||||
if y < 0 {
|
if y < 0 {
|
||||||
@ -154,6 +173,7 @@ pub(crate) fn shl<T: Display + CheckedShl>(x: T, y: INT) -> FuncReturn<T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Checked right-shift
|
// Checked right-shift
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub(crate) fn shr<T: Display + CheckedShr>(x: T, y: INT) -> FuncReturn<T> {
|
pub(crate) fn shr<T: Display + CheckedShr>(x: T, y: INT) -> FuncReturn<T> {
|
||||||
// Cannot shift by a negative number of bits
|
// Cannot shift by a negative number of bits
|
||||||
if y < 0 {
|
if y < 0 {
|
||||||
@ -171,14 +191,17 @@ pub(crate) fn shr<T: Display + CheckedShr>(x: T, y: INT) -> FuncReturn<T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Unchecked left-shift - may panic if shifting by a negative number of bits
|
// Unchecked left-shift - may panic if shifting by a negative number of bits
|
||||||
|
#[cfg(feature = "unchecked")]
|
||||||
pub(crate) fn shl_u<T: Shl<T>>(x: T, y: T) -> FuncReturn<<T as Shl<T>>::Output> {
|
pub(crate) fn shl_u<T: Shl<T>>(x: T, y: T) -> FuncReturn<<T as Shl<T>>::Output> {
|
||||||
Ok(x.shl(y))
|
Ok(x.shl(y))
|
||||||
}
|
}
|
||||||
// Unchecked right-shift - may panic if shifting by a negative number of bits
|
// Unchecked right-shift - may panic if shifting by a negative number of bits
|
||||||
|
#[cfg(feature = "unchecked")]
|
||||||
pub(crate) fn shr_u<T: Shr<T>>(x: T, y: T) -> FuncReturn<<T as Shr<T>>::Output> {
|
pub(crate) fn shr_u<T: Shr<T>>(x: T, y: T) -> FuncReturn<<T as Shr<T>>::Output> {
|
||||||
Ok(x.shr(y))
|
Ok(x.shr(y))
|
||||||
}
|
}
|
||||||
// Checked modulo
|
// Checked modulo
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub(crate) fn modulo<T: Display + CheckedRem>(x: T, y: T) -> FuncReturn<T> {
|
pub(crate) fn modulo<T: Display + CheckedRem>(x: T, y: T) -> FuncReturn<T> {
|
||||||
x.checked_rem(&y).ok_or_else(|| {
|
x.checked_rem(&y).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
Box::new(EvalAltResult::ErrorArithmetic(
|
||||||
@ -188,10 +211,12 @@ pub(crate) fn modulo<T: Display + CheckedRem>(x: T, y: T) -> FuncReturn<T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Unchecked modulo - may panic if dividing by zero
|
// Unchecked modulo - may panic if dividing by zero
|
||||||
|
#[cfg(any(feature = "unchecked", not(feature = "no_float")))]
|
||||||
fn modulo_u<T: Rem>(x: T, y: T) -> FuncReturn<<T as Rem>::Output> {
|
fn modulo_u<T: Rem>(x: T, y: T) -> FuncReturn<<T as Rem>::Output> {
|
||||||
Ok(x % y)
|
Ok(x % y)
|
||||||
}
|
}
|
||||||
// Checked power
|
// Checked power
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub(crate) fn pow_i_i(x: INT, y: INT) -> FuncReturn<INT> {
|
pub(crate) fn pow_i_i(x: INT, y: INT) -> FuncReturn<INT> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
if y > (u32::MAX as INT) {
|
if y > (u32::MAX as INT) {
|
||||||
@ -229,6 +254,7 @@ pub(crate) fn pow_i_i(x: INT, y: INT) -> FuncReturn<INT> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Unchecked integer power - may panic on overflow or if the power index is too high (> u32::MAX)
|
// Unchecked integer power - may panic on overflow or if the power index is too high (> u32::MAX)
|
||||||
|
#[cfg(feature = "unchecked")]
|
||||||
pub(crate) fn pow_i_i_u(x: INT, y: INT) -> FuncReturn<INT> {
|
pub(crate) fn pow_i_i_u(x: INT, y: INT) -> FuncReturn<INT> {
|
||||||
Ok(x.pow(y as u32))
|
Ok(x.pow(y as u32))
|
||||||
}
|
}
|
||||||
@ -239,6 +265,7 @@ pub(crate) fn pow_f_f(x: FLOAT, y: FLOAT) -> FuncReturn<FLOAT> {
|
|||||||
}
|
}
|
||||||
// Checked power
|
// Checked power
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub(crate) fn pow_f_i(x: FLOAT, y: INT) -> FuncReturn<FLOAT> {
|
pub(crate) fn pow_f_i(x: FLOAT, y: INT) -> FuncReturn<FLOAT> {
|
||||||
// Raise to power that is larger than an i32
|
// Raise to power that is larger than an i32
|
||||||
if y > (i32::MAX as INT) {
|
if y > (i32::MAX as INT) {
|
||||||
|
@ -5,10 +5,14 @@ use crate::def_package;
|
|||||||
use crate::engine::{Array, Engine};
|
use crate::engine::{Array, Engine};
|
||||||
use crate::module::{FuncReturn, Module};
|
use crate::module::{FuncReturn, Module};
|
||||||
use crate::parser::{ImmutableString, INT};
|
use crate::parser::{ImmutableString, INT};
|
||||||
use crate::result::EvalAltResult;
|
|
||||||
use crate::token::Position;
|
|
||||||
|
|
||||||
use crate::stdlib::{any::TypeId, boxed::Box, string::ToString};
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
use crate::{result::EvalAltResult, token::Position};
|
||||||
|
|
||||||
|
use crate::stdlib::{any::TypeId, boxed::Box};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
use crate::stdlib::string::ToString;
|
||||||
|
|
||||||
// Register array utility functions
|
// Register array utility functions
|
||||||
fn push<T: Variant + Clone>(list: &mut Array, item: T) -> FuncReturn<()> {
|
fn push<T: Variant + Clone>(list: &mut Array, item: T) -> FuncReturn<()> {
|
||||||
@ -26,7 +30,7 @@ fn ins<T: Variant + Clone>(list: &mut Array, position: INT, item: T) -> FuncRetu
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn pad<T: Variant + Clone>(
|
fn pad<T: Variant + Clone>(
|
||||||
engine: &Engine,
|
_engine: &Engine,
|
||||||
_: &Module,
|
_: &Module,
|
||||||
args: &mut [&mut Dynamic],
|
args: &mut [&mut Dynamic],
|
||||||
) -> FuncReturn<()> {
|
) -> FuncReturn<()> {
|
||||||
@ -34,10 +38,13 @@ fn pad<T: Variant + Clone>(
|
|||||||
|
|
||||||
// Check if array will be over max size limit
|
// Check if array will be over max size limit
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if engine.max_array_size > 0 && len > 0 && (len as usize) > engine.max_array_size {
|
if _engine.limits.max_array_size > 0
|
||||||
|
&& len > 0
|
||||||
|
&& (len as usize) > _engine.limits.max_array_size
|
||||||
|
{
|
||||||
return Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
return Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
||||||
"Size of array".to_string(),
|
"Size of array".to_string(),
|
||||||
engine.max_array_size,
|
_engine.limits.max_array_size,
|
||||||
len as usize,
|
len as usize,
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
)));
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
#![cfg(not(feature = "no_object"))]
|
#![cfg(not(feature = "no_object"))]
|
||||||
|
|
||||||
use crate::any::Dynamic;
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::engine::Map;
|
use crate::engine::Map;
|
||||||
use crate::module::FuncReturn;
|
|
||||||
use crate::parser::{ImmutableString, INT};
|
use crate::parser::{ImmutableString, INT};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
use crate::{any::Dynamic, module::FuncReturn};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
use crate::stdlib::vec::Vec;
|
use crate::stdlib::vec::Vec;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
fn map_get_keys(map: &mut Map) -> FuncReturn<Vec<Dynamic>> {
|
fn map_get_keys(map: &mut Map) -> FuncReturn<Vec<Dynamic>> {
|
||||||
Ok(map.iter().map(|(k, _)| k.clone().into()).collect())
|
Ok(map.iter().map(|(k, _)| k.clone().into()).collect())
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
fn map_get_values(map: &mut Map) -> FuncReturn<Vec<Dynamic>> {
|
fn map_get_values(map: &mut Map) -> FuncReturn<Vec<Dynamic>> {
|
||||||
Ok(map.iter().map(|(_, v)| v.clone()).collect())
|
Ok(map.iter().map(|(_, v)| v.clone()).collect())
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,26 @@
|
|||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
use crate::result::EvalAltResult;
|
|
||||||
use crate::token::Position;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use crate::parser::FLOAT;
|
use crate::parser::FLOAT;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
use crate::{result::EvalAltResult, token::Position};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use num_traits::*;
|
use num_traits::*;
|
||||||
|
|
||||||
use crate::stdlib::{boxed::Box, format, i32, i64};
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
use crate::stdlib::{boxed::Box, format};
|
||||||
|
|
||||||
#[cfg(feature = "only_i32")]
|
#[cfg(feature = "only_i32")]
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub const MAX_INT: INT = i32::MAX;
|
pub const MAX_INT: INT = i32::MAX;
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub const MAX_INT: INT = i64::MAX;
|
pub const MAX_INT: INT = i64::MAX;
|
||||||
|
|
||||||
def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, {
|
def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, {
|
||||||
|
@ -24,7 +24,6 @@ pub use arithmetic::ArithmeticPackage;
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub use array_basic::BasicArrayPackage;
|
pub use array_basic::BasicArrayPackage;
|
||||||
pub use eval::EvalPackage;
|
pub use eval::EvalPackage;
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
pub use fn_basic::BasicFnPackage;
|
pub use fn_basic::BasicFnPackage;
|
||||||
pub use iter_basic::BasicIteratorPackage;
|
pub use iter_basic::BasicIteratorPackage;
|
||||||
pub use logic::LogicPackage;
|
pub use logic::LogicPackage;
|
||||||
@ -74,6 +73,7 @@ impl PackagesCollection {
|
|||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
/// Does the specified TypeId iterator exist in the `PackagesCollection`?
|
/// Does the specified TypeId iterator exist in the `PackagesCollection`?
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn contains_iter(&self, id: TypeId) -> bool {
|
pub fn contains_iter(&self, id: TypeId) -> bool {
|
||||||
self.0.iter().any(|p| p.contains_iter(id))
|
self.0.iter().any(|p| p.contains_iter(id))
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,11 @@ use crate::def_package;
|
|||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::module::{FuncReturn, Module};
|
use crate::module::{FuncReturn, Module};
|
||||||
use crate::parser::{ImmutableString, INT};
|
use crate::parser::{ImmutableString, INT};
|
||||||
use crate::result::EvalAltResult;
|
|
||||||
use crate::token::Position;
|
|
||||||
use crate::utils::StaticVec;
|
use crate::utils::StaticVec;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
use crate::{result::EvalAltResult, token::Position};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
use crate::engine::Array;
|
use crate::engine::Array;
|
||||||
|
|
||||||
@ -226,15 +227,15 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str
|
|||||||
lib.set_raw_fn(
|
lib.set_raw_fn(
|
||||||
"pad",
|
"pad",
|
||||||
&[TypeId::of::<ImmutableString>(), TypeId::of::<INT>(), TypeId::of::<char>()],
|
&[TypeId::of::<ImmutableString>(), TypeId::of::<INT>(), TypeId::of::<char>()],
|
||||||
|engine: &Engine, _: &Module, args: &mut [&mut Dynamic]| {
|
|_engine: &Engine, _: &Module, args: &mut [&mut Dynamic]| {
|
||||||
let len = *args[1].downcast_ref::< INT>().unwrap();
|
let len = *args[1].downcast_ref::< INT>().unwrap();
|
||||||
|
|
||||||
// Check if string will be over max size limit
|
// Check if string will be over max size limit
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if engine.max_string_size > 0 && len > 0 && (len as usize) > engine.max_string_size {
|
if _engine.limits.max_string_size > 0 && len > 0 && (len as usize) > _engine.limits.max_string_size {
|
||||||
return Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
return Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
||||||
"Length of string".to_string(),
|
"Length of string".to_string(),
|
||||||
engine.max_string_size,
|
_engine.limits.max_string_size,
|
||||||
len as usize,
|
len as usize,
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
)));
|
||||||
@ -253,10 +254,11 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str
|
|||||||
p.push(ch);
|
p.push(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
if engine.max_string_size > 0 && s.len() > engine.max_string_size {
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
if _engine.limits.max_string_size > 0 && s.len() > _engine.limits.max_string_size {
|
||||||
return Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
return Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
||||||
"Length of string".to_string(),
|
"Length of string".to_string(),
|
||||||
engine.max_string_size,
|
_engine.limits.max_string_size,
|
||||||
s.len(),
|
s.len(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
)));
|
||||||
|
@ -1,11 +1,21 @@
|
|||||||
#![cfg(not(feature = "no_std"))]
|
#![cfg(not(feature = "no_std"))]
|
||||||
use super::logic::{eq, gt, gte, lt, lte, ne};
|
use super::logic::{eq, gt, gte, lt, lte, ne};
|
||||||
|
|
||||||
|
#[cfg(feature = "no_float")]
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
use super::math_basic::MAX_INT;
|
use super::math_basic::MAX_INT;
|
||||||
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::module::FuncReturn;
|
|
||||||
use crate::parser::INT;
|
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
use crate::parser::FLOAT;
|
||||||
|
|
||||||
|
#[cfg(feature = "no_float")]
|
||||||
|
use crate::parser::INT;
|
||||||
|
|
||||||
|
#[cfg(feature = "no_float")]
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
@ -14,9 +24,6 @@ use crate::stdlib::time::Instant;
|
|||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use instant::Instant;
|
use instant::Instant;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
use crate::parser::FLOAT;
|
|
||||||
|
|
||||||
def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, {
|
def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, {
|
||||||
// Register date/time functions
|
// Register date/time functions
|
||||||
lib.set_fn_0("timestamp", || Ok(Instant::now()));
|
lib.set_fn_0("timestamp", || Ok(Instant::now()));
|
||||||
|
127
src/parser.rs
127
src/parser.rs
@ -2,10 +2,7 @@
|
|||||||
|
|
||||||
use crate::any::{Dynamic, Union};
|
use crate::any::{Dynamic, Union};
|
||||||
use crate::calc_fn_hash;
|
use crate::calc_fn_hash;
|
||||||
use crate::engine::{
|
use crate::engine::{Engine, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
|
||||||
make_getter, make_setter, Engine, FN_ANONYMOUS, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR,
|
|
||||||
MARKER_IDENT,
|
|
||||||
};
|
|
||||||
use crate::error::{LexError, ParseError, ParseErrorType};
|
use crate::error::{LexError, ParseError, ParseErrorType};
|
||||||
use crate::fn_native::Shared;
|
use crate::fn_native::Shared;
|
||||||
use crate::module::{Module, ModuleRef};
|
use crate::module::{Module, ModuleRef};
|
||||||
@ -15,6 +12,12 @@ use crate::syntax::FnCustomSyntaxEval;
|
|||||||
use crate::token::{is_valid_identifier, Position, Token, TokenStream};
|
use crate::token::{is_valid_identifier, Position, Token, TokenStream};
|
||||||
use crate::utils::{StaticVec, StraightHasherBuilder};
|
use crate::utils::{StaticVec, StraightHasherBuilder};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
use crate::engine::FN_ANONYMOUS;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
use crate::engine::{make_getter, make_setter};
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
@ -32,9 +35,11 @@ use crate::stdlib::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::stdlib::collections::hash_map::DefaultHasher;
|
use crate::stdlib::collections::hash_map::DefaultHasher;
|
||||||
|
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
use ahash::AHasher;
|
use ahash::AHasher;
|
||||||
|
|
||||||
/// The system integer type.
|
/// The system integer type.
|
||||||
@ -84,7 +89,7 @@ impl AST {
|
|||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the statements.
|
/// [INTERNALS] Get the statements.
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[deprecated(note = "this method is volatile and may change")]
|
#[deprecated(note = "this method is volatile and may change")]
|
||||||
pub fn statements(&self) -> &[Stmt] {
|
pub fn statements(&self) -> &[Stmt] {
|
||||||
@ -102,7 +107,7 @@ impl AST {
|
|||||||
&self.1
|
&self.1
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the internal `Module` containing all script-defined functions.
|
/// [INTERNALS] Get the internal `Module` containing all script-defined functions.
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[deprecated(note = "this method is volatile and may change")]
|
#[deprecated(note = "this method is volatile and may change")]
|
||||||
pub fn lib(&self) -> &Module {
|
pub fn lib(&self) -> &Module {
|
||||||
@ -404,20 +409,28 @@ struct ParseState<'e> {
|
|||||||
/// Encapsulates a local stack with variable names to simulate an actual runtime scope.
|
/// Encapsulates a local stack with variable names to simulate an actual runtime scope.
|
||||||
modules: Vec<String>,
|
modules: Vec<String>,
|
||||||
/// Maximum levels of expression nesting.
|
/// Maximum levels of expression nesting.
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
max_expr_depth: usize,
|
max_expr_depth: usize,
|
||||||
/// Maximum levels of expression nesting in functions.
|
/// Maximum levels of expression nesting in functions.
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
max_function_expr_depth: usize,
|
max_function_expr_depth: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'e> ParseState<'e> {
|
impl<'e> ParseState<'e> {
|
||||||
/// Create a new `ParseState`.
|
/// Create a new `ParseState`.
|
||||||
pub fn new(engine: &'e Engine, max_expr_depth: usize, max_function_expr_depth: usize) -> Self {
|
pub fn new(
|
||||||
|
engine: &'e Engine,
|
||||||
|
#[cfg(not(feature = "unchecked"))] max_expr_depth: usize,
|
||||||
|
#[cfg(not(feature = "unchecked"))] max_function_expr_depth: usize,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine,
|
engine,
|
||||||
max_expr_depth,
|
|
||||||
max_function_expr_depth,
|
|
||||||
stack: Default::default(),
|
stack: Default::default(),
|
||||||
modules: Default::default(),
|
modules: Default::default(),
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
max_expr_depth,
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
max_function_expr_depth,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Find a variable by name in the `ParseState`, searching in reverse.
|
/// Find a variable by name in the `ParseState`, searching in reverse.
|
||||||
@ -476,6 +489,7 @@ impl ParseSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Make sure that the current level of expression nesting is within the maximum limit.
|
/// Make sure that the current level of expression nesting is within the maximum limit.
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub fn ensure_level_within_max_limit(&self, limit: usize) -> Result<(), ParseError> {
|
pub fn ensure_level_within_max_limit(&self, limit: usize) -> Result<(), ParseError> {
|
||||||
if limit == 0 {
|
if limit == 0 {
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -519,8 +533,10 @@ pub enum Stmt {
|
|||||||
/// return/throw
|
/// return/throw
|
||||||
ReturnWithVal(Box<((ReturnType, Position), Option<Expr>)>),
|
ReturnWithVal(Box<((ReturnType, Position), Option<Expr>)>),
|
||||||
/// import expr as module
|
/// import expr as module
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Import(Box<(Expr, (String, Position))>),
|
Import(Box<(Expr, (String, Position))>),
|
||||||
/// expr id as name, ...
|
/// expr id as name, ...
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Export(Box<StaticVec<((String, Position), Option<(String, Position)>)>>),
|
Export(Box<StaticVec<((String, Position), Option<(String, Position)>)>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,7 +560,10 @@ impl Stmt {
|
|||||||
Stmt::While(x) => x.1.position(),
|
Stmt::While(x) => x.1.position(),
|
||||||
Stmt::Loop(x) => x.position(),
|
Stmt::Loop(x) => x.position(),
|
||||||
Stmt::For(x) => x.2.position(),
|
Stmt::For(x) => x.2.position(),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Stmt::Import(x) => (x.1).1,
|
Stmt::Import(x) => (x.1).1,
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Stmt::Export(x) => (x.get(0).0).1,
|
Stmt::Export(x) => (x.get(0).0).1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -563,12 +582,13 @@ impl Stmt {
|
|||||||
|
|
||||||
Stmt::Let(_)
|
Stmt::Let(_)
|
||||||
| Stmt::Const(_)
|
| Stmt::Const(_)
|
||||||
| Stmt::Import(_)
|
|
||||||
| Stmt::Export(_)
|
|
||||||
| Stmt::Expr(_)
|
| Stmt::Expr(_)
|
||||||
| Stmt::Continue(_)
|
| Stmt::Continue(_)
|
||||||
| Stmt::Break(_)
|
| Stmt::Break(_)
|
||||||
| Stmt::ReturnWithVal(_) => false,
|
| Stmt::ReturnWithVal(_) => false,
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
Stmt::Import(_) | Stmt::Export(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,7 +607,10 @@ impl Stmt {
|
|||||||
Stmt::Let(_) | Stmt::Const(_) => false,
|
Stmt::Let(_) | Stmt::Const(_) => false,
|
||||||
Stmt::Block(x) => x.0.iter().all(Stmt::is_pure),
|
Stmt::Block(x) => x.0.iter().all(Stmt::is_pure),
|
||||||
Stmt::Continue(_) | Stmt::Break(_) | Stmt::ReturnWithVal(_) => false,
|
Stmt::Continue(_) | Stmt::Break(_) | Stmt::ReturnWithVal(_) => false,
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Stmt::Import(_) => false,
|
Stmt::Import(_) => false,
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Stmt::Export(_) => false,
|
Stmt::Export(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -950,6 +973,7 @@ impl Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a `Variable` into a `Property`. All other variants are untouched.
|
/// Convert a `Variable` into a `Property`. All other variants are untouched.
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub(crate) fn into_property(self) -> Self {
|
pub(crate) fn into_property(self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Variable(x) if x.1.is_none() => {
|
Self::Variable(x) if x.1.is_none() => {
|
||||||
@ -996,6 +1020,7 @@ fn parse_paren_expr(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
if match_token(input, Token::RightParen)? {
|
if match_token(input, Token::RightParen)? {
|
||||||
@ -1028,6 +1053,8 @@ fn parse_call_expr(
|
|||||||
settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
let (token, token_pos) = input.peek().unwrap();
|
let (token, token_pos) = input.peek().unwrap();
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
let mut args = StaticVec::new();
|
let mut args = StaticVec::new();
|
||||||
@ -1141,6 +1168,7 @@ fn parse_call_expr(
|
|||||||
|
|
||||||
/// Parse an indexing chain.
|
/// Parse an indexing chain.
|
||||||
/// Indexing binds to the right, so this call parses all possible levels of indexing following in the input.
|
/// Indexing binds to the right, so this call parses all possible levels of indexing following in the input.
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
fn parse_index_chain(
|
fn parse_index_chain(
|
||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
@ -1148,6 +1176,7 @@ fn parse_index_chain(
|
|||||||
lhs: Expr,
|
lhs: Expr,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
let idx_expr = parse_expr(input, state, lib, settings.level_up())?;
|
let idx_expr = parse_expr(input, state, lib, settings.level_up())?;
|
||||||
@ -1321,21 +1350,25 @@ fn parse_index_chain(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parse an array literal.
|
/// Parse an array literal.
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
fn parse_array_literal(
|
fn parse_array_literal(
|
||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
let mut arr = StaticVec::new();
|
let mut arr = StaticVec::new();
|
||||||
|
|
||||||
while !input.peek().unwrap().0.is_eof() {
|
while !input.peek().unwrap().0.is_eof() {
|
||||||
if state.engine.max_array_size > 0 && arr.len() >= state.engine.max_array_size {
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
if state.engine.limits.max_array_size > 0 && arr.len() >= state.engine.limits.max_array_size
|
||||||
|
{
|
||||||
return Err(PERR::LiteralTooLarge(
|
return Err(PERR::LiteralTooLarge(
|
||||||
"Size of array literal".to_string(),
|
"Size of array literal".to_string(),
|
||||||
state.engine.max_array_size,
|
state.engine.limits.max_array_size,
|
||||||
)
|
)
|
||||||
.into_err(input.peek().unwrap().1));
|
.into_err(input.peek().unwrap().1));
|
||||||
}
|
}
|
||||||
@ -1378,12 +1411,14 @@ fn parse_array_literal(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a map literal.
|
/// Parse a map literal.
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
fn parse_map_literal(
|
fn parse_map_literal(
|
||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
let mut map = StaticVec::new();
|
let mut map = StaticVec::new();
|
||||||
@ -1436,10 +1471,11 @@ fn parse_map_literal(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if state.engine.max_map_size > 0 && map.len() >= state.engine.max_map_size {
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
if state.engine.limits.max_map_size > 0 && map.len() >= state.engine.limits.max_map_size {
|
||||||
return Err(PERR::LiteralTooLarge(
|
return Err(PERR::LiteralTooLarge(
|
||||||
"Number of properties in object map literal".to_string(),
|
"Number of properties in object map literal".to_string(),
|
||||||
state.engine.max_map_size,
|
state.engine.limits.max_map_size,
|
||||||
)
|
)
|
||||||
.into_err(input.peek().unwrap().1));
|
.into_err(input.peek().unwrap().1));
|
||||||
}
|
}
|
||||||
@ -1492,6 +1528,8 @@ fn parse_primary(
|
|||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
let (token, token_pos) = input.peek().unwrap();
|
let (token, token_pos) = input.peek().unwrap();
|
||||||
settings.pos = *token_pos;
|
settings.pos = *token_pos;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
let (token, _) = match token {
|
let (token, _) = match token {
|
||||||
@ -1626,6 +1664,8 @@ fn parse_unary(
|
|||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
let (token, token_pos) = input.peek().unwrap();
|
let (token, token_pos) = input.peek().unwrap();
|
||||||
settings.pos = *token_pos;
|
settings.pos = *token_pos;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
match token {
|
match token {
|
||||||
@ -1708,7 +1748,9 @@ fn parse_unary(
|
|||||||
Token::Pipe | Token::Or => {
|
Token::Pipe | Token::Or => {
|
||||||
let mut state = ParseState::new(
|
let mut state = ParseState::new(
|
||||||
state.engine,
|
state.engine,
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
state.max_function_expr_depth,
|
state.max_function_expr_depth,
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
state.max_function_expr_depth,
|
state.max_function_expr_depth,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1809,6 +1851,8 @@ fn parse_op_assignment_stmt(
|
|||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
let (token, token_pos) = input.peek().unwrap();
|
let (token, token_pos) = input.peek().unwrap();
|
||||||
settings.pos = *token_pos;
|
settings.pos = *token_pos;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
let op = match token {
|
let op = match token {
|
||||||
@ -1835,6 +1879,7 @@ fn parse_op_assignment_stmt(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Make a dot expression.
|
/// Make a dot expression.
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
fn make_dot_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseError> {
|
fn make_dot_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseError> {
|
||||||
Ok(match (lhs, rhs) {
|
Ok(match (lhs, rhs) {
|
||||||
// idx_lhs[idx_expr].rhs
|
// idx_lhs[idx_expr].rhs
|
||||||
@ -2048,6 +2093,8 @@ fn parse_binary_op(
|
|||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
settings.pos = lhs.position();
|
settings.pos = lhs.position();
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
let mut root = lhs;
|
let mut root = lhs;
|
||||||
@ -2081,6 +2128,8 @@ fn parse_binary_op(
|
|||||||
|
|
||||||
settings = settings.level_up();
|
settings = settings.level_up();
|
||||||
settings.pos = pos;
|
settings.pos = pos;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
let cmp_def = Some(false);
|
let cmp_def = Some(false);
|
||||||
@ -2164,6 +2213,8 @@ fn parse_expr(
|
|||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
settings.pos = input.peek().unwrap().1;
|
settings.pos = input.peek().unwrap().1;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
// Check if it is a custom syntax.
|
// Check if it is a custom syntax.
|
||||||
@ -2291,6 +2342,8 @@ fn parse_if(
|
|||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// if ...
|
// if ...
|
||||||
settings.pos = eat_token(input, Token::If);
|
settings.pos = eat_token(input, Token::If);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
// if guard { if_body }
|
// if guard { if_body }
|
||||||
@ -2324,6 +2377,8 @@ fn parse_while(
|
|||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// while ...
|
// while ...
|
||||||
settings.pos = eat_token(input, Token::While);
|
settings.pos = eat_token(input, Token::While);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
// while guard { body }
|
// while guard { body }
|
||||||
@ -2346,6 +2401,8 @@ fn parse_loop(
|
|||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// loop ...
|
// loop ...
|
||||||
settings.pos = eat_token(input, Token::Loop);
|
settings.pos = eat_token(input, Token::Loop);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
// loop { body }
|
// loop { body }
|
||||||
@ -2364,6 +2421,8 @@ fn parse_for(
|
|||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// for ...
|
// for ...
|
||||||
settings.pos = eat_token(input, Token::For);
|
settings.pos = eat_token(input, Token::For);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
// for name ...
|
// for name ...
|
||||||
@ -2417,6 +2476,8 @@ fn parse_let(
|
|||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// let/const... (specified in `var_type`)
|
// let/const... (specified in `var_type`)
|
||||||
settings.pos = input.next().unwrap().1;
|
settings.pos = input.next().unwrap().1;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
// let name ...
|
// let name ...
|
||||||
@ -2475,6 +2536,8 @@ fn parse_import(
|
|||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// import ...
|
// import ...
|
||||||
settings.pos = eat_token(input, Token::Import);
|
settings.pos = eat_token(input, Token::Import);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
// import expr ...
|
// import expr ...
|
||||||
@ -2509,12 +2572,14 @@ fn parse_import(
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
fn parse_export(
|
fn parse_export(
|
||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
_state: &mut ParseState,
|
||||||
_lib: &mut FunctionsLib,
|
_lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
settings.pos = eat_token(input, Token::Export);
|
settings.pos = eat_token(input, Token::Export);
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
settings.ensure_level_within_max_limit(_state.max_expr_depth)?;
|
||||||
|
|
||||||
let mut exports = StaticVec::new();
|
let mut exports = StaticVec::new();
|
||||||
|
|
||||||
@ -2594,6 +2659,7 @@ fn parse_block(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
let mut statements = StaticVec::new();
|
let mut statements = StaticVec::new();
|
||||||
@ -2657,6 +2723,8 @@ fn parse_expr_stmt(
|
|||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
settings.pos = input.peek().unwrap().1;
|
settings.pos = input.peek().unwrap().1;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
let expr = parse_expr(input, state, lib, settings.level_up())?;
|
let expr = parse_expr(input, state, lib, settings.level_up())?;
|
||||||
@ -2678,6 +2746,8 @@ fn parse_stmt(
|
|||||||
x => x,
|
x => x,
|
||||||
};
|
};
|
||||||
settings.pos = *token_pos;
|
settings.pos = *token_pos;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
match token {
|
match token {
|
||||||
@ -2703,7 +2773,9 @@ fn parse_stmt(
|
|||||||
(Token::Fn, pos) => {
|
(Token::Fn, pos) => {
|
||||||
let mut state = ParseState::new(
|
let mut state = ParseState::new(
|
||||||
state.engine,
|
state.engine,
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
state.max_function_expr_depth,
|
state.max_function_expr_depth,
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
state.max_function_expr_depth,
|
state.max_function_expr_depth,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2807,6 +2879,7 @@ fn parse_fn(
|
|||||||
access: FnAccess,
|
access: FnAccess,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<ScriptFnDef, ParseError> {
|
) -> Result<ScriptFnDef, ParseError> {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
let name = match input.next().unwrap() {
|
let name = match input.next().unwrap() {
|
||||||
@ -2899,6 +2972,7 @@ fn parse_anon_fn(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<(Expr, ScriptFnDef), ParseError> {
|
) -> Result<(Expr, ScriptFnDef), ParseError> {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
let mut params = Vec::new();
|
let mut params = Vec::new();
|
||||||
@ -2994,7 +3068,15 @@ impl Engine {
|
|||||||
optimization_level: OptimizationLevel,
|
optimization_level: OptimizationLevel,
|
||||||
) -> Result<AST, ParseError> {
|
) -> Result<AST, ParseError> {
|
||||||
let mut functions = Default::default();
|
let mut functions = Default::default();
|
||||||
let mut state = ParseState::new(self, self.max_expr_depth, self.max_function_expr_depth);
|
|
||||||
|
let mut state = ParseState::new(
|
||||||
|
self,
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
self.limits.max_expr_depth,
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
self.limits.max_function_expr_depth,
|
||||||
|
);
|
||||||
|
|
||||||
let settings = ParseSettings {
|
let settings = ParseSettings {
|
||||||
allow_if_expr: false,
|
allow_if_expr: false,
|
||||||
allow_stmt_expr: false,
|
allow_stmt_expr: false,
|
||||||
@ -3032,7 +3114,14 @@ impl Engine {
|
|||||||
) -> Result<(Vec<Stmt>, Vec<ScriptFnDef>), ParseError> {
|
) -> Result<(Vec<Stmt>, Vec<ScriptFnDef>), ParseError> {
|
||||||
let mut statements: Vec<Stmt> = Default::default();
|
let mut statements: Vec<Stmt> = Default::default();
|
||||||
let mut functions = Default::default();
|
let mut functions = Default::default();
|
||||||
let mut state = ParseState::new(self, self.max_expr_depth, self.max_function_expr_depth);
|
|
||||||
|
let mut state = ParseState::new(
|
||||||
|
self,
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
self.limits.max_expr_depth,
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
self.limits.max_function_expr_depth,
|
||||||
|
);
|
||||||
|
|
||||||
while !input.peek().unwrap().0.is_eof() {
|
while !input.peek().unwrap().0.is_eof() {
|
||||||
let settings = ParseSettings {
|
let settings = ParseSettings {
|
||||||
|
@ -34,10 +34,10 @@ pub enum EvalAltResult {
|
|||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
ErrorReadingScriptFile(PathBuf, Position, std::io::Error),
|
ErrorReadingScriptFile(PathBuf, Position, std::io::Error),
|
||||||
|
|
||||||
/// Call to an unknown function. Wrapped value is the name of the function.
|
/// Call to an unknown function. Wrapped value is the signature of the function.
|
||||||
ErrorFunctionNotFound(String, Position),
|
ErrorFunctionNotFound(String, Position),
|
||||||
/// An error has occurred inside a called function.
|
/// An error has occurred inside a called function.
|
||||||
/// Wrapped values re the name of the function and the interior error.
|
/// Wrapped values are the name of the function and the interior error.
|
||||||
ErrorInFunctionCall(String, Box<EvalAltResult>, Position),
|
ErrorInFunctionCall(String, Box<EvalAltResult>, Position),
|
||||||
/// Access to `this` that is not bounded.
|
/// Access to `this` that is not bounded.
|
||||||
ErrorUnboundedThis(Position),
|
ErrorUnboundedThis(Position),
|
||||||
|
@ -377,6 +377,7 @@ impl<'a> Scope<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Update the access type of an entry in the Scope.
|
/// Update the access type of an entry in the Scope.
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub(crate) fn set_entry_alias(&mut self, index: usize, alias: String) -> &mut Self {
|
pub(crate) fn set_entry_alias(&mut self, index: usize, alias: String) -> &mut Self {
|
||||||
let entry = self.0.get_mut(index).expect("invalid index in Scope");
|
let entry = self.0.get_mut(index).expect("invalid index in Scope");
|
||||||
entry.alias = Some(Box::new(alias));
|
entry.alias = Some(Box::new(alias));
|
||||||
@ -384,6 +385,7 @@ impl<'a> Scope<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get an iterator to entries in the Scope.
|
/// Get an iterator to entries in the Scope.
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub(crate) fn into_iter(self) -> impl Iterator<Item = Entry<'a>> {
|
pub(crate) fn into_iter(self) -> impl Iterator<Item = Entry<'a>> {
|
||||||
self.0.into_iter()
|
self.0.into_iter()
|
||||||
}
|
}
|
||||||
|
@ -8,17 +8,20 @@ use crate::token::Position;
|
|||||||
use crate::utils::ImmutableString;
|
use crate::utils::ImmutableString;
|
||||||
|
|
||||||
use serde::de::{
|
use serde::de::{
|
||||||
DeserializeSeed, Deserializer, EnumAccess, Error, IntoDeserializer, MapAccess, SeqAccess,
|
DeserializeSeed, Deserializer, Error, IntoDeserializer, MapAccess, SeqAccess, Visitor,
|
||||||
VariantAccess, Visitor,
|
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
use crate::engine::Array;
|
use crate::engine::Array;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
use crate::engine::Map;
|
use crate::engine::Map;
|
||||||
|
|
||||||
use crate::stdlib::{any::type_name, fmt};
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
use serde::de::{EnumAccess, VariantAccess};
|
||||||
|
|
||||||
|
use crate::stdlib::{any::type_name, boxed::Box, fmt, string::ToString};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
@ -46,8 +49,12 @@ impl<'de> DynamicDeserializer<'de> {
|
|||||||
}
|
}
|
||||||
/// Shortcut for a type conversion error.
|
/// Shortcut for a type conversion error.
|
||||||
fn type_error<T>(&self) -> Result<T, Box<EvalAltResult>> {
|
fn type_error<T>(&self) -> Result<T, Box<EvalAltResult>> {
|
||||||
|
self.type_error_str(type_name::<T>())
|
||||||
|
}
|
||||||
|
/// Shortcut for a type conversion error.
|
||||||
|
fn type_error_str<T>(&self, error: &str) -> Result<T, Box<EvalAltResult>> {
|
||||||
Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
type_name::<T>().into(),
|
error.into(),
|
||||||
self.value.type_name().into(),
|
self.value.type_name().into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)))
|
||||||
@ -283,23 +290,23 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_f32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_f32<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
return self
|
return self
|
||||||
.value
|
.value
|
||||||
.downcast_ref::<f32>()
|
.downcast_ref::<f32>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_f32(x));
|
.map_or_else(|| self.type_error(), |&x| _visitor.visit_f32(x));
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
#[cfg(feature = "no_float")]
|
||||||
return self.type_error_str("f32");
|
return self.type_error_str("f32");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_f64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_f64<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
return self
|
return self
|
||||||
.value
|
.value
|
||||||
.downcast_ref::<f64>()
|
.downcast_ref::<f64>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_f64(x));
|
.map_or_else(|| self.type_error(), |&x| _visitor.visit_f64(x));
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
#[cfg(feature = "no_float")]
|
||||||
return self.type_error_str("f64");
|
return self.type_error_str("f64");
|
||||||
@ -359,11 +366,11 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
visitor.visit_newtype_struct(self)
|
visitor.visit_newtype_struct(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_seq<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_seq<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
return self.value.downcast_ref::<Array>().map_or_else(
|
return self.value.downcast_ref::<Array>().map_or_else(
|
||||||
|| self.type_error(),
|
|| self.type_error(),
|
||||||
|arr| visitor.visit_seq(IterateArray::new(arr.iter())),
|
|arr| _visitor.visit_seq(IterateArray::new(arr.iter())),
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
@ -387,11 +394,11 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
self.deserialize_seq(visitor)
|
self.deserialize_seq(visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_map<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_map<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
return self.value.downcast_ref::<Map>().map_or_else(
|
return self.value.downcast_ref::<Map>().map_or_else(
|
||||||
|| self.type_error(),
|
|| self.type_error(),
|
||||||
|map| visitor.visit_map(IterateMap::new(map.keys(), map.values())),
|
|map| _visitor.visit_map(IterateMap::new(map.keys(), map.values())),
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
@ -461,6 +468,7 @@ where
|
|||||||
iter: ITER,
|
iter: ITER,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
impl<'a, ITER> IterateArray<'a, ITER>
|
impl<'a, ITER> IterateArray<'a, ITER>
|
||||||
where
|
where
|
||||||
ITER: Iterator<Item = &'a Dynamic>,
|
ITER: Iterator<Item = &'a Dynamic>,
|
||||||
@ -502,6 +510,7 @@ where
|
|||||||
values: VALUES,
|
values: VALUES,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
impl<'a, KEYS, VALUES> IterateMap<'a, KEYS, VALUES>
|
impl<'a, KEYS, VALUES> IterateMap<'a, KEYS, VALUES>
|
||||||
where
|
where
|
||||||
KEYS: Iterator<Item = &'a ImmutableString>,
|
KEYS: Iterator<Item = &'a ImmutableString>,
|
||||||
|
121
src/serde/ser.rs
121
src/serde/ser.rs
@ -10,27 +10,36 @@ use crate::engine::Array;
|
|||||||
use crate::engine::Map;
|
use crate::engine::Map;
|
||||||
|
|
||||||
use serde::ser::{
|
use serde::ser::{
|
||||||
Error, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
|
Error, SerializeMap, SerializeSeq, SerializeStruct, SerializeTuple, SerializeTupleStruct,
|
||||||
SerializeTupleStruct, SerializeTupleVariant, Serializer,
|
Serializer,
|
||||||
};
|
};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::stdlib::{any::type_name, fmt, mem};
|
#[cfg(not(any(feature = "no_object", feature = "no_index")))]
|
||||||
|
use serde::ser::SerializeTupleVariant;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
use serde::ser::SerializeStructVariant;
|
||||||
|
|
||||||
|
use crate::stdlib::{boxed::Box, fmt, string::ToString};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
use crate::stdlib::mem;
|
||||||
|
|
||||||
/// Serializer for `Dynamic` which is kept as a reference.
|
/// Serializer for `Dynamic` which is kept as a reference.
|
||||||
pub struct DynamicSerializer {
|
pub struct DynamicSerializer {
|
||||||
/// Buffer to hold a temporary key.
|
/// Buffer to hold a temporary key.
|
||||||
key: Dynamic,
|
_key: Dynamic,
|
||||||
/// Buffer to hold a temporary value.
|
/// Buffer to hold a temporary value.
|
||||||
value: Dynamic,
|
_value: Dynamic,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DynamicSerializer {
|
impl DynamicSerializer {
|
||||||
/// Create a `DynamicSerializer` from a `Dynamic` value.
|
/// Create a `DynamicSerializer` from a `Dynamic` value.
|
||||||
pub fn new(value: Dynamic) -> Self {
|
pub fn new(_value: Dynamic) -> Self {
|
||||||
Self {
|
Self {
|
||||||
key: Default::default(),
|
_key: Default::default(),
|
||||||
value,
|
_value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -280,13 +289,13 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
self,
|
self,
|
||||||
_name: &'static str,
|
_name: &'static str,
|
||||||
_variant_index: u32,
|
_variant_index: u32,
|
||||||
variant: &'static str,
|
_variant: &'static str,
|
||||||
value: &T,
|
_value: &T,
|
||||||
) -> Result<Self::Ok, Box<EvalAltResult>> {
|
) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
{
|
{
|
||||||
let content = to_dynamic(value)?;
|
let content = to_dynamic(_value)?;
|
||||||
make_variant(variant, content)
|
make_variant(_variant, content)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
return Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
return Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
@ -323,13 +332,13 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
self,
|
self,
|
||||||
_name: &'static str,
|
_name: &'static str,
|
||||||
_variant_index: u32,
|
_variant_index: u32,
|
||||||
variant: &'static str,
|
_variant: &'static str,
|
||||||
len: usize,
|
_len: usize,
|
||||||
) -> Result<Self::SerializeTupleVariant, Box<EvalAltResult>> {
|
) -> Result<Self::SerializeTupleVariant, Box<EvalAltResult>> {
|
||||||
#[cfg(not(any(feature = "no_object", feature = "no_index")))]
|
#[cfg(not(any(feature = "no_object", feature = "no_index")))]
|
||||||
return Ok(TupleVariantSerializer {
|
return Ok(TupleVariantSerializer {
|
||||||
variant,
|
variant: _variant,
|
||||||
array: Array::with_capacity(len),
|
array: Array::with_capacity(_len),
|
||||||
});
|
});
|
||||||
#[cfg(any(feature = "no_object", feature = "no_index"))]
|
#[cfg(any(feature = "no_object", feature = "no_index"))]
|
||||||
{
|
{
|
||||||
@ -368,13 +377,13 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
self,
|
self,
|
||||||
_name: &'static str,
|
_name: &'static str,
|
||||||
_variant_index: u32,
|
_variant_index: u32,
|
||||||
variant: &'static str,
|
_variant: &'static str,
|
||||||
len: usize,
|
_len: usize,
|
||||||
) -> Result<Self::SerializeStructVariant, Box<EvalAltResult>> {
|
) -> Result<Self::SerializeStructVariant, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
return Ok(StructVariantSerializer {
|
return Ok(StructVariantSerializer {
|
||||||
variant,
|
variant: _variant,
|
||||||
map: Map::with_capacity(len),
|
map: Map::with_capacity(_len),
|
||||||
});
|
});
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
return Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
return Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
@ -391,13 +400,13 @@ impl SerializeSeq for DynamicSerializer {
|
|||||||
|
|
||||||
fn serialize_element<T: ?Sized + Serialize>(
|
fn serialize_element<T: ?Sized + Serialize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
value: &T,
|
_value: &T,
|
||||||
) -> Result<(), Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
let value = value.serialize(&mut *self)?;
|
let _value = _value.serialize(&mut *self)?;
|
||||||
let arr = self.value.downcast_mut::<Array>().unwrap();
|
let arr = self._value.downcast_mut::<Array>().unwrap();
|
||||||
arr.push(value);
|
arr.push(_value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
@ -407,7 +416,7 @@ impl SerializeSeq for DynamicSerializer {
|
|||||||
// Close the sequence.
|
// Close the sequence.
|
||||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
return Ok(self.value);
|
return Ok(self._value);
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
@ -419,13 +428,13 @@ impl SerializeTuple for DynamicSerializer {
|
|||||||
|
|
||||||
fn serialize_element<T: ?Sized + Serialize>(
|
fn serialize_element<T: ?Sized + Serialize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
value: &T,
|
_value: &T,
|
||||||
) -> Result<(), Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
let value = value.serialize(&mut *self)?;
|
let _value = _value.serialize(&mut *self)?;
|
||||||
let arr = self.value.downcast_mut::<Array>().unwrap();
|
let arr = self._value.downcast_mut::<Array>().unwrap();
|
||||||
arr.push(value);
|
arr.push(_value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
@ -434,7 +443,7 @@ impl SerializeTuple for DynamicSerializer {
|
|||||||
|
|
||||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
return Ok(self.value);
|
return Ok(self._value);
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
@ -446,13 +455,13 @@ impl SerializeTupleStruct for DynamicSerializer {
|
|||||||
|
|
||||||
fn serialize_field<T: ?Sized + Serialize>(
|
fn serialize_field<T: ?Sized + Serialize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
value: &T,
|
_value: &T,
|
||||||
) -> Result<(), Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
let value = value.serialize(&mut *self)?;
|
let _value = _value.serialize(&mut *self)?;
|
||||||
let arr = self.value.downcast_mut::<Array>().unwrap();
|
let arr = self._value.downcast_mut::<Array>().unwrap();
|
||||||
arr.push(value);
|
arr.push(_value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
@ -461,7 +470,7 @@ impl SerializeTupleStruct for DynamicSerializer {
|
|||||||
|
|
||||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
return Ok(self.value);
|
return Ok(self._value);
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
@ -471,10 +480,10 @@ impl SerializeMap for DynamicSerializer {
|
|||||||
type Ok = Dynamic;
|
type Ok = Dynamic;
|
||||||
type Error = Box<EvalAltResult>;
|
type Error = Box<EvalAltResult>;
|
||||||
|
|
||||||
fn serialize_key<T: ?Sized + Serialize>(&mut self, key: &T) -> Result<(), Box<EvalAltResult>> {
|
fn serialize_key<T: ?Sized + Serialize>(&mut self, _key: &T) -> Result<(), Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
{
|
{
|
||||||
self.key = key.serialize(&mut *self)?;
|
self._key = _key.serialize(&mut *self)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
@ -483,11 +492,11 @@ impl SerializeMap for DynamicSerializer {
|
|||||||
|
|
||||||
fn serialize_value<T: ?Sized + Serialize>(
|
fn serialize_value<T: ?Sized + Serialize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
value: &T,
|
_value: &T,
|
||||||
) -> Result<(), Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
{
|
{
|
||||||
let key = mem::take(&mut self.key)
|
let key = mem::take(&mut self._key)
|
||||||
.take_immutable_string()
|
.take_immutable_string()
|
||||||
.map_err(|typ| {
|
.map_err(|typ| {
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
@ -496,9 +505,9 @@ impl SerializeMap for DynamicSerializer {
|
|||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
let value = value.serialize(&mut *self)?;
|
let _value = _value.serialize(&mut *self)?;
|
||||||
let map = self.value.downcast_mut::<Map>().unwrap();
|
let map = self._value.downcast_mut::<Map>().unwrap();
|
||||||
map.insert(key, value);
|
map.insert(key, _value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
@ -507,22 +516,22 @@ impl SerializeMap for DynamicSerializer {
|
|||||||
|
|
||||||
fn serialize_entry<K: ?Sized + Serialize, T: ?Sized + Serialize>(
|
fn serialize_entry<K: ?Sized + Serialize, T: ?Sized + Serialize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
key: &K,
|
_key: &K,
|
||||||
value: &T,
|
_value: &T,
|
||||||
) -> Result<(), Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
{
|
{
|
||||||
let key: Dynamic = key.serialize(&mut *self)?;
|
let _key: Dynamic = _key.serialize(&mut *self)?;
|
||||||
let key = key.take_immutable_string().map_err(|typ| {
|
let _key = _key.take_immutable_string().map_err(|typ| {
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
"string".into(),
|
"string".into(),
|
||||||
typ.into(),
|
typ.into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
let value = value.serialize(&mut *self)?;
|
let _value = _value.serialize(&mut *self)?;
|
||||||
let map = self.value.downcast_mut::<Map>().unwrap();
|
let map = self._value.downcast_mut::<Map>().unwrap();
|
||||||
map.insert(key, value);
|
map.insert(_key, _value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
@ -531,7 +540,7 @@ impl SerializeMap for DynamicSerializer {
|
|||||||
|
|
||||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
return Ok(self.value);
|
return Ok(self._value);
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
@ -543,14 +552,14 @@ impl SerializeStruct for DynamicSerializer {
|
|||||||
|
|
||||||
fn serialize_field<T: ?Sized + Serialize>(
|
fn serialize_field<T: ?Sized + Serialize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
key: &'static str,
|
_key: &'static str,
|
||||||
value: &T,
|
_value: &T,
|
||||||
) -> Result<(), Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
{
|
{
|
||||||
let value = value.serialize(&mut *self)?;
|
let _value = _value.serialize(&mut *self)?;
|
||||||
let map = self.value.downcast_mut::<Map>().unwrap();
|
let map = self._value.downcast_mut::<Map>().unwrap();
|
||||||
map.insert(key.into(), value);
|
map.insert(_key.into(), _value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
@ -559,7 +568,7 @@ impl SerializeStruct for DynamicSerializer {
|
|||||||
|
|
||||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
return Ok(self.value);
|
return Ok(self._value);
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use crate::utils::ImmutableString;
|
|||||||
|
|
||||||
use serde::de::{Deserializer, Visitor};
|
use serde::de::{Deserializer, Visitor};
|
||||||
|
|
||||||
use crate::stdlib::any::type_name;
|
use crate::stdlib::{any::type_name, boxed::Box};
|
||||||
|
|
||||||
/// Deserializer for `ImmutableString`.
|
/// Deserializer for `ImmutableString`.
|
||||||
pub struct ImmutableStringDeserializer<'a> {
|
pub struct ImmutableStringDeserializer<'a> {
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
//! Configuration settings for `Engine`.
|
//! Configuration settings for `Engine`.
|
||||||
|
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::module::ModuleResolver;
|
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::packages::PackageLibrary;
|
use crate::packages::PackageLibrary;
|
||||||
use crate::token::{is_valid_identifier, Token};
|
use crate::token::{is_valid_identifier, Token};
|
||||||
|
|
||||||
use crate::stdlib::{boxed::Box, format, string::String};
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
use crate::module::ModuleResolver;
|
||||||
|
|
||||||
|
use crate::stdlib::{format, string::String};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
use crate::stdlib::boxed::Box;
|
||||||
|
|
||||||
impl Engine {
|
impl Engine {
|
||||||
/// Load a new package into the `Engine`.
|
/// Load a new package into the `Engine`.
|
||||||
@ -41,21 +46,21 @@ impl Engine {
|
|||||||
/// infinite recursion and stack overflows.
|
/// infinite recursion and stack overflows.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub fn set_max_call_levels(&mut self, levels: usize) -> &mut Self {
|
pub fn set_max_call_levels(&mut self, levels: usize) -> &mut Self {
|
||||||
self.max_call_stack_depth = levels;
|
self.limits.max_call_stack_depth = levels;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The maximum levels of function calls allowed for a script.
|
/// The maximum levels of function calls allowed for a script.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub fn max_call_levels(&self) -> usize {
|
pub fn max_call_levels(&self) -> usize {
|
||||||
self.max_call_stack_depth
|
self.limits.max_call_stack_depth
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the maximum number of operations allowed for a script to run to avoid
|
/// Set the maximum number of operations allowed for a script to run to avoid
|
||||||
/// consuming too much resources (0 for unlimited).
|
/// consuming too much resources (0 for unlimited).
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub fn set_max_operations(&mut self, operations: u64) -> &mut Self {
|
pub fn set_max_operations(&mut self, operations: u64) -> &mut Self {
|
||||||
self.max_operations = if operations == u64::MAX {
|
self.limits.max_operations = if operations == u64::MAX {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
operations
|
operations
|
||||||
@ -66,20 +71,20 @@ impl Engine {
|
|||||||
/// The maximum number of operations allowed for a script to run (0 for unlimited).
|
/// The maximum number of operations allowed for a script to run (0 for unlimited).
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub fn max_operations(&self) -> u64 {
|
pub fn max_operations(&self) -> u64 {
|
||||||
self.max_operations
|
self.limits.max_operations
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the maximum number of imported modules allowed for a script.
|
/// Set the maximum number of imported modules allowed for a script.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub fn set_max_modules(&mut self, modules: usize) -> &mut Self {
|
pub fn set_max_modules(&mut self, modules: usize) -> &mut Self {
|
||||||
self.max_modules = modules;
|
self.limits.max_modules = modules;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The maximum number of imported modules allowed for a script.
|
/// The maximum number of imported modules allowed for a script.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub fn max_modules(&self) -> usize {
|
pub fn max_modules(&self) -> usize {
|
||||||
self.max_modules
|
self.limits.max_modules
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the depth limits for expressions (0 for unlimited).
|
/// Set the depth limits for expressions (0 for unlimited).
|
||||||
@ -89,12 +94,12 @@ impl Engine {
|
|||||||
max_expr_depth: usize,
|
max_expr_depth: usize,
|
||||||
max_function_expr_depth: usize,
|
max_function_expr_depth: usize,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.max_expr_depth = if max_expr_depth == usize::MAX {
|
self.limits.max_expr_depth = if max_expr_depth == usize::MAX {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
max_expr_depth
|
max_expr_depth
|
||||||
};
|
};
|
||||||
self.max_function_expr_depth = if max_function_expr_depth == usize::MAX {
|
self.limits.max_function_expr_depth = if max_function_expr_depth == usize::MAX {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
max_function_expr_depth
|
max_function_expr_depth
|
||||||
@ -105,33 +110,33 @@ impl Engine {
|
|||||||
/// The depth limit for expressions (0 for unlimited).
|
/// The depth limit for expressions (0 for unlimited).
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub fn max_expr_depth(&self) -> usize {
|
pub fn max_expr_depth(&self) -> usize {
|
||||||
self.max_expr_depth
|
self.limits.max_expr_depth
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The depth limit for expressions in functions (0 for unlimited).
|
/// The depth limit for expressions in functions (0 for unlimited).
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub fn max_function_expr_depth(&self) -> usize {
|
pub fn max_function_expr_depth(&self) -> usize {
|
||||||
self.max_function_expr_depth
|
self.limits.max_function_expr_depth
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the maximum length of strings (0 for unlimited).
|
/// Set the maximum length of strings (0 for unlimited).
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub fn set_max_string_size(&mut self, max_size: usize) -> &mut Self {
|
pub fn set_max_string_size(&mut self, max_size: usize) -> &mut Self {
|
||||||
self.max_string_size = if max_size == usize::MAX { 0 } else { max_size };
|
self.limits.max_string_size = if max_size == usize::MAX { 0 } else { max_size };
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The maximum length of strings (0 for unlimited).
|
/// The maximum length of strings (0 for unlimited).
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub fn max_string_size(&self) -> usize {
|
pub fn max_string_size(&self) -> usize {
|
||||||
self.max_string_size
|
self.limits.max_string_size
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the maximum length of arrays (0 for unlimited).
|
/// Set the maximum length of arrays (0 for unlimited).
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub fn set_max_array_size(&mut self, max_size: usize) -> &mut Self {
|
pub fn set_max_array_size(&mut self, max_size: usize) -> &mut Self {
|
||||||
self.max_array_size = if max_size == usize::MAX { 0 } else { max_size };
|
self.limits.max_array_size = if max_size == usize::MAX { 0 } else { max_size };
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,14 +144,14 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub fn max_array_size(&self) -> usize {
|
pub fn max_array_size(&self) -> usize {
|
||||||
self.max_array_size
|
self.limits.max_array_size
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the maximum length of object maps (0 for unlimited).
|
/// Set the maximum length of object maps (0 for unlimited).
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub fn set_max_map_size(&mut self, max_size: usize) -> &mut Self {
|
pub fn set_max_map_size(&mut self, max_size: usize) -> &mut Self {
|
||||||
self.max_map_size = if max_size == usize::MAX { 0 } else { max_size };
|
self.limits.max_map_size = if max_size == usize::MAX { 0 } else { max_size };
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +159,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub fn max_map_size(&self) -> usize {
|
pub fn max_map_size(&self) -> usize {
|
||||||
self.max_map_size
|
self.limits.max_map_size
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the module resolution service used by the `Engine`.
|
/// Set the module resolution service used by the `Engine`.
|
||||||
|
@ -14,11 +14,14 @@ use crate::utils::StaticVec;
|
|||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
fmt, format,
|
fmt, format,
|
||||||
rc::Rc,
|
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
sync::Arc,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "sync"))]
|
||||||
|
use crate::stdlib::rc::Rc;
|
||||||
|
#[cfg(feature = "sync")]
|
||||||
|
use crate::stdlib::sync::Arc;
|
||||||
|
|
||||||
/// A general expression evaluation trait object.
|
/// A general expression evaluation trait object.
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
pub type FnCustomSyntaxEval = dyn Fn(
|
pub type FnCustomSyntaxEval = dyn Fn(
|
||||||
|
@ -1549,7 +1549,10 @@ pub fn lex<'a, 'e>(input: &'a [&'a str], engine: &'e Engine) -> TokenIterator<'a
|
|||||||
TokenIterator {
|
TokenIterator {
|
||||||
engine,
|
engine,
|
||||||
state: TokenizeState {
|
state: TokenizeState {
|
||||||
max_string_size: engine.max_string_size,
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
max_string_size: engine.limits.max_string_size,
|
||||||
|
#[cfg(feature = "unchecked")]
|
||||||
|
max_string_size: 0,
|
||||||
non_unary: false,
|
non_unary: false,
|
||||||
comment_level: 0,
|
comment_level: 0,
|
||||||
end_with_none: false,
|
end_with_none: false,
|
||||||
|
@ -166,9 +166,9 @@ fn test_fn_ptr_curry_call() -> Result<(), Box<EvalAltResult>> {
|
|||||||
module.set_raw_fn(
|
module.set_raw_fn(
|
||||||
"call_with_arg",
|
"call_with_arg",
|
||||||
&[TypeId::of::<FnPtr>(), TypeId::of::<INT>()],
|
&[TypeId::of::<FnPtr>(), TypeId::of::<INT>()],
|
||||||
|engine: &Engine, module: &Module, args: &mut [&mut Dynamic]| {
|
|engine: &Engine, lib: &Module, args: &mut [&mut Dynamic]| {
|
||||||
let fn_ptr = std::mem::take(args[0]).cast::<FnPtr>();
|
let fn_ptr = std::mem::take(args[0]).cast::<FnPtr>();
|
||||||
fn_ptr.call_dynamic(engine, module, None, [std::mem::take(args[1])])
|
fn_ptr.call_dynamic(engine, lib, None, [std::mem::take(args[1])])
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ fn test_module_from_ast() -> Result<(), Box<EvalAltResult>> {
|
|||||||
*engine
|
*engine
|
||||||
.consume(r#"import "testing" as ttt; ttt::hidden()"#)
|
.consume(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(())
|
||||||
|
Loading…
Reference in New Issue
Block a user