From 151cd1af48210fd62f63f0ee8d8c3ad6b6cc68d9 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 16 Jun 2020 23:47:31 +0800 Subject: [PATCH] Support compiling to WASM. --- README.md | 9 ++++++--- RELEASES.md | 2 +- src/any.rs | 8 ++++++++ src/api.rs | 2 ++ src/packages/pkg_std.rs | 4 ++++ src/packages/time_basic.rs | 3 +++ tests/string.rs | 14 ++++++++++++++ 7 files changed, 38 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2ee5e6b3..d25637cd 100644 --- a/README.md +++ b/README.md @@ -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. * Track script evaluation [progress](#tracking-progress-and-force-terminate-script-run) and manually terminate a script run. * [`no-std`](#optional-features) support. +* Supports compiling to `WASM`, optionally with [minimal builds](#minimal-builds). * [Function overloading](#function-overloading). * [Operator overloading](#operator-overloading). * Organize code base with dynamically-loadable [modules]. @@ -141,8 +142,8 @@ Making [`Dynamic`] small helps performance due to better cache efficiency. ### Minimal builds -In order to compile a _minimal_build - i.e. a build optimized for size - perhaps for embedded targets, it is essential that -the correct linker flags are used in `cargo.toml`: +In order to compile a _minimal_build - i.e. a build optimized for size - perhaps for `no-std` embedded targets or for +compiling to `WASM`, it is essential that the correct linker flags are used in `cargo.toml`: ```toml [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 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. [`Engine::new_raw`](#raw-engine) creates a _raw_ engine. diff --git a/RELEASES.md b/RELEASES.md index 6fec7a48..d9cd5309 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -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. * 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 compiling to `WASM`. Version 0.15.0 ============== diff --git a/src/any.rs b/src/any.rs index a50d6820..ec25a545 100644 --- a/src/any.rs +++ b/src/any.rs @@ -24,6 +24,8 @@ use crate::stdlib::{ }; #[cfg(not(feature = "no_std"))] +#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(target_arch = "wasm64"))] use crate::stdlib::time::Instant; /// Trait to represent any type. @@ -192,6 +194,8 @@ impl Dynamic { Union::Module(_) => "sub-scope", #[cfg(not(feature = "no_std"))] + #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(target_arch = "wasm64"))] Union::Variant(value) if value.is::() => "timestamp", Union::Variant(value) => (***value).type_name(), } @@ -215,6 +219,8 @@ impl fmt::Display for Dynamic { Union::Module(value) => fmt::Debug::fmt(value, f), #[cfg(not(feature = "no_std"))] + #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(target_arch = "wasm64"))] Union::Variant(value) if value.is::() => write!(f, ""), Union::Variant(_) => write!(f, "?"), } @@ -238,6 +244,8 @@ impl fmt::Debug for Dynamic { Union::Module(value) => fmt::Debug::fmt(value, f), #[cfg(not(feature = "no_std"))] + #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(target_arch = "wasm64"))] Union::Variant(value) if value.is::() => write!(f, ""), Union::Variant(_) => write!(f, ""), } diff --git a/src/api.rs b/src/api.rs index 6a6dbf5c..4a6e04cc 100644 --- a/src/api.rs +++ b/src/api.rs @@ -27,6 +27,8 @@ use crate::stdlib::{ }; #[cfg(not(feature = "no_std"))] +#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(target_arch = "wasm64"))] use crate::stdlib::{fs::File, io::prelude::*, path::PathBuf}; /// Engine public API diff --git a/src/packages/pkg_std.rs b/src/packages/pkg_std.rs index d2790d50..80179f43 100644 --- a/src/packages/pkg_std.rs +++ b/src/packages/pkg_std.rs @@ -6,6 +6,8 @@ use super::math_basic::BasicMathPackage; use super::pkg_core::CorePackage; use super::string_more::MoreStringPackage; #[cfg(not(feature = "no_std"))] +#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(target_arch = "wasm64"))] use super::time_basic::BasicTimePackage; use crate::def_package; @@ -18,6 +20,8 @@ def_package!(crate:StandardPackage:"_Standard_ package containing all built-in f #[cfg(not(feature = "no_object"))] BasicMapPackage::init(lib); #[cfg(not(feature = "no_std"))] + #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(target_arch = "wasm64"))] BasicTimePackage::init(lib); MoreStringPackage::init(lib); }); diff --git a/src/packages/time_basic.rs b/src/packages/time_basic.rs index b8e13604..098c417d 100644 --- a/src/packages/time_basic.rs +++ b/src/packages/time_basic.rs @@ -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::math_basic::MAX_INT; diff --git a/tests/string.rs b/tests/string.rs index 6eed9e6a..e6b77841 100644 --- a/tests/string.rs +++ b/tests/string.rs @@ -159,6 +159,20 @@ fn test_string_substring() -> Result<(), Box> { fn test_string_fn() -> Result<(), Box> { 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::(r#"let x="foo"; x[0].set_to_x(); x"#)?, + "Xoo" + ); + #[cfg(not(feature = "no_index"))] + assert_eq!( + engine.eval::(r#"let x="foo"; set_to_x(x[0]); x"#)?, + "foo" + ); + engine.register_fn("foo1", |s: &str| s.len() as INT); engine.register_fn("foo2", |s: ImmutableString| s.len() as INT); engine.register_fn("foo3", |s: String| s.len() as INT);