From c5e2620d0f54a48b3aae5f637237345fcb23e778 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 3 Feb 2021 19:14:26 +0800 Subject: [PATCH] Minor code refactors. --- src/ast.rs | 2 +- src/fn_call.rs | 110 ++++++++++++++++++++++++------------------------- src/parser.rs | 74 ++++++++++++++------------------- 3 files changed, 88 insertions(+), 98 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 910352fe..78d179de 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1305,7 +1305,7 @@ impl Expr { _ => return None, }) } - /// Is the expression a simple variable access? + /// Return the variable name if the expression a simple variable access. #[inline(always)] pub(crate) fn get_variable_access(&self, non_qualified: bool) -> Option<&str> { match self { diff --git a/src/fn_call.rs b/src/fn_call.rs index 7e277d77..03d9e33a 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -914,59 +914,6 @@ impl Engine { ) -> Result> { let args_expr = args_expr.as_ref(); - // Handle Fn() - if fn_name == KEYWORD_FN_PTR && args_expr.len() == 1 { - let hash_fn = - calc_native_fn_hash(empty(), fn_name, once(TypeId::of::())); - - if !self.has_override(Some(mods), lib, hash_fn, hash_script, pub_only) { - // Fn - only in function call style - return self - .eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)? - .take_immutable_string() - .map_err(|typ| { - self.make_type_mismatch_err::(typ, args_expr[0].position()) - }) - .and_then(|s| FnPtr::try_from(s)) - .map(Into::::into) - .map_err(|err| err.fill_position(args_expr[0].position())); - } - } - - // Handle curry() - if fn_name == KEYWORD_FN_PTR_CURRY && args_expr.len() > 1 { - let fn_ptr = self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?; - - if !fn_ptr.is::() { - return Err(self.make_type_mismatch_err::( - self.map_type_name(fn_ptr.type_name()), - args_expr[0].position(), - )); - } - - let (fn_name, mut fn_curry) = fn_ptr.cast::().take_data(); - - // Append the new curried arguments to the existing list. - - args_expr - .iter() - .skip(1) - .try_for_each(|expr| -> Result<(), Box> { - fn_curry.push(self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?); - Ok(()) - })?; - - return Ok(FnPtr::new_unchecked(fn_name, fn_curry).into()); - } - - // Handle is_shared() - #[cfg(not(feature = "no_closure"))] - if fn_name == crate::engine::KEYWORD_IS_SHARED && args_expr.len() == 1 { - let value = self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?; - - return Ok(value.is_shared().into()); - } - // Handle call() - Redirect function call let redirected; let mut args_expr = args_expr.as_ref(); @@ -1001,6 +948,58 @@ impl Engine { hash_script = calc_script_fn_hash(empty(), name, args_len); } + // Handle Fn() + if name == KEYWORD_FN_PTR && args_expr.len() == 1 { + let hash_fn = calc_native_fn_hash(empty(), name, once(TypeId::of::())); + + if !self.has_override(Some(mods), lib, hash_fn, hash_script, pub_only) { + // Fn - only in function call style + return self + .eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)? + .take_immutable_string() + .map_err(|typ| { + self.make_type_mismatch_err::(typ, args_expr[0].position()) + }) + .and_then(|s| FnPtr::try_from(s)) + .map(Into::::into) + .map_err(|err| err.fill_position(args_expr[0].position())); + } + } + + // Handle curry() + if name == KEYWORD_FN_PTR_CURRY && args_expr.len() > 1 { + let fn_ptr = self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?; + + if !fn_ptr.is::() { + return Err(self.make_type_mismatch_err::( + self.map_type_name(fn_ptr.type_name()), + args_expr[0].position(), + )); + } + + let (name, mut fn_curry) = fn_ptr.cast::().take_data(); + + // Append the new curried arguments to the existing list. + + args_expr + .iter() + .skip(1) + .try_for_each(|expr| -> Result<(), Box> { + fn_curry.push(self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?); + Ok(()) + })?; + + return Ok(FnPtr::new_unchecked(name, fn_curry).into()); + } + + // Handle is_shared() + #[cfg(not(feature = "no_closure"))] + if name == crate::engine::KEYWORD_IS_SHARED && args_expr.len() == 1 { + let value = self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?; + + return Ok(value.is_shared().into()); + } + // Handle is_def_var() if name == KEYWORD_IS_DEF_VAR && args_expr.len() == 1 { let hash_fn = calc_native_fn_hash(empty(), name, once(TypeId::of::())); @@ -1055,8 +1054,9 @@ impl Engine { // No arguments args = Default::default(); } else { - // If the first argument is a variable, and there is no curried arguments, convert to method-call style - // in order to leverage potential &mut first argument and avoid cloning the value + // If the first argument is a variable, and there is no curried arguments, + // convert to method-call style in order to leverage potential &mut first argument and + // avoid cloning the value if curry.is_empty() && args_expr[0].get_variable_access(false).is_some() { // func(x, ...) -> x.func(...) arg_values = args_expr diff --git a/src/parser.rs b/src/parser.rs index 3b05f0ad..41c72a88 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1036,9 +1036,9 @@ fn parse_primary( match input.peek().unwrap().0 { // Function call Token::LeftParen | Token::Bang => { - // Once the identifier consumed we must enable next variables capturing #[cfg(not(feature = "no_closure"))] { + // Once the identifier consumed we must enable next variables capturing state.allow_capture = true; } let var_name_def = Ident { @@ -1050,9 +1050,9 @@ fn parse_primary( // Namespace qualification #[cfg(not(feature = "no_module"))] Token::DoubleColon => { - // Once the identifier consumed we must enable next variables capturing #[cfg(not(feature = "no_closure"))] { + // Once the identifier consumed we must enable next variables capturing state.allow_capture = true; } let var_name_def = Ident { @@ -1082,36 +1082,30 @@ fn parse_primary( match input.peek().unwrap().0 { // Function call is allowed to have reserved keyword - Token::LeftParen | Token::Bang => { - if is_keyword_function(&s) { - let var_name_def = Ident { - name: state.get_interned_string(s), - pos: settings.pos, - }; - Expr::Variable(Box::new((None, None, var_name_def))) - } else { - return Err(PERR::Reserved(s).into_err(settings.pos)); - } + Token::LeftParen | Token::Bang if is_keyword_function(&s) => { + let var_name_def = Ident { + name: state.get_interned_string(s), + pos: settings.pos, + }; + Expr::Variable(Box::new((None, None, var_name_def))) } - // Access to `this` as a variable is OK + // Access to `this` as a variable is OK within a function scope + _ if s == KEYWORD_THIS && settings.is_function_scope => { + let var_name_def = Ident { + name: state.get_interned_string(s), + pos: settings.pos, + }; + Expr::Variable(Box::new((None, None, var_name_def))) + } + // Cannot access to `this` as a variable not in a function scope _ if s == KEYWORD_THIS => { - if !settings.is_function_scope { - let msg = format!("'{}' can only be used in functions", s); - return Err(LexError::ImproperSymbol(s, msg).into_err(settings.pos)); - } else { - let var_name_def = Ident { - name: state.get_interned_string(s), - pos: settings.pos, - }; - Expr::Variable(Box::new((None, None, var_name_def))) - } + let msg = format!("'{}' can only be used in functions", s); + return Err(LexError::ImproperSymbol(s, msg).into_err(settings.pos)); } _ if is_valid_identifier(s.chars()) => { - return Err(PERR::Reserved(s).into_err(settings.pos)); - } - _ => { - return Err(LexError::UnexpectedInput(s).into_err(settings.pos)); + return Err(PERR::Reserved(s).into_err(settings.pos)) } + _ => return Err(LexError::UnexpectedInput(s).into_err(settings.pos)), } } @@ -1125,9 +1119,7 @@ fn parse_primary( } _ => { - return Err( - LexError::UnexpectedInput(token.syntax().to_string()).into_err(settings.pos) - ); + return Err(LexError::UnexpectedInput(token.syntax().to_string()).into_err(settings.pos)) } }; @@ -2275,6 +2267,12 @@ fn parse_let( (_, pos) => return Err(PERR::VariableExpected.into_err(pos)), }; + let name = state.get_interned_string(name); + let var_def = Ident { + name: name.clone(), + pos, + }; + // let name = ... let expr = if match_token(input, Token::Equals).0 { // let name = expr @@ -2283,21 +2281,13 @@ fn parse_let( None }; + state.stack.push((name, var_type)); + match var_type { // let name = expr - AccessMode::ReadWrite => { - let name = state.get_interned_string(name); - state.stack.push((name.clone(), AccessMode::ReadWrite)); - let var_def = Ident { name, pos }; - Ok(Stmt::Let(Box::new(var_def), expr, export, settings.pos)) - } + AccessMode::ReadWrite => Ok(Stmt::Let(Box::new(var_def), expr, export, settings.pos)), // const name = { expr:constant } - AccessMode::ReadOnly => { - let name = state.get_interned_string(name); - state.stack.push((name.clone(), AccessMode::ReadOnly)); - let var_def = Ident { name, pos }; - Ok(Stmt::Const(Box::new(var_def), expr, export, settings.pos)) - } + AccessMode::ReadOnly => Ok(Stmt::Const(Box::new(var_def), expr, export, settings.pos)), } }