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:
allow_failures:
- rust: nightly
script: bash ./.ci/build.sh

View File

@ -15,14 +15,34 @@ include = [
]
[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]
#default = ["no_function", "no_index", "no_float", "only_i32", "no_stdlib", "unchecked", "no_optimize"]
default = [ "optimize_full" ]
debug_msgs = [] # print debug messages on function registrations and calls
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_float = [] # no floating-point
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.
use std::{
any::{type_name, TypeId},
use crate::stdlib::{
any::{self, type_name, TypeId},
boxed::Box,
fmt,
};
@ -12,7 +13,7 @@ pub type Variant = dyn Any;
pub type Dynamic = Box<Variant>;
/// A trait covering any type.
pub trait Any: std::any::Any {
pub trait Any: any::Any {
/// Get the `TypeId` of this type.
fn type_id(&self) -> TypeId;
@ -27,7 +28,7 @@ pub trait Any: std::any::Any {
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 {
TypeId::of::<T>()
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
//! Module containing error definitions for the parsing process.
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.
#[derive(Debug, Eq, PartialEq, Hash, Clone)]

View File

@ -4,7 +4,7 @@ use crate::any::{Any, Dynamic};
use crate::engine::{Engine, FnCallArgs};
use crate::parser::Position;
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`.
///

View File

@ -16,7 +16,7 @@
//!
//! And the Rust part:
//!
//! ```rust,no_run
//! ```rust,ignore
//! use rhai::{Engine, EvalAltResult, RegisterFn};
//!
//! fn main() -> Result<(), EvalAltResult>
@ -37,8 +37,12 @@
//!
//! [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)]
#[cfg(feature = "no_stdlib")]
extern crate alloc;
// needs to be here, because order matters for macros
macro_rules! debug_println {
() => (
@ -61,6 +65,8 @@ macro_rules! debug_println {
);
}
#[macro_use]
mod stdlib;
mod any;
mod api;
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::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
#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)]

View File

@ -8,9 +8,19 @@ use crate::scope::{Scope, VariableType};
#[cfg(not(feature = "no_optimize"))]
use crate::optimize::optimize_ast;
use std::{
borrow::Cow, char, cmp::Ordering, fmt, iter::Peekable, str::Chars, str::FromStr, sync::Arc,
usize,
use crate::stdlib::{
borrow::Cow,
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.

View File

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

View File

@ -3,7 +3,12 @@
use crate::any::{Any, Dynamic};
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.
#[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
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::*;