Added no_std support

This commit is contained in:
Trangar 2020-03-17 19:26:11 +01:00
parent bffa3ed636
commit c8a9df0a0a
16 changed files with 140 additions and 24 deletions

13
.ci/build.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/bash
set -ex
cargo build --verbose
cargo test --verbose
if [ "$TRAVIS_RUST_VERSION" = "nightly" ]
then
cargo build --verbose --features no_stdlib
cargo test --verbose --features no_stdlib
fi

View File

@ -6,3 +6,5 @@ rust:
matrix: matrix:
allow_failures: allow_failures:
- rust: nightly - rust: nightly
script: bash ./.ci/build.sh

View File

@ -15,14 +15,34 @@ include = [
] ]
[dependencies] [dependencies]
num-traits = "*" num-traits = "0.2.11"
[dependencies.libm]
version = "0.2.1"
optional = true
[dependencies.core-error]
version = "0.0.1-rc4"
features = ["alloc"]
optional = true
[dependencies.hashbrown]
version = "0.7.1"
default-features = false
features = ["ahash", "nightly", "inline-more"]
optional = true
[dependencies.ahash]
version = "0.3.2"
default-features = false
optional = true
[features] [features]
#default = ["no_function", "no_index", "no_float", "only_i32", "no_stdlib", "unchecked", "no_optimize"] #default = ["no_function", "no_index", "no_float", "only_i32", "no_stdlib", "unchecked", "no_optimize"]
default = [ "optimize_full" ] default = [ "optimize_full" ]
debug_msgs = [] # print debug messages on function registrations and calls debug_msgs = [] # print debug messages on function registrations and calls
unchecked = [] # unchecked arithmetic unchecked = [] # unchecked arithmetic
no_stdlib = [] # no standard library of utility functions no_stdlib = ["num-traits/libm", "hashbrown", "core-error", "libm"] # no standard library of utility functions
no_index = [] # no arrays and indexing no_index = [] # no arrays and indexing
no_float = [] # no floating-point no_float = [] # no floating-point
no_function = [] # no script-defined functions no_function = [] # no script-defined functions

View File

