From 3e7adc2e514cef6ece94fb019a01171ca478e6b4 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 8 Mar 2020 19:54:02 +0800 Subject: [PATCH] More comments in code. --- src/any.rs | 2 + src/api.rs | 27 +++++----- src/builtin.rs | 3 ++ src/call.rs | 3 +- src/engine.rs | 125 ++++++++++++++++++++++++--------------------- src/error.rs | 6 +-- src/fn_register.rs | 3 +- src/parser.rs | 14 ++--- src/result.rs | 7 +-- src/scope.rs | 2 + 10 files changed, 106 insertions(+), 86 deletions(-) diff --git a/src/any.rs b/src/any.rs index c53c8c74..c2003da4 100644 --- a/src/any.rs +++ b/src/any.rs @@ -1,3 +1,5 @@ +//! Helper module which defines the `Any` trait to to allow dynamic value handling. + use std::any::{type_name, TypeId}; use std::fmt; diff --git a/src/api.rs b/src/api.rs index d38dad9a..698affa7 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,3 +1,5 @@ +//! Module that defines the extern API of `Engine`. + use crate::any::{Any, AnyExt, Dynamic}; use crate::call::FuncArgs; use crate::engine::{Engine, FnAny, FnIntExt, FnSpec}; @@ -6,7 +8,7 @@ use crate::fn_register::RegisterFn; use crate::parser::{lex, parse, Position, AST}; use crate::result::EvalAltResult; use crate::scope::Scope; -use std::any::TypeId; +use std::any::{type_name, TypeId}; use std::sync::Arc; impl<'e> Engine<'e> { @@ -17,12 +19,16 @@ impl<'e> Engine<'e> { f: Box, ) { debug_println!( - "Register function: {} for {} parameter(s)", + "Register function: {} with {}", fn_name, if let Some(a) = &args { - format!("{}", a.len()) + format!( + "{} parameter{}", + a.len(), + if a.len() > 1 { "s" } else { "" } + ) } else { - "no".to_string() + "no parameter".to_string() } ); @@ -31,24 +37,21 @@ impl<'e> Engine<'e> { args, }; - self.external_functions - .insert(spec, Arc::new(FnIntExt::Ext(f))); + self.ext_functions.insert(spec, Arc::new(FnIntExt::Ext(f))); } /// Register a custom type for use with the `Engine`. /// The type must be `Clone`. pub fn register_type(&mut self) { - self.register_type_with_name::(std::any::type_name::()); + self.register_type_with_name::(type_name::()); } /// Register a custom type for use with the `Engine` with a name for the `type_of` function. /// The type must be `Clone`. - pub fn register_type_with_name(&mut self, type_name: &str) { + pub fn register_type_with_name(&mut self, name: &str) { // Add the pretty-print type name into the map - self.type_names.insert( - std::any::type_name::().to_string(), - type_name.to_string(), - ); + self.type_names + .insert(type_name::().to_string(), name.to_string()); } /// Register an iterator adapter for a type with the `Engine`. diff --git a/src/builtin.rs b/src/builtin.rs index 7c43f0a4..66789ef3 100644 --- a/src/builtin.rs +++ b/src/builtin.rs @@ -1,3 +1,6 @@ +//! Helper module that allows registration of the _core library_ and +//! _standard library_ of utility functions. + use crate::any::Any; use crate::engine::{Array, Engine}; use crate::fn_register::RegisterFn; diff --git a/src/call.rs b/src/call.rs index b287f2bf..065cc8d5 100644 --- a/src/call.rs +++ b/src/call.rs @@ -1,5 +1,4 @@ -//! Helper module which defines `FnArgs` -//! to make function calling easier. +//! Helper module which defines `FnArgs` to make function calling easier. use crate::any::{Any, Variant}; diff --git a/src/engine.rs b/src/engine.rs index 5203c495..1c13637e 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1,19 +1,25 @@ -use std::any::TypeId; -use std::borrow::Cow; -use std::cmp::{PartialEq, PartialOrd}; -use std::collections::HashMap; -use std::sync::Arc; +//! Main module defining the script evaluation `Engine`. use crate::any::{Any, AnyExt, Dynamic, Variant}; use crate::parser::{Expr, FnDef, Position, Stmt}; use crate::result::EvalAltResult; use crate::scope::Scope; +use std::any::TypeId; +use std::borrow::Cow; +use std::cmp::{PartialEq, PartialOrd}; +use std::collections::HashMap; +use std::iter::once; +use std::sync::Arc; /// An dynamic array of `Dynamic` values. pub type Array = Vec; pub type FnCallArgs<'a> = Vec<&'a mut Variant>; +pub type FnAny = dyn Fn(FnCallArgs, Position) -> Result; + +type IteratorFn = dyn Fn(&Dynamic) -> Box>; + const KEYWORD_PRINT: &'static str = "print"; const KEYWORD_DEBUG: &'static str = "debug"; const KEYWORD_TYPE_OF: &'static str = "type_of"; @@ -33,8 +39,6 @@ pub struct FnSpec<'a> { pub args: Option>, } -type IteratorFn = dyn Fn(&Dynamic) -> Box>; - /// Rhai main scripting engine. /// /// ```rust @@ -50,13 +54,14 @@ type IteratorFn = dyn Fn(&Dynamic) -> Box>; /// ``` pub struct Engine<'e> { /// A hashmap containing all compiled functions known to the engine - pub(crate) external_functions: HashMap, Arc>>, + pub(crate) ext_functions: HashMap, Arc>>, /// A hashmap containing all script-defined functions pub(crate) script_functions: HashMap, Arc>>, /// A hashmap containing all iterators known to the engine pub(crate) type_iterators: HashMap>, pub(crate) type_names: HashMap, + // Closures for implementing the print/debug commands pub(crate) on_print: Box, pub(crate) on_debug: Box, } @@ -66,8 +71,6 @@ pub enum FnIntExt<'a> { Int(FnDef<'a>), } -pub type FnAny = dyn Fn(FnCallArgs, Position) -> Result; - impl Engine<'_> { /// Universal method for calling functions, that are either /// registered with the `Engine` or written in Rhai @@ -75,7 +78,7 @@ impl Engine<'_> { &mut self, fn_name: &str, args: FnCallArgs, - def_value: Option<&Dynamic>, + def_val: Option<&Dynamic>, pos: Position, ) -> Result { debug_println!( @@ -94,21 +97,23 @@ impl Engine<'_> { }; // First search in script-defined functions (can override built-in), - // then in built-in's + // then built-in's and external functions let fn_def = self .script_functions .get(&spec) .or_else(|| { spec.args = Some(args.iter().map(|a| Any::type_id(&**a)).collect()); - self.external_functions.get(&spec) + self.ext_functions.get(&spec) }) .map(|f| f.clone()); if let Some(f) = fn_def { match *f { + // Run external function FnIntExt::Ext(ref func) => { let result = func(args, pos)?; + // See if the function match print/debug (which requires special processing) let callback = match spec.name.as_ref() { KEYWORD_PRINT => self.on_print.as_mut(), KEYWORD_DEBUG => self.on_debug.as_mut(), @@ -122,7 +127,10 @@ impl Engine<'_> { Ok(callback(val).into_dynamic()) } + + // Run script-defined function FnIntExt::Int(ref func) => { + // First check number of parameters if func.params.len() != args.len() { return Err(EvalAltResult::ErrorFunctionArgsMismatch( spec.name.into(), @@ -135,45 +143,50 @@ impl Engine<'_> { let mut scope = Scope::new(); scope.extend( + // Put arguments into scope as variables func.params .iter() - .map(|s| s.clone()) + .cloned() .zip(args.iter().map(|x| (*x).into_dynamic())), ); + // Evaluate match self.eval_stmt(&mut scope, &*func.body) { + // Convert return statement to return value Err(EvalAltResult::Return(x, _)) => Ok(x), other => other, } } } } else if spec.name == KEYWORD_TYPE_OF && args.len() == 1 { + // Handle `type_of` function Ok(self .map_type_name(args[0].type_name()) .to_string() .into_dynamic()) - } else if let Some(val) = def_value { - // Return default value - Ok(val.clone()) } else if spec.name.starts_with(FUNC_GETTER) { - // Getter + // Getter function not found Err(EvalAltResult::ErrorDotExpr( format!( - "- unknown property '{}' or it is write-only", + "- property '{}' unknown or write-only", &spec.name[FUNC_GETTER.len()..] ), pos, )) } else if spec.name.starts_with(FUNC_SETTER) { - // Setter + // Setter function not found Err(EvalAltResult::ErrorDotExpr( format!( - "- unknown property '{}' or it is read-only", + "- property '{}' unknown or read-only", &spec.name[FUNC_SETTER.len()..] ), pos, )) + } else if let Some(val) = def_val { + // Return default value + Ok(val.clone()) } else { + // Raise error let types_list = args .iter() .map(|x| (*x).type_name()) @@ -194,11 +207,9 @@ impl Engine<'_> { this_ptr: &mut Variant, dot_rhs: &Expr, ) -> Result { - use std::iter::once; - match dot_rhs { // xxx.fn_name(args) - Expr::FunctionCall(fn_name, args, def_value, pos) => { + Expr::FunctionCall(fn_name, args, def_val, pos) => { let mut args: Array = args .iter() .map(|arg| self.eval_expr(scope, arg)) @@ -208,7 +219,7 @@ impl Engine<'_> { .chain(args.iter_mut().map(|b| b.as_mut())) .collect(); - self.call_fn_raw(fn_name, args, def_value.as_ref(), *pos) + self.call_fn_raw(fn_name, args, def_val.as_ref(), *pos) } // xxx.id @@ -220,7 +231,7 @@ impl Engine<'_> { // xxx.idx_lhs[idx_expr] Expr::Index(idx_lhs, idx_expr, idx_pos) => { - let (lhs_value, _) = match idx_lhs.as_ref() { + let (expr, _) = match idx_lhs.as_ref() { // xxx.id[idx_expr] Expr::Identifier(id, pos) => { let get_fn_name = format!("{}{}", FUNC_GETTER, id); @@ -243,7 +254,7 @@ impl Engine<'_> { }; let idx = self.eval_index_value(scope, idx_expr)?; - self.get_indexed_value(lhs_value, idx, idx_expr.position(), *idx_pos) + self.get_indexed_value(expr, idx, idx_expr.position(), *idx_pos) .map(|(v, _)| v) } @@ -258,7 +269,7 @@ impl Engine<'_> { } // xxx.idx_lhs[idx_expr].rhs Expr::Index(idx_lhs, idx_expr, idx_pos) => { - let (lhs_value, _) = match idx_lhs.as_ref() { + let (expr, _) = match idx_lhs.as_ref() { // xxx.id[idx_expr].rhs Expr::Identifier(id, pos) => { let get_fn_name = format!("{}{}", FUNC_GETTER, id); @@ -281,10 +292,8 @@ impl Engine<'_> { }; let idx = self.eval_index_value(scope, idx_expr)?; - self.get_indexed_value(lhs_value, idx, idx_expr.position(), *idx_pos) - .and_then(|(mut value, _)| { - self.get_dot_val_helper(scope, value.as_mut(), rhs) - }) + self.get_indexed_value(expr, idx, idx_expr.position(), *idx_pos) + .and_then(|(mut v, _)| self.get_dot_val_helper(scope, v.as_mut(), rhs)) } // Syntax error _ => Err(EvalAltResult::ErrorDotExpr( @@ -312,21 +321,21 @@ impl Engine<'_> { // id.??? Expr::Identifier(id, pos) => { let (src_idx, mut target) = Self::search_scope(scope, id, Ok, *pos)?; - let value = self.get_dot_val_helper(scope, target.as_mut(), dot_rhs); + let val = self.get_dot_val_helper(scope, target.as_mut(), dot_rhs); - // In case the expression mutated `target`, we need to reassign it because of the above `clone`. + // In case the expression mutated `target`, we need to update it back into the scope because it is cloned. *scope.get_mut(id, src_idx) = target; - value + val } // idx_lhs[idx_expr].??? Expr::Index(idx_lhs, idx_expr, idx_pos) => { let (src_type, src, idx, mut target) = self.eval_index_expr(scope, idx_lhs, idx_expr, *idx_pos)?; - let value = self.get_dot_val_helper(scope, target.as_mut(), dot_rhs); + let val = self.get_dot_val_helper(scope, target.as_mut(), dot_rhs); - // In case the expression mutated `target`, we need to reassign it because of the above `clone`. + // In case the expression mutated `target`, we need to update it back into the scope because it is cloned. if let Some((id, src_idx)) = src { Self::update_indexed_var_in_scope( src_type, @@ -339,7 +348,7 @@ impl Engine<'_> { )?; } - value + val } // {expr}.??? @@ -449,7 +458,7 @@ impl Engine<'_> { let val = self.eval_expr(scope, expr)?; self.get_indexed_value(val, idx, idx_expr.position(), idx_pos) - .map(|(value, _)| (IndexSourceType::Expression, None, idx as usize, value)) + .map(|(v, _)| (IndexSourceType::Expression, None, idx as usize, v)) } } } @@ -474,21 +483,21 @@ impl Engine<'_> { id: &str, src_idx: usize, idx: usize, - val: Dynamic, + new_val: Dynamic, val_pos: Position, ) -> Result { match src_type { // array_id[idx] = val IndexSourceType::Array => { let arr = scope.get_mut_by_type::(id, src_idx); - Ok((arr[idx as usize] = val).into_dynamic()) + Ok((arr[idx as usize] = new_val).into_dynamic()) } // string_id[idx] = val IndexSourceType::String => { let s = scope.get_mut_by_type::(id, src_idx); // Value must be a character - let ch = *val + let ch = *new_val .downcast::() .map_err(|_| EvalAltResult::ErrorCharMismatch(val_pos))?; Ok(Self::str_replace_char(s, idx as usize, ch).into_dynamic()) @@ -501,16 +510,16 @@ impl Engine<'_> { /// Update the value at an index position fn update_indexed_value( - mut val: Dynamic, + mut target: Dynamic, idx: usize, new_val: Dynamic, pos: Position, ) -> Result { - if val.is::() { - let arr = val.downcast_mut::().expect("array expected"); + if target.is::() { + let arr = target.downcast_mut::().expect("array expected"); arr[idx as usize] = new_val; - } else if val.is::() { - let s = val.downcast_mut::().expect("string expected"); + } else if target.is::() { + let s = target.downcast_mut::().expect("string expected"); // Value must be a character let ch = *new_val .downcast::() @@ -521,7 +530,7 @@ impl Engine<'_> { panic!("array or string source type expected for indexing") } - Ok(val) + Ok(target) } /// Chain-evaluate a dot setter @@ -609,7 +618,7 @@ impl Engine<'_> { val_pos, )?; - // In case the expression mutated `target`, we need to reassign it because of the above `clone`. + // In case the expression mutated `target`, we need to update it back into the scope because it is cloned. Self::update_indexed_value(v, idx as usize, target, val_pos) }) .and_then(|mut v| { @@ -659,13 +668,13 @@ impl Engine<'_> { // id.??? Expr::Identifier(id, pos) => { let (src_idx, mut target) = Self::search_scope(scope, id, Ok, *pos)?; - let value = + let val = self.set_dot_val_helper(scope, target.as_mut(), dot_rhs, new_val, val_pos); - // In case the expression mutated `target`, we need to reassign it because of the above `clone`. + // In case the expression mutated `target`, we need to update it back into the scope because it is cloned. *scope.get_mut(id, src_idx) = target; - value + val } // lhs[idx_expr].??? @@ -673,10 +682,10 @@ impl Engine<'_> { Expr::Index(lhs, idx_expr, idx_pos) => { let (src_type, src, idx, mut target) = self.eval_index_expr(scope, lhs, idx_expr, *idx_pos)?; - let value = + let val = self.set_dot_val_helper(scope, target.as_mut(), dot_rhs, new_val, val_pos); - // In case the expression mutated `target`, we need to reassign it because of the above `clone`. + // In case the expression mutated `target`, we need to update it back into the scope because it is cloned. if let Some((id, src_idx)) = src { Self::update_indexed_var_in_scope( src_type, @@ -689,7 +698,7 @@ impl Engine<'_> { )?; } - value + val } // Syntax error @@ -782,7 +791,7 @@ impl Engine<'_> { Ok(Box::new(arr)) } - Expr::FunctionCall(fn_name, args, def_value, pos) => { + Expr::FunctionCall(fn_name, args, def_val, pos) => { let mut args = args .iter() .map(|expr| self.eval_expr(scope, expr)) @@ -791,7 +800,7 @@ impl Engine<'_> { self.call_fn_raw( fn_name, args.iter_mut().map(|b| b.as_mut()).collect(), - def_value.as_ref(), + def_val.as_ref(), *pos, ) } @@ -996,7 +1005,7 @@ impl Engine<'_> { // Create the new scripting Engine let mut engine = Engine { - external_functions: HashMap::new(), + ext_functions: HashMap::new(), script_functions: HashMap::new(), type_iterators: HashMap::new(), type_names, diff --git a/src/error.rs b/src/error.rs index d4096cb1..41a793c3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,7 +1,7 @@ +//! Module containing error definitions for the parsing process. + use crate::parser::Position; -use std::char; -use std::error::Error; -use std::fmt; +use std::{char, error::Error, fmt}; /// Error when tokenizing the script text. #[derive(Debug, Eq, PartialEq, Hash, Clone)] diff --git a/src/fn_register.rs b/src/fn_register.rs index 9e84492f..535ffc83 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -1,9 +1,10 @@ -use std::any::TypeId; +//! Module which defines the function registration mechanism. use crate::any::{Any, Dynamic}; use crate::engine::{Engine, FnCallArgs}; use crate::parser::Position; use crate::result::EvalAltResult; +use std::any::TypeId; /// A trait to register custom functions with the `Engine`. /// diff --git a/src/parser.rs b/src/parser.rs index a395d21e..ad714187 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,8 +1,8 @@ +//! Main module defining the lexer and parser. + use crate::any::Dynamic; use crate::error::{LexError, ParseError, ParseErrorType}; -use std::char; -use std::iter::Peekable; -use std::{borrow::Cow, str::Chars}; +use std::{borrow::Cow, char, fmt, iter::Peekable, str::Chars}; type LERR = LexError; type PERR = ParseErrorType; @@ -78,8 +78,8 @@ impl Default for Position { } } -impl std::fmt::Display for Position { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Display for Position { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.is_eof() { write!(f, "EOF") } else { @@ -88,8 +88,8 @@ impl std::fmt::Display for Position { } } -impl std::fmt::Debug for Position { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Debug for Position { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.is_eof() { write!(f, "(EOF)") } else { diff --git a/src/result.rs b/src/result.rs index d9e009d2..26272030 100644 --- a/src/result.rs +++ b/src/result.rs @@ -1,8 +1,9 @@ -use std::error::Error; +//! Module containing error definitions for the evaluation process. use crate::any::Dynamic; use crate::error::ParseError; use crate::parser::Position; +use std::{error::Error, fmt}; /// Evaluation result. /// @@ -102,8 +103,8 @@ impl Error for EvalAltResult { } } -impl std::fmt::Display for EvalAltResult { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Display for EvalAltResult { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let desc = self.description(); match self { diff --git a/src/scope.rs b/src/scope.rs index 9a5eb815..01bcebda 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -1,3 +1,5 @@ +//! Module that defines the `Scope` type representing a function call-stack scope. + use crate::any::{Any, Dynamic}; use std::borrow::Cow;