Support compiling to WASM.

This commit is contained in:
Stephen Chung 2020-06-16 23:47:31 +08:00
parent 1adf3cc39a
commit 151cd1af48
7 changed files with 38 additions and 4 deletions

View File

@ -28,6 +28,7 @@ Features
* Rugged - protection against malicious attacks (such as [stack-overflow](#maximum-call-stack-depth), [over-sized data](#maximum-length-of-strings), and [runaway scripts](#maximum-number-of-operations) etc.) that may come from untrusted third-party user-land scripts. * Rugged - protection against malicious attacks (such as [stack-overflow](#maximum-call-stack-depth), [over-sized data](#maximum-length-of-strings), and [runaway scripts](#maximum-number-of-operations) etc.) that may come from untrusted third-party user-land scripts.
* Track script evaluation [progress](#tracking-progress-and-force-terminate-script-run) and manually terminate a script run. * Track script evaluation [progress](#tracking-progress-and-force-terminate-script-run) and manually terminate a script run.
* [`no-std`](#optional-features) support. * [`no-std`](#optional-features) support.
* Supports compiling to `WASM`, optionally with [minimal builds](#minimal-builds).
* [Function overloading](#function-overloading). * [Function overloading](#function-overloading).
* [Operator overloading](#operator-overloading). * [Operator overloading](#operator-overloading).
* Organize code base with dynamically-loadable [modules]. * Organize code base with dynamically-loadable [modules].
@ -141,8 +142,8 @@ Making [`Dynamic`] small helps performance due to better cache efficiency.
### Minimal builds ### Minimal builds
In order to compile a _minimal_build - i.e. a build optimized for size - perhaps for embedded targets, it is essential that In order to compile a _minimal_build - i.e. a build optimized for size - perhaps for `no-std` embedded targets or for
the correct linker flags are used in `cargo.toml`: compiling to `WASM`, it is essential that the correct linker flags are used in `cargo.toml`:
```toml ```toml
[profile.release] [profile.release]
@ -156,7 +157,9 @@ all code is compiled in as what a script requires cannot be predicted. If a lang
omitting them via special features is a prudent strategy to optimize the build for size. omitting them via special features is a prudent strategy to optimize the build for size.
Omitting arrays (`no_index`) yields the most code-size savings, followed by floating-point support Omitting arrays (`no_index`) yields the most code-size savings, followed by floating-point support
(`no_float`), checked arithmetic (`unchecked`) and finally object maps and custom types (`no_object`). (`no_float`), checked arithmetic/script resource limits (`unchecked`) and finally object maps and custom types (`no_object`).
Where the usage scenario does not call for loading externally-defined modules, use `no_module` to save some bytes.
Disable script-defined functions (`no_function`) only when the feature is not needed because code size savings is minimal. Disable script-defined functions (`no_function`) only when the feature is not needed because code size savings is minimal.
[`Engine::new_raw`](#raw-engine) creates a _raw_ engine. [`Engine::new_raw`](#raw-engine) creates a _raw_ engine.

View File

@ -23,7 +23,7 @@ New features
* `Engine:register_fn` and `Engine:register_result_fn` accepts functions that take parameters of type `&str` (immutable string slice), which maps directly to `ImmutableString`. This is to avoid needing wrappers for functions taking string parameters. * `Engine:register_fn` and `Engine:register_result_fn` accepts functions that take parameters of type `&str` (immutable string slice), which maps directly to `ImmutableString`. This is to avoid needing wrappers for functions taking string parameters.
* Set maximum limit on data sizes: `Engine::set_max_string_size`, `Engine::set_max_array_size` and `Engine::set_max_map_size`. * Set maximum limit on data sizes: `Engine::set_max_string_size`, `Engine::set_max_array_size` and `Engine::set_max_map_size`.
* Supports trailing commas on array literals, object map literals, function definitions and function calls. * Supports trailing commas on array literals, object map literals, function definitions and function calls.
* Supports compiling to `WASM`.
Version 0.15.0 Version 0.15.0
============== ==============

View File

@ -24,6 +24,8 @@ use crate::stdlib::{
}; };
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(target_arch = "wasm64"))]
use crate::stdlib::time::Instant; use crate::stdlib::time::Instant;
/// Trait to represent any type. /// Trait to represent any type.
@ -192,6 +194,8 @@ impl Dynamic {
Union::Module(_) => "sub-scope", Union::Module(_) => "sub-scope",
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(target_arch = "wasm64"))]
Union::Variant(value) if value.is::<Instant>() => "timestamp", Union::Variant(value) if value.is::<Instant>() => "timestamp",
Union::Variant(value) => (***value).type_name(), Union::Variant(value) => (***value).type_name(),
} }
@ -215,6 +219,8 @@ impl fmt::Display for Dynamic {
Union::Module(value) => fmt::Debug::fmt(value, f), Union::Module(value) => fmt::Debug::fmt(value, f),
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(target_arch = "wasm64"))]
Union::Variant(value) if value.is::<Instant>() => write!(f, "<timestamp>"), Union::Variant(value) if value.is::<Instant>() => write!(f, "<timestamp>"),
Union::Variant(_) => write!(f, "?"), Union::Variant(_) => write!(f, "?"),
} }
@ -238,6 +244,8 @@ impl fmt::Debug for Dynamic {
Union::Module(value) => fmt::Debug::fmt(value, f), Union::Module(value) => fmt::Debug::fmt(value, f),
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(target_arch = "wasm64"))]
Union::Variant(value) if value.is::<Instant>() => write!(f, "<timestamp>"), Union::Variant(value) if value.is::<Instant>() => write!(f, "<timestamp>"),
Union::Variant(_) => write!(f, "<dynamic>"), Union::Variant(_) => write!(f, "<dynamic>"),
} }