@ -1,7 +1,8 @@
//! Helper module which defines the `Any` trait to to allow dynamic value handling. //! Helper module which defines the `Any` trait to to allow dynamic value handling.
use std::{ use crate::stdlib::{
any::{type_name, TypeId}, any::{self, type_name, TypeId},
boxed::Box,
fmt, fmt,
}; };
@ -12,7 +13,7 @@ pub type Variant = dyn Any;
pub type Dynamic = Box<Variant>; pub type Dynamic = Box<Variant>;
/// A trait covering any type. /// A trait covering any type.
pub trait Any: std::any::Any { pub trait Any: any::Any {
/// Get the `TypeId` of this type. /// Get the `TypeId` of this type.
fn type_id(&self) -> TypeId; fn type_id(&self) -> TypeId;
@ -27,7 +28,7 @@ pub trait Any: std::any::Any {
fn _closed(&self) -> _Private; fn _closed(&self) -> _Private;
} }
impl<T: Clone + std::any::Any + ?Sized> Any for T { impl<T: Clone + any::Any + ?Sized> Any for T {
fn type_id(&self) -> TypeId { fn type_id(&self) -> TypeId {
TypeId::of::<T>() TypeId::of::<T>()
} }

View File

@ -12,13 +12,15 @@ use crate::scope::Scope;
#[cfg(not(feature = "no_optimize"))] #[cfg(not(feature = "no_optimize"))]
use crate::optimize::optimize_ast; use crate::optimize::optimize_ast;
use std::{ use crate::stdlib::{
any::{type_name, TypeId}, any::{type_name, TypeId},
fs::File, boxed::Box,
io::prelude::*, string::{String, ToString},
path::PathBuf,
sync::Arc, sync::Arc,
vec::Vec,
}; };
#[cfg(not(feature = "no_stdlib"))]
use crate::stdlib::{fs::File, io::prelude::*, path::PathBuf};
impl<'e> Engine<'e> { impl<'e> Engine<'e> {
pub(crate) fn register_fn_raw( pub(crate) fn register_fn_raw(
@ -115,6 +117,7 @@ impl<'e> Engine<'e> {
parse(&mut tokens_stream.peekable(), self, scope) parse(&mut tokens_stream.peekable(), self, scope)
} }
#[cfg(not(feature = "no_stdlib"))]
fn read_file(path: PathBuf) -> Result<String, EvalAltResult> { fn read_file(path: PathBuf) -> Result<String, EvalAltResult> {
let mut f = File::open(path.clone()) let mut f = File::open(path.clone())
.map_err(|err| EvalAltResult::ErrorReadingScriptFile(path.clone(), err))?; .map_err(|err| EvalAltResult::ErrorReadingScriptFile(path.clone(), err))?;
@ -127,12 +130,14 @@ impl<'e> Engine<'e> {
} }
/// Compile a file into an AST. /// Compile a file into an AST.
#[cfg(not(feature = "no_stdlib"))]
pub fn compile_file(&self, path: PathBuf) -> Result<AST, EvalAltResult> { pub fn compile_file(&self, path: PathBuf) -> Result<AST, EvalAltResult> {
self.compile_file_with_scope(&Scope::new(), path) self.compile_file_with_scope(&Scope::new(), path)
} }
/// Compile a file into an AST using own scope. /// Compile a file into an AST using own scope.
/// The scope is useful for passing constants into the script for optimization. /// The scope is useful for passing constants into the script for optimization.
#[cfg(not(feature = "no_stdlib"))]
pub fn compile_file_with_scope( pub fn compile_file_with_scope(
&self, &self,
scope: &Scope, scope: &Scope,
@ -145,11 +150,13 @@ impl<'e> Engine<'e> {
} }
/// Evaluate a file. /// Evaluate a file.
#[cfg(not(feature = "no_stdlib"))]
pub fn eval_file<T: Any + Clone>(&mut self, path: PathBuf) -> Result<T, EvalAltResult> { pub fn eval_file<T: Any + Clone>(&mut self, path: PathBuf) -> Result<T, EvalAltResult> {
Self::read_file(path).and_then(|contents| self.eval::<T>(&contents)) Self::read_file(path).and_then(|contents| self.eval::<T>(&contents))
} }
/// Evaluate a file with own scope. /// Evaluate a file with own scope.
#[cfg(not(feature = "no_stdlib"))]
pub fn eval_file_with_scope<T: Any + Clone>( pub fn eval_file_with_scope<T: Any + Clone>(
&mut self, &mut self,
scope: &mut Scope, scope: &mut Scope,
@ -234,6 +241,7 @@ impl<'e> Engine<'e> {
/// ///
/// Note - if `retain_functions` is set to `true`, functions defined by previous scripts are _retained_ /// Note - if `retain_functions` is set to `true`, functions defined by previous scripts are _retained_
/// and not cleared from run to run. /// and not cleared from run to run.
#[cfg(not(feature = "no_stdlib"))]
pub fn consume_file( pub fn consume_file(
&mut self, &mut self,
retain_functions: bool, retain_functions: bool,
@ -247,6 +255,7 @@ impl<'e> Engine<'e> {
/// ///
/// Note - if `retain_functions` is set to `true`, functions defined by previous scripts are _retained_ /// Note - if `retain_functions` is set to `true`, functions defined by previous scripts are _retained_
/// and not cleared from run to run. /// and not cleared from run to run.
#[cfg(not(feature = "no_stdlib"))]
pub fn consume_file_with_scope( pub fn consume_file_with_scope(
&mut self, &mut self,
scope: &mut Scope, scope: &mut Scope,

View File

@ -17,9 +17,12 @@ use num_traits::{
CheckedShr, CheckedSub, CheckedShr, CheckedSub,
}; };
use std::{ use crate::stdlib::{
boxed::Box,
fmt::{Debug, Display}, fmt::{Debug, Display},
format,
ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Range, Rem, Shl, Shr, Sub}, ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Range, Rem, Shl, Shr, Sub},
string::{String, ToString},
{i32, i64, u32}, {i32, i64, u32},
}; };

View File

@ -1,6 +1,7 @@
//! Helper module which defines `FnArgs` to make function calling easier. //! Helper module which defines `FnArgs` to make function calling easier.
use crate::any::{Any, Dynamic}; use crate::any::{Any, Dynamic};
use crate::stdlib::{string::String, vec, vec::Vec};
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
use crate::engine::Array; use crate::engine::Array;

View File

@ -11,12 +11,17 @@ use crate::optimize::OptimizationLevel;
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
use crate::INT; use crate::INT;
use std::{ use crate::stdlib::{
any::{type_name, TypeId}, any::{type_name, TypeId},
borrow::Cow, borrow::Cow,
boxed::Box,
collections::HashMap, collections::HashMap,
format,
iter::once, iter::once,
string::{String, ToString},
sync::Arc, sync::Arc,
vec,
vec::Vec,
}; };
/// An dynamic array of `Dynamic` values. /// An dynamic array of `Dynamic` values.

View File

@ -1,7 +1,7 @@
//! Module containing error definitions for the parsing process. //! Module containing error definitions for the parsing process.
use crate::parser::Position; use crate::parser::Position;
use std::{char, error::Error, fmt}; use crate::stdlib::{char, error::Error, fmt, string::String};
/// Error when tokenizing the script text. /// Error when tokenizing the script text.
#[derive(Debug, Eq, PartialEq, Hash, Clone)] #[derive(Debug, Eq, PartialEq, Hash, Clone)]

View File

@ -4,7 +4,7 @@ use crate::any::{Any, Dynamic};
use crate::engine::{Engine, FnCallArgs}; use crate::engine::{Engine, FnCallArgs};
use crate::parser::Position; use crate::parser::Position;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use std::any::TypeId; use crate::stdlib::{any::TypeId, boxed::Box, string::ToString, vec};
/// A trait to register custom functions with the `Engine`. /// A trait to register custom functions with the `Engine`.
/// ///

View File

@ -16,7 +16,7 @@
//! //!
//! And the Rust part: //! And the Rust part:
//! //!
//! ```rust,no_run //! ```rust,ignore
//! use rhai::{Engine, EvalAltResult, RegisterFn}; //! use rhai::{Engine, EvalAltResult, RegisterFn};
//! //!
//! fn main() -> Result<(), EvalAltResult> //! fn main() -> Result<(), EvalAltResult>
@ -37,8 +37,12 @@
//! //!
//! [Check out the README on GitHub for more information!](https://github.com/jonathandturner/rhai) //! [Check out the README on GitHub for more information!](https://github.com/jonathandturner/rhai)
#![cfg_attr(feature = "no_stdlib", no_std)]
#![allow(non_snake_case)] #![allow(non_snake_case)]
#[cfg(feature = "no_stdlib")]
extern crate alloc;
// needs to be here, because order matters for macros // needs to be here, because order matters for macros
macro_rules! debug_println { macro_rules! debug_println {
() => ( () => (
@ -61,6 +65,8 @@ macro_rules! debug_println {
); );
} }
#[macro_use]
mod stdlib;
mod any; mod any;
mod api; mod api;
mod builtin; mod builtin;

View File

@ -5,7 +5,11 @@ use crate::engine::{Engine, FnCallArgs, KEYWORD_DEBUG, KEYWORD_DUMP_AST, KEYWORD
use crate::parser::{map_dynamic_to_expr, Expr, FnDef, Stmt, AST}; use crate::parser::{map_dynamic_to_expr, Expr, FnDef, Stmt, AST};
use crate::scope::{Scope, ScopeEntry, VariableType}; use crate::scope::{Scope, ScopeEntry, VariableType};
use std::sync::Arc; use crate::stdlib::{
sync::Arc,
vec::Vec, string::{String, ToString},
boxed::Box, vec,
};
/// Level of optimization performed /// Level of optimization performed
#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)] #[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)]

View File

@ -8,9 +8,19 @@ use crate::scope::{Scope, VariableType};
#[cfg(not(feature = "no_optimize"))] #[cfg(not(feature = "no_optimize"))]
use crate::optimize::optimize_ast; use crate::optimize::optimize_ast;
use std::{ use crate::stdlib::{
borrow::Cow, char, cmp::Ordering, fmt, iter::Peekable, str::Chars, str::FromStr, sync::Arc, borrow::Cow,
usize, boxed::Box,
char,
cmp::Ordering,
fmt, format,
iter::Peekable,
str::Chars,
str::FromStr,
string::{String, ToString},
sync::Arc,
usize, vec,
vec::Vec,
}; };
/// The system integer type. /// The system integer type.

View File

@ -4,7 +4,14 @@ use crate::any::Dynamic;
use crate::error::ParseError; use crate::error::ParseError;
use crate::parser::{Position, INT}; use crate::parser::{Position, INT};
use std::{error::Error, fmt, path::PathBuf}; use crate::stdlib::{
error::Error,
fmt,
string::{String, ToString},
};
#[cfg(not(feature = "no_stdlib"))]
use crate::stdlib::path::PathBuf;
/// Evaluation result. /// Evaluation result.
/// ///
@ -47,6 +54,7 @@ pub enum EvalAltResult {
/// Wrapped value is the type of the actual result. /// Wrapped value is the type of the actual result.
ErrorMismatchOutputType(String, Position), ErrorMismatchOutputType(String, Position),
/// Error reading from a script file. Wrapped value is the path of the script file. /// Error reading from a script file. Wrapped value is the path of the script file.
#[cfg(not(feature = "no_stdlib"))]
ErrorReadingScriptFile(PathBuf, std::io::Error), ErrorReadingScriptFile(PathBuf, std::io::Error),
/// Inappropriate member access. /// Inappropriate member access.
ErrorDotExpr(String, Position), ErrorDotExpr(String, Position),
@ -93,6 +101,7 @@ impl EvalAltResult {
} }
Self::ErrorAssignmentToConstant(_, _) => "Assignment to a constant variable", Self::ErrorAssignmentToConstant(_, _) => "Assignment to a constant variable",
Self::ErrorMismatchOutputType(_, _) => "Output type is incorrect", Self::ErrorMismatchOutputType(_, _) => "Output type is incorrect",
#[cfg(not(feature = "no_stdlib"))]
Self::ErrorReadingScriptFile(_, _) => "Cannot read from script file", Self::ErrorReadingScriptFile(_, _) => "Cannot read from script file",
Self::ErrorDotExpr(_, _) => "Malformed dot expression", Self::ErrorDotExpr(_, _) => "Malformed dot expression",
Self::ErrorArithmetic(_, _) => "Arithmetic error", Self::ErrorArithmetic(_, _) => "Arithmetic error",
@ -127,6 +136,7 @@ impl fmt::Display for EvalAltResult {
} }
Self::LoopBreak => write!(f, "{}", desc), Self::LoopBreak => write!(f, "{}", desc),
Self::Return(_, pos) => write!(f, "{} ({})", desc, pos), Self::Return(_, pos) => write!(f, "{} ({})", desc, pos),
#[cfg(not(feature = "no_stdlib"))]
Self::ErrorReadingScriptFile(path, err) => { Self::ErrorReadingScriptFile(path, err) => {
write!(f, "{} '{}': {}", desc, path.display(), err) write!(f, "{} '{}': {}", desc, path.display(), err)
} }
@ -199,7 +209,9 @@ impl<T: AsRef<str>> From<T> for EvalAltResult {
impl EvalAltResult { impl EvalAltResult {
pub fn position(&self) -> Position { pub fn position(&self) -> Position {
match self { match self {
Self::ErrorReadingScriptFile(_, _) | Self::LoopBreak => Position::none(), #[cfg(not(feature = "no_stdlib"))]
Self::ErrorReadingScriptFile(_, _) => Position::none(),
Self::LoopBreak => Position::none(),
Self::ErrorParsing(err) => err.position(), Self::ErrorParsing(err) => err.position(),
@ -226,7 +238,9 @@ impl EvalAltResult {
pub(crate) fn set_position(&mut self, new_position: Position) { pub(crate) fn set_position(&mut self, new_position: Position) {
match self { match self {
Self::ErrorReadingScriptFile(_, _) | Self::LoopBreak => (), #[cfg(not(feature = "no_stdlib"))]
Self::ErrorReadingScriptFile(_, _) => (),
Self::LoopBreak => (),
Self::ErrorParsing(ParseError(_, ref mut pos)) Self::ErrorParsing(ParseError(_, ref mut pos))
| Self::ErrorFunctionNotFound(_, ref mut pos) | Self::ErrorFunctionNotFound(_, ref mut pos)

View File

@ -3,7 +3,12 @@
use crate::any::{Any, Dynamic}; use crate::any::{Any, Dynamic};
use crate::parser::{map_dynamic_to_expr, Expr, Position}; use crate::parser::{map_dynamic_to_expr, Expr, Position};
use std::borrow::Cow; use crate::stdlib::{
borrow::Cow,
iter,
string::{String, ToString},
vec::Vec,
};
/// Type of a variable in the Scope. /// Type of a variable in the Scope.
#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)] #[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
@ -193,7 +198,7 @@ impl<'a> Scope<'a> {
} }
} }
impl<'a, K> std::iter::Extend<(K, VariableType, Dynamic)> for Scope<'a> impl<'a, K> iter::Extend<(K, VariableType, Dynamic)> for Scope<'a>
where where
K: Into<Cow<'a, str>>, K: Into<Cow<'a, str>>,
{ {

23
src/stdlib.rs Normal file
View File

@ -0,0 +1,23 @@
#[cfg(feature = "no_stdlib")]
mod inner {
pub use core::{
any, arch, array, ascii, cell, char, clone, cmp, convert, default, f32, f64, ffi, fmt,
future, hash, hint, i128, i16, i32, i64, i8, isize, iter, marker, mem, num, ops, option,
panic, pin, prelude, ptr, result, slice, str, task, time, u128, u16, u32, u64, u8, usize,
};
pub use alloc::{borrow, boxed, format, string, sync, vec};
pub use core_error as error;
pub mod collections {
pub use hashbrown::HashMap;
}
}
#[cfg(not(feature = "no_stdlib"))]
mod inner {
pub use std::*;
}
pub use self::inner::*;