Avoid string copying.
This commit is contained in:
parent
ea82ee81d6
commit
024133ae2d
@ -46,22 +46,22 @@ type IteratorFn = dyn Fn(&Dynamic) -> Box<dyn Iterator<Item = Dynamic>>;
|
|||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Engine<'a> {
|
pub struct Engine<'e> {
|
||||||
/// A hashmap containing all compiled functions known to the engine
|
/// A hashmap containing all compiled functions known to the engine
|
||||||
pub(crate) external_functions: HashMap<FnSpec<'a>, Arc<FnIntExt>>,
|
pub(crate) external_functions: HashMap<FnSpec<'e>, Arc<FnIntExt<'e>>>,
|
||||||
/// A hashmap containing all script-defined functions
|
/// A hashmap containing all script-defined functions
|
||||||
pub(crate) script_functions: HashMap<FnSpec<'a>, Arc<FnIntExt>>,
|
pub(crate) script_functions: HashMap<FnSpec<'e>, Arc<FnIntExt<'e>>>,
|
||||||
/// A hashmap containing all iterators known to the engine
|
/// A hashmap containing all iterators known to the engine
|
||||||
pub(crate) type_iterators: HashMap<TypeId, Arc<IteratorFn>>,
|
pub(crate) type_iterators: HashMap<TypeId, Arc<IteratorFn>>,
|
||||||
pub(crate) type_names: HashMap<String, String>,
|
pub(crate) type_names: HashMap<String, String>,
|
||||||
|
|
||||||
pub(crate) on_print: Box<dyn FnMut(&str) + 'a>,
|
pub(crate) on_print: Box<dyn FnMut(&str) + 'e>,
|
||||||
pub(crate) on_debug: Box<dyn FnMut(&str) + 'a>,
|
pub(crate) on_debug: Box<dyn FnMut(&str) + 'e>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum FnIntExt {
|
pub enum FnIntExt<'a> {
|
||||||
Ext(Box<FnAny>),
|
Ext(Box<FnAny>),
|
||||||
Int(FnDef),
|
Int(FnDef<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type FnAny = dyn Fn(FnCallArgs, Position) -> Result<Dynamic, EvalAltResult>;
|
pub type FnAny = dyn Fn(FnCallArgs, Position) -> Result<Dynamic, EvalAltResult>;
|
||||||
@ -104,27 +104,27 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
if let Some(f) = fn_def {
|
if let Some(f) = fn_def {
|
||||||
match *f {
|
match *f {
|
||||||
FnIntExt::Ext(ref f) => {
|
FnIntExt::Ext(ref func) => {
|
||||||
let r = f(args, pos)?;
|
let result = func(args, pos)?;
|
||||||
|
|
||||||
let callback = match spec.name.as_ref() {
|
let callback = match spec.name.as_ref() {
|
||||||
KEYWORD_PRINT => self.on_print.as_mut(),
|
KEYWORD_PRINT => self.on_print.as_mut(),
|
||||||
KEYWORD_DEBUG => self.on_debug.as_mut(),
|
KEYWORD_DEBUG => self.on_debug.as_mut(),
|
||||||
_ => return Ok(r),
|
_ => return Ok(result),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(callback(
|
let val = &result
|
||||||
&r.downcast::<String>()
|
.downcast::<String>()
|
||||||
.map(|s| *s)
|
.map(|s| *s)
|
||||||
.unwrap_or("error: not a string".into()),
|
.unwrap_or("error: not a string".into());
|
||||||
)
|
|
||||||
.into_dynamic())
|
Ok(callback(val).into_dynamic())
|
||||||
}
|
}
|
||||||
FnIntExt::Int(ref f) => {
|
FnIntExt::Int(ref func) => {
|
||||||
if f.params.len() != args.len() {
|
if func.params.len() != args.len() {
|
||||||
return Err(EvalAltResult::ErrorFunctionArgsMismatch(
|
return Err(EvalAltResult::ErrorFunctionArgsMismatch(
|
||||||
spec.name.into(),
|
spec.name.into(),
|
||||||
f.params.len(),
|
func.params.len(),
|
||||||
args.len(),
|
args.len(),
|
||||||
pos,
|
pos,
|
||||||
));
|
));
|
||||||
@ -133,13 +133,13 @@ impl Engine<'_> {
|
|||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
|
|
||||||
scope.extend(
|
scope.extend(
|
||||||
f.params
|
func.params
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.map(|s| s.clone())
|
||||||
.zip(args.iter().map(|x| (*x).into_dynamic())),
|
.zip(args.iter().map(|x| (*x).into_dynamic())),
|
||||||
);
|
);
|
||||||
|
|
||||||
match self.eval_stmt(&mut scope, &*f.body) {
|
match self.eval_stmt(&mut scope, &*func.body) {
|
||||||
Err(EvalAltResult::Return(x, _)) => Ok(x),
|
Err(EvalAltResult::Return(x, _)) => Ok(x),
|
||||||
other => other,
|
other => other,
|
||||||
}
|
}
|
||||||
@ -319,12 +319,12 @@ impl Engine<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate an index expression
|
/// Evaluate an index expression
|
||||||
fn eval_index_expr(
|
fn eval_index_expr<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
lhs: &Expr,
|
lhs: &'a Expr,
|
||||||
idx_expr: &Expr,
|
idx_expr: &Expr,
|
||||||
) -> Result<(IndexSourceType, Option<(String, usize)>, usize, Dynamic), EvalAltResult> {
|
) -> Result<(IndexSourceType, Option<(&'a str, usize)>, usize, Dynamic), EvalAltResult> {
|
||||||
let idx = self.eval_index_value(scope, idx_expr)?;
|
let idx = self.eval_index_value(scope, idx_expr)?;
|
||||||
|
|
||||||
match lhs {
|
match lhs {
|
||||||
@ -336,7 +336,7 @@ impl Engine<'_> {
|
|||||||
lhs.position(),
|
lhs.position(),
|
||||||
)
|
)
|
||||||
.map(|(src_idx, (val, src_type))| {
|
.map(|(src_idx, (val, src_type))| {
|
||||||
(src_type, Some((id.clone(), src_idx)), idx as usize, val)
|
(src_type, Some((id.as_str(), src_idx)), idx as usize, val)
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// (expr)[idx_expr]
|
// (expr)[idx_expr]
|
||||||
@ -371,7 +371,8 @@ impl Engine<'_> {
|
|||||||
// array_id[idx] = val
|
// array_id[idx] = val
|
||||||
IndexSourceType::Array => {
|
IndexSourceType::Array => {
|
||||||
let arr = scope.get_mut_by_type::<Array>(id, src_idx);
|
let arr = scope.get_mut_by_type::<Array>(id, src_idx);
|
||||||
(arr[idx as usize] = val).into_dynamic()
|
arr[idx as usize] = val;
|
||||||
|
().into_dynamic()
|
||||||
}
|
}
|
||||||
|
|
||||||
// string_id[idx] = val
|
// string_id[idx] = val
|
||||||
@ -381,7 +382,8 @@ impl Engine<'_> {
|
|||||||
let ch = *val
|
let ch = *val
|
||||||
.downcast::<char>()
|
.downcast::<char>()
|
||||||
.expect("char value expected to update an index position in a string");
|
.expect("char value expected to update an index position in a string");
|
||||||
Self::str_replace_char(s, idx as usize, ch).into_dynamic()
|
Self::str_replace_char(s, idx as usize, ch);
|
||||||
|
().into_dynamic()
|
||||||
}
|
}
|
||||||
|
|
||||||
// All other variable types should be an error
|
// All other variable types should be an error
|
||||||
@ -419,7 +421,7 @@ impl Engine<'_> {
|
|||||||
// of the above `clone`.
|
// of the above `clone`.
|
||||||
if let Some((id, src_idx)) = src {
|
if let Some((id, src_idx)) = src {
|
||||||
Self::update_indexed_variable_in_scope(
|
Self::update_indexed_variable_in_scope(
|
||||||
src_type, scope, &id, src_idx, idx, target,
|
src_type, scope, id, src_idx, idx, target,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,7 +512,7 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
if let Some((id, src_idx)) = src {
|
if let Some((id, src_idx)) = src {
|
||||||
Self::update_indexed_variable_in_scope(
|
Self::update_indexed_variable_in_scope(
|
||||||
src_type, scope, &id, src_idx, idx, target,
|
src_type, scope, id, src_idx, idx, target,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,10 +527,10 @@ impl Engine<'_> {
|
|||||||
/// Evaluate an expression
|
/// Evaluate an expression
|
||||||
fn eval_expr(&mut self, scope: &mut Scope, expr: &Expr) -> Result<Dynamic, EvalAltResult> {
|
fn eval_expr(&mut self, scope: &mut Scope, expr: &Expr) -> Result<Dynamic, EvalAltResult> {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::IntegerConstant(i, _) => Ok((*i).into_dynamic()),
|
Expr::IntegerConstant(i, _) => Ok(i.into_dynamic()),
|
||||||
Expr::FloatConstant(i, _) => Ok((*i).into_dynamic()),
|
Expr::FloatConstant(f, _) => Ok(f.into_dynamic()),
|
||||||
Expr::StringConstant(s, _) => Ok(s.into_dynamic()),
|
Expr::StringConstant(s, _) => Ok(s.into_dynamic()),
|
||||||
Expr::CharConstant(c, _) => Ok((*c).into_dynamic()),
|
Expr::CharConstant(c, _) => Ok(c.into_dynamic()),
|
||||||
Expr::Identifier(id, pos) => {
|
Expr::Identifier(id, pos) => {
|
||||||
Self::search_scope(scope, id, Ok, *pos).map(|(_, val)| val)
|
Self::search_scope(scope, id, Ok, *pos).map(|(_, val)| val)
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,8 @@ pub enum ParseErrorType {
|
|||||||
FnMissingName,
|
FnMissingName,
|
||||||
/// A function definition is missing the parameters list. Wrapped value is the function name.
|
/// A function definition is missing the parameters list. Wrapped value is the function name.
|
||||||
FnMissingParams(String),
|
FnMissingParams(String),
|
||||||
|
/// Assignment to an inappropriate LHS (left-hand-side) expression.
|
||||||
|
AssignmentToInvalidLHS,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error when parsing a script.
|
/// Error when parsing a script.
|
||||||
@ -114,6 +116,7 @@ impl Error for ParseError {
|
|||||||
ParseErrorType::FnMissingName => "Expecting name in function declaration",
|
ParseErrorType::FnMissingName => "Expecting name in function declaration",
|
||||||
ParseErrorType::FnMissingParams(_) => "Expecting parameters in function declaration",
|
ParseErrorType::FnMissingParams(_) => "Expecting parameters in function declaration",
|
||||||
ParseErrorType::WrongFnDefinition => "Function definitions must be at top level and cannot be inside a block or another function",
|
ParseErrorType::WrongFnDefinition => "Function definitions must be at top level and cannot be inside a block or another function",
|
||||||
|
ParseErrorType::AssignmentToInvalidLHS => "Assignment to an unsupported left-hand side expression"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ use crate::any::Dynamic;
|
|||||||
use crate::error::{LexError, ParseError, ParseErrorType};
|
use crate::error::{LexError, ParseError, ParseErrorType};
|
||||||
use std::char;
|
use std::char;
|
||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
use std::str::Chars;
|
use std::{borrow::Cow, str::Chars};
|
||||||
|
|
||||||
type LERR = LexError;
|
type LERR = LexError;
|
||||||
type PERR = ParseErrorType;
|
type PERR = ParseErrorType;
|
||||||
@ -99,12 +99,12 @@ impl std::fmt::Debug for Position {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Compiled AST (abstract syntax tree) of a Rhai script.
|
/// Compiled AST (abstract syntax tree) of a Rhai script.
|
||||||
pub struct AST(pub(crate) Vec<Stmt>, pub(crate) Vec<FnDef>);
|
pub struct AST(pub(crate) Vec<Stmt>, pub(crate) Vec<FnDef<'static>>);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FnDef {
|
pub struct FnDef<'a> {
|
||||||
pub name: String,
|
pub name: Cow<'a, str>,
|
||||||
pub params: Vec<String>,
|
pub params: Vec<Cow<'a, str>>,
|
||||||
pub body: Box<Stmt>,
|
pub body: Box<Stmt>,
|
||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
}
|
}
|
||||||
@ -232,14 +232,14 @@ pub enum Token {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Token {
|
impl Token {
|
||||||
pub fn syntax(&self) -> std::borrow::Cow<'static, str> {
|
pub fn syntax<'a>(&'a self) -> Cow<'a, str> {
|
||||||
use self::Token::*;
|
use self::Token::*;
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
IntegerConstant(ref s) => s.to_string().into(),
|
IntegerConstant(ref i) => i.to_string().into(),
|
||||||
FloatConstant(ref s) => s.to_string().into(),
|
FloatConstant(ref f) => f.to_string().into(),
|
||||||
Identifier(ref s) => s.to_string().into(),
|
Identifier(ref s) => s.into(),
|
||||||
CharConstant(ref s) => s.to_string().into(),
|
CharConstant(ref c) => c.to_string().into(),
|
||||||
LexError(ref err) => err.to_string().into(),
|
LexError(ref err) => err.to_string().into(),
|
||||||
|
|
||||||
ref token => (match token {
|
ref token => (match token {
|
||||||
@ -301,7 +301,7 @@ impl Token {
|
|||||||
PowerOfAssign => "~=",
|
PowerOfAssign => "~=",
|
||||||
For => "for",
|
For => "for",
|
||||||
In => "in",
|
In => "in",
|
||||||
_ => panic!(),
|
_ => panic!("operator should be match in outer scope"),
|
||||||
})
|
})
|
||||||
.into(),
|
.into(),
|
||||||
}
|
}
|
||||||
@ -538,8 +538,7 @@ impl<'a> TokenIterator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let out: String = result.iter().collect();
|
Ok(result.iter().collect())
|
||||||
Ok(out)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inner_next(&mut self) -> Option<(Token, Position)> {
|
fn inner_next(&mut self) -> Option<(Token, Position)> {
|
||||||
@ -640,8 +639,7 @@ impl<'a> TokenIterator<'a> {
|
|||||||
},
|
},
|
||||||
pos,
|
pos,
|
||||||
));
|
));
|
||||||
}
|
} else {
|
||||||
|
|
||||||
let out: String = result.iter().filter(|&&c| c != '_').collect();
|
let out: String = result.iter().filter(|&&c| c != '_').collect();
|
||||||
|
|
||||||
return Some((
|
return Some((
|
||||||
@ -655,6 +653,7 @@ impl<'a> TokenIterator<'a> {
|
|||||||
pos,
|
pos,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
'A'..='Z' | 'a'..='z' | '_' => {
|
'A'..='Z' | 'a'..='z' | '_' => {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
result.push(c);
|
result.push(c);
|
||||||
@ -687,7 +686,7 @@ impl<'a> TokenIterator<'a> {
|
|||||||
"fn" => Token::Fn,
|
"fn" => Token::Fn,
|
||||||
"for" => Token::For,
|
"for" => Token::For,
|
||||||
"in" => Token::In,
|
"in" => Token::In,
|
||||||
x => Token::Identifier(x.into()),
|
_ => Token::Identifier(out),
|
||||||
},
|
},
|
||||||
pos,
|
pos,
|
||||||
));
|
));
|
||||||
@ -1264,6 +1263,21 @@ fn parse_unary<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, Pars
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_assignment(lhs: Expr, rhs: Expr) -> Result<Expr, ParseError> {
|
||||||
|
match lhs {
|
||||||
|
// Only assignments to a variable, and index erxpression and a dot expression is valid LHS
|
||||||
|
Expr::Identifier(_, _) | Expr::Index(_, _) | Expr::Dot(_, _) => {
|
||||||
|
Ok(Expr::Assignment(Box::new(lhs), Box::new(rhs)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// All other LHS cannot be assigned to
|
||||||
|
_ => Err(ParseError::new(
|
||||||
|
PERR::AssignmentToInvalidLHS,
|
||||||
|
lhs.position(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_binary_op<'a>(
|
fn parse_binary_op<'a>(
|
||||||
input: &mut Peekable<TokenIterator<'a>>,
|
input: &mut Peekable<TokenIterator<'a>>,
|
||||||
precedence: i8,
|
precedence: i8,
|
||||||
@ -1308,7 +1322,7 @@ fn parse_binary_op<'a>(
|
|||||||
}
|
}
|
||||||
Token::Divide => Expr::FunctionCall("/".into(), vec![current_lhs, rhs], None, pos),
|
Token::Divide => Expr::FunctionCall("/".into(), vec![current_lhs, rhs], None, pos),
|
||||||
|
|
||||||
Token::Equals => Expr::Assignment(Box::new(current_lhs), Box::new(rhs)),
|
Token::Equals => parse_assignment(current_lhs, rhs)?,
|
||||||
Token::PlusAssign => {
|
Token::PlusAssign => {
|
||||||
let lhs_copy = current_lhs.clone();
|
let lhs_copy = current_lhs.clone();
|
||||||
Expr::Assignment(
|
Expr::Assignment(
|
||||||
@ -1687,7 +1701,7 @@ fn parse_stmt<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, Parse
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_fn<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<FnDef, ParseError> {
|
fn parse_fn<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<FnDef<'static>, ParseError> {
|
||||||
let pos = match input.next() {
|
let pos = match input.next() {
|
||||||
Some((_, tok_pos)) => tok_pos,
|
Some((_, tok_pos)) => tok_pos,
|
||||||
_ => return Err(ParseError::new(PERR::InputPastEndOfFile, Position::eof())),
|
_ => return Err(ParseError::new(PERR::InputPastEndOfFile, Position::eof())),
|
||||||
@ -1723,7 +1737,7 @@ fn parse_fn<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<FnDef, ParseE
|
|||||||
Some((Token::RightParen, _)) => break,
|
Some((Token::RightParen, _)) => break,
|
||||||
Some((Token::Comma, _)) => (),
|
Some((Token::Comma, _)) => (),
|
||||||
Some((Token::Identifier(s), _)) => {
|
Some((Token::Identifier(s), _)) => {
|
||||||
params.push(s);
|
params.push(s.into());
|
||||||
}
|
}
|
||||||
Some((_, pos)) => return Err(ParseError::new(PERR::MalformedCallExpr, pos)),
|
Some((_, pos)) => return Err(ParseError::new(PERR::MalformedCallExpr, pos)),
|
||||||
None => return Err(ParseError::new(PERR::MalformedCallExpr, Position::eof())),
|
None => return Err(ParseError::new(PERR::MalformedCallExpr, Position::eof())),
|
||||||
@ -1734,7 +1748,7 @@ fn parse_fn<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<FnDef, ParseE
|
|||||||
let body = parse_block(input)?;
|
let body = parse_block(input)?;
|
||||||
|
|
||||||
Ok(FnDef {
|
Ok(FnDef {
|
||||||
name: name,
|
name: name.into(),
|
||||||
params: params,
|
params: params,
|
||||||
body: Box::new(body),
|
body: Box::new(body),
|
||||||
pos: pos,
|
pos: pos,
|
||||||
|
35
src/scope.rs
35
src/scope.rs
@ -1,4 +1,5 @@
|
|||||||
use crate::any::{Any, Dynamic};
|
use crate::any::{Any, Dynamic};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
/// A type containing information about current scope.
|
/// A type containing information about current scope.
|
||||||
/// Useful for keeping state between `Engine` runs
|
/// Useful for keeping state between `Engine` runs
|
||||||
@ -17,9 +18,9 @@ use crate::any::{Any, Dynamic};
|
|||||||
///
|
///
|
||||||
/// When searching for variables, newly-added variables are found before similarly-named but older variables,
|
/// When searching for variables, newly-added variables are found before similarly-named but older variables,
|
||||||
/// allowing for automatic _shadowing_ of variables.
|
/// allowing for automatic _shadowing_ of variables.
|
||||||
pub struct Scope(Vec<(String, Dynamic)>);
|
pub struct Scope<'a>(Vec<(Cow<'a, str>, Dynamic)>);
|
||||||
|
|
||||||
impl Scope {
|
impl<'a> Scope<'a> {
|
||||||
/// Create a new Scope.
|
/// Create a new Scope.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self(Vec::new())
|
Self(Vec::new())
|
||||||
@ -36,18 +37,18 @@ impl Scope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add (push) a new variable to the Scope.
|
/// Add (push) a new variable to the Scope.
|
||||||
pub fn push<T: Any>(&mut self, key: String, value: T) {
|
pub fn push<K: Into<Cow<'a, str>>, T: Any>(&mut self, key: K, value: T) {
|
||||||
self.0.push((key, Box::new(value)));
|
self.0.push((key.into(), Box::new(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add (push) a new variable to the Scope.
|
/// Add (push) a new variable to the Scope.
|
||||||
pub(crate) fn push_dynamic(&mut self, key: String, value: Dynamic) {
|
pub(crate) fn push_dynamic<K: Into<Cow<'a, str>>>(&mut self, key: K, value: Dynamic) {
|
||||||
self.0.push((key, value));
|
self.0.push((key.into(), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove (pop) the last variable from the Scope.
|
/// Remove (pop) the last variable from the Scope.
|
||||||
pub fn pop(&mut self) -> Option<(String, Dynamic)> {
|
pub fn pop(&mut self) -> Option<(String, Dynamic)> {
|
||||||
self.0.pop()
|
self.0.pop().map(|(key, value)| (key.to_string(), value))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Truncate (rewind) the Scope to a previous size.
|
/// Truncate (rewind) the Scope to a previous size.
|
||||||
@ -56,13 +57,13 @@ impl Scope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Find a variable in the Scope, starting from the last.
|
/// Find a variable in the Scope, starting from the last.
|
||||||
pub fn get(&self, key: &str) -> Option<(usize, String, Dynamic)> {
|
pub fn get(&self, key: &str) -> Option<(usize, &str, Dynamic)> {
|
||||||
self.0
|
self.0
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.rev() // Always search a Scope in reverse order
|
.rev() // Always search a Scope in reverse order
|
||||||
.find(|(_, (name, _))| name == key)
|
.find(|(_, (name, _))| name == key)
|
||||||
.map(|(i, (name, value))| (i, name.clone(), value.clone()))
|
.map(|(i, (name, value))| (i, name.as_ref(), value.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the value of a variable in the Scope, starting from the last.
|
/// Get the value of a variable in the Scope, starting from the last.
|
||||||
@ -97,20 +98,26 @@ impl Scope {
|
|||||||
self.0
|
self.0
|
||||||
.iter()
|
.iter()
|
||||||
.rev() // Always search a Scope in reverse order
|
.rev() // Always search a Scope in reverse order
|
||||||
.map(|(key, value)| (key.as_str(), value))
|
.map(|(key, value)| (key.as_ref(), value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/// Get a mutable iterator to variables in the Scope.
|
/// Get a mutable iterator to variables in the Scope.
|
||||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&str, &mut Dynamic)> {
|
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&str, &mut Dynamic)> {
|
||||||
self.0
|
self.0
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.rev() // Always search a Scope in reverse order
|
.rev() // Always search a Scope in reverse order
|
||||||
.map(|(key, value)| (key.as_str(), value))
|
.map(|(key, value)| (key.as_ref(), value))
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::iter::Extend<(String, Dynamic)> for Scope {
|
impl<'a, K> std::iter::Extend<(K, Dynamic)> for Scope<'a>
|
||||||
fn extend<T: IntoIterator<Item = (String, Dynamic)>>(&mut self, iter: T) {
|
where
|
||||||
self.0.extend(iter);
|
K: Into<Cow<'a, str>>,
|
||||||
|
{
|
||||||
|
fn extend<T: IntoIterator<Item = (K, Dynamic)>>(&mut self, iter: T) {
|
||||||
|
self.0
|
||||||
|
.extend(iter.into_iter().map(|(key, value)| (key.into(), value)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,8 @@ fn test_scope_eval() -> Result<(), EvalAltResult> {
|
|||||||
// Then push some initialized variables into the state
|
// Then push some initialized variables into the state
|
||||||
// NOTE: Remember the default numbers used by Rhai are i64 and f64.
|
// NOTE: Remember the default numbers used by Rhai are i64 and f64.
|
||||||
// Better stick to them or it gets hard to work with other variables in the script.
|
// Better stick to them or it gets hard to work with other variables in the script.
|
||||||
scope.push("y".into(), 42_i64);
|
scope.push("y", 42_i64);
|
||||||
scope.push("z".into(), 999_i64);
|
scope.push("z", 999_i64);
|
||||||
|
|
||||||
// First invocation
|
// First invocation
|
||||||
engine
|
engine
|
||||||
|
Loading…
Reference in New Issue
Block a user