View File

@ -27,6 +27,8 @@ use crate::stdlib::{
}; };
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(target_arch = "wasm64"))]
use crate::stdlib::{fs::File, io::prelude::*, path::PathBuf}; use crate::stdlib::{fs::File, io::prelude::*, path::PathBuf};
/// Engine public API /// Engine public API

View File

@ -6,6 +6,8 @@ use super::math_basic::BasicMathPackage;
use super::pkg_core::CorePackage; use super::pkg_core::CorePackage;
use super::string_more::MoreStringPackage; use super::string_more::MoreStringPackage;
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(target_arch = "wasm64"))]
use super::time_basic::BasicTimePackage; use super::time_basic::BasicTimePackage;
use crate::def_package; use crate::def_package;
@ -18,6 +20,8 @@ def_package!(crate:StandardPackage:"_Standard_ package containing all built-in f
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
BasicMapPackage::init(lib); BasicMapPackage::init(lib);
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(target_arch = "wasm64"))]
BasicTimePackage::init(lib); BasicTimePackage::init(lib);
MoreStringPackage::init(lib); MoreStringPackage::init(lib);
}); });

View File

@ -1,3 +1,6 @@
#![cfg(not(target_arch = "wasm32"))]
#![cfg(not(target_arch = "wasm64"))]
use super::logic::{eq, gt, gte, lt, lte, ne}; use super::logic::{eq, gt, gte, lt, lte, ne};
use super::math_basic::MAX_INT; use super::math_basic::MAX_INT;

View File

@ -159,6 +159,20 @@ fn test_string_substring() -> Result<(), Box<EvalAltResult>> {
fn test_string_fn() -> Result<(), Box<EvalAltResult>> { fn test_string_fn() -> Result<(), Box<EvalAltResult>> {
let mut engine = Engine::new(); let mut engine = Engine::new();
engine.register_fn("set_to_x", |ch: &mut char| *ch = 'X');
#[cfg(not(feature = "no_index"))]
#[cfg(not(feature = "no_object"))]
assert_eq!(
engine.eval::<String>(r#"let x="foo"; x[0].set_to_x(); x"#)?,
"Xoo"
);
#[cfg(not(feature = "no_index"))]
assert_eq!(
engine.eval::<String>(r#"let x="foo"; set_to_x(x[0]); x"#)?,
"foo"
);
engine.register_fn("foo1", |s: &str| s.len() as INT); engine.register_fn("foo1", |s: &str| s.len() as INT);
engine.register_fn("foo2", |s: ImmutableString| s.len() as INT); engine.register_fn("foo2", |s: ImmutableString| s.len() as INT);
engine.register_fn("foo3", |s: String| s.len() as INT); engine.register_fn("foo3", |s: String| s.len() as INT);