Add version to repl.

This commit is contained in:
Stephen Chung 2021-04-21 17:39:45 +08:00
parent 956c57e9d6
commit cc546fcaab
2 changed files with 80 additions and 77 deletions

View File

@ -55,8 +55,9 @@ fn print_help() {
} }
fn main() { fn main() {
println!("Rhai REPL tool"); let title = format!("Rhai REPL tool (version {})", env!("CARGO_PKG_VERSION"));
println!("=============="); println!("{}", title);
println!("{0:=<1$}", "", title.len());
print_help(); print_help();
// Initialize scripting engine // Initialize scripting engine

View File

@ -574,6 +574,7 @@ impl State {
self.scope_level == 0 self.scope_level == 0
} }
/// Get a mutable reference to the current function resolution cache. /// Get a mutable reference to the current function resolution cache.
#[inline(always)]
pub fn fn_resolution_cache_mut(&mut self) -> &mut FnResolutionCache { pub fn fn_resolution_cache_mut(&mut self) -> &mut FnResolutionCache {
if self.fn_resolution_caches.0.is_empty() { if self.fn_resolution_caches.0.is_empty() {
self.fn_resolution_caches.0.push(BTreeMap::new()); self.fn_resolution_caches.0.push(BTreeMap::new());
@ -582,6 +583,7 @@ impl State {
} }
/// Push an empty function resolution cache onto the stack and make it current. /// Push an empty function resolution cache onto the stack and make it current.
#[allow(dead_code)] #[allow(dead_code)]
#[inline(always)]
pub fn push_fn_resolution_cache(&mut self) { pub fn push_fn_resolution_cache(&mut self) {
self.fn_resolution_caches self.fn_resolution_caches
.0 .0
@ -592,6 +594,7 @@ impl State {
/// # Panics /// # Panics
/// ///
/// Panics if there are no more function resolution cache in the stack. /// Panics if there are no more function resolution cache in the stack.
#[inline(always)]
pub fn pop_fn_resolution_cache(&mut self) { pub fn pop_fn_resolution_cache(&mut self) {
let mut cache = self.fn_resolution_caches.0.pop().unwrap(); let mut cache = self.fn_resolution_caches.0.pop().unwrap();
cache.clear(); cache.clear();
@ -1915,7 +1918,11 @@ impl Engine {
_ => unreachable!("expression cannot be evaluated: {:?}", expr), _ => unreachable!("expression cannot be evaluated: {:?}", expr),
}; };
self.check_data_size(result, expr.position()) #[cfg(not(feature = "unchecked"))]
self.check_data_size(&result)
.map_err(|err| err.fill_position(expr.position()))?;
result
} }
/// Evaluate a statements block. /// Evaluate a statements block.
@ -2166,29 +2173,26 @@ impl Engine {
} }
// If statement // If statement
Stmt::If(expr, x, _) => self Stmt::If(expr, x, _) => {
let guard_val = self
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)? .eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
.as_bool() .as_bool()
.map_err(|err| self.make_type_mismatch_err::<bool>(err, expr.position())) .map_err(|err| self.make_type_mismatch_err::<bool>(err, expr.position()))?;
.and_then(|guard_val| {
if guard_val { if guard_val {
if !x.0.is_empty() { if !x.0.is_empty() {
self.eval_stmt_block( self.eval_stmt_block(scope, mods, state, lib, this_ptr, &x.0, true, level)
scope, mods, state, lib, this_ptr, &x.0, true, level,
)
} else { } else {
Ok(Dynamic::UNIT) Ok(Dynamic::UNIT)
} }
} else { } else {
if !x.1.is_empty() { if !x.1.is_empty() {
self.eval_stmt_block( self.eval_stmt_block(scope, mods, state, lib, this_ptr, &x.1, true, level)
scope, mods, state, lib, this_ptr, &x.1, true, level,
)
} else { } else {
Ok(Dynamic::UNIT) Ok(Dynamic::UNIT)
} }
} }
}), }
// Switch statement // Switch statement
Stmt::Switch(match_expr, x, _) => { Stmt::Switch(match_expr, x, _) => {
@ -2258,11 +2262,9 @@ impl Engine {
if !condition { if !condition {
return Ok(Dynamic::UNIT); return Ok(Dynamic::UNIT);
} }
if body.is_empty() { if !body.is_empty() {
continue; match self.eval_stmt_block(scope, mods, state, lib, this_ptr, body, true, level)
} {
match self.eval_stmt_block(scope, mods, state, lib, this_ptr, body, true, level) {
Ok(_) => (), Ok(_) => (),
Err(err) => match *err { Err(err) => match *err {
EvalAltResult::LoopBreak(false, _) => (), EvalAltResult::LoopBreak(false, _) => (),
@ -2270,6 +2272,7 @@ impl Engine {
_ => return Err(err), _ => return Err(err),
}, },
} }
}
}, },
// Do loop // Do loop
@ -2286,19 +2289,14 @@ impl Engine {
} }
} }
if self let condition = self
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)? .eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
.as_bool() .as_bool()
.map_err(|err| self.make_type_mismatch_err::<bool>(err, expr.position()))? .map_err(|err| self.make_type_mismatch_err::<bool>(err, expr.position()))?;
{
if !*is_while { if condition ^ *is_while {
return Ok(Dynamic::UNIT); return Ok(Dynamic::UNIT);
} }
} else {
if *is_while {
return Ok(Dynamic::UNIT);
}
}
}, },
// For loop // For loop
@ -2364,9 +2362,11 @@ impl Engine {
continue; continue;
} }
match self.eval_stmt_block( let result = self.eval_stmt_block(
scope, mods, state, lib, this_ptr, statements, true, level, scope, mods, state, lib, this_ptr, statements, true, level,
) { );
match result {
Ok(_) => (), Ok(_) => (),
Err(err) => match *err { Err(err) => match *err {
EvalAltResult::LoopBreak(false, _) => (), EvalAltResult::LoopBreak(false, _) => (),
@ -2477,25 +2477,25 @@ impl Engine {
} }
// Return value // Return value
Stmt::Return(ReturnType::Return, Some(expr), pos) => { Stmt::Return(ReturnType::Return, Some(expr), pos) => EvalAltResult::Return(
let value = self self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)? .flatten(),
.flatten(); *pos,
EvalAltResult::Return(value, *pos).into() )
} .into(),
// Empty return // Empty return
Stmt::Return(ReturnType::Return, None, pos) => { Stmt::Return(ReturnType::Return, None, pos) => {
EvalAltResult::Return(Default::default(), *pos).into() EvalAltResult::Return(Dynamic::UNIT, *pos).into()
} }
// Throw value // Throw value
Stmt::Return(ReturnType::Exception, Some(expr), pos) => { Stmt::Return(ReturnType::Exception, Some(expr), pos) => EvalAltResult::ErrorRuntime(
let value = self self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)? .flatten(),
.flatten(); *pos,
EvalAltResult::ErrorRuntime(value, *pos).into() )
} .into(),
// Empty throw // Empty throw
Stmt::Return(ReturnType::Exception, None, pos) => { Stmt::Return(ReturnType::Exception, None, pos) => {
@ -2640,24 +2640,18 @@ impl Engine {
} }
}; };
self.check_data_size(result, stmt.position()) #[cfg(not(feature = "unchecked"))]
} self.check_data_size(&result)
.map_err(|err| err.fill_position(stmt.position()))?;
/// Check a result to ensure that the data size is within allowable limit.
/// [`Position`] in [`EvalAltResult`] may be None and should be set afterwards.
#[cfg(feature = "unchecked")]
#[inline(always)]
fn check_data_size(&self, result: RhaiResult, _pos: Position) -> RhaiResult {
result result
} }
/// Check a result to ensure that the data size is within allowable limit. /// Check a result to ensure that the data size is within allowable limit.
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[inline(always)] fn check_data_size(&self, result: &RhaiResult) -> Result<(), Box<EvalAltResult>> {
fn check_data_size(&self, result: RhaiResult, pos: Position) -> RhaiResult {
// Simply return all errors
if result.is_err() { if result.is_err() {
return result; return Ok(());
} }
// If no data size limits, just return // If no data size limits, just return
@ -2672,7 +2666,7 @@ impl Engine {
} }
if !_has_limit { if !_has_limit {
return result; return Ok(());
} }
// Recursively calculate the size of a value (especially `Array` and `Map`) // Recursively calculate the size of a value (especially `Array` and `Map`)
@ -2734,7 +2728,11 @@ impl Engine {
.max_string_size .max_string_size
.map_or(usize::MAX, NonZeroUsize::get) .map_or(usize::MAX, NonZeroUsize::get)
{ {
return EvalAltResult::ErrorDataTooLarge("Length of string".to_string(), pos).into(); return EvalAltResult::ErrorDataTooLarge(
"Length of string".to_string(),
Position::NONE,
)
.into();
} }
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
@ -2744,7 +2742,8 @@ impl Engine {
.max_array_size .max_array_size
.map_or(usize::MAX, NonZeroUsize::get) .map_or(usize::MAX, NonZeroUsize::get)
{ {
return EvalAltResult::ErrorDataTooLarge("Size of array".to_string(), pos).into(); return EvalAltResult::ErrorDataTooLarge("Size of array".to_string(), Position::NONE)
.into();
} }
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
@ -2754,14 +2753,17 @@ impl Engine {
.max_map_size .max_map_size
.map_or(usize::MAX, NonZeroUsize::get) .map_or(usize::MAX, NonZeroUsize::get)
{ {
return EvalAltResult::ErrorDataTooLarge("Size of object map".to_string(), pos).into(); return EvalAltResult::ErrorDataTooLarge(
"Size of object map".to_string(),
Position::NONE,
)
.into();
} }
result Ok(())
} }
/// Check if the number of operations stay within limit. /// Check if the number of operations stay within limit.
#[inline]
pub(crate) fn inc_operations( pub(crate) fn inc_operations(
&self, &self,
state: &mut State, state: &mut State,