Minor code refactors.

This commit is contained in:
Stephen Chung 2021-02-03 19:14:26 +08:00
parent 42058836ba
commit c5e2620d0f
3 changed files with 88 additions and 98 deletions

View File

@ -1305,7 +1305,7 @@ impl Expr {
_ => return None, _ => return None,
}) })
} }
/// Is the expression a simple variable access? /// Return the variable name if the expression a simple variable access.
#[inline(always)] #[inline(always)]
pub(crate) fn get_variable_access(&self, non_qualified: bool) -> Option<&str> { pub(crate) fn get_variable_access(&self, non_qualified: bool) -> Option<&str> {
match self { match self {

View File

@ -914,59 +914,6 @@ impl Engine {
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
let args_expr = args_expr.as_ref(); 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::<ImmutableString>()));
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::<ImmutableString>(typ, args_expr[0].position())
})
.and_then(|s| FnPtr::try_from(s))
.map(Into::<Dynamic>::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::<FnPtr>() {
return Err(self.make_type_mismatch_err::<FnPtr>(
self.map_type_name(fn_ptr.type_name()),
args_expr[0].position(),
));
}
let (fn_name, mut fn_curry) = fn_ptr.cast::<FnPtr>().take_data();
// Append the new curried arguments to the existing list.
args_expr
.iter()
.skip(1)
.try_for_each(|expr| -> Result<(), Box<EvalAltResult>> {
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 // Handle call() - Redirect function call
let redirected; let redirected;
let mut args_expr = args_expr.as_ref(); let mut args_expr = args_expr.as_ref();
@ -1001,6 +948,58 @@ impl Engine {
hash_script = calc_script_fn_hash(empty(), name, args_len); 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::<ImmutableString>()));
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::<ImmutableString>(typ, args_expr[0].position())
})
.and_then(|s| FnPtr::try_from(s))
.map(Into::<Dynamic>::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::<FnPtr>() {
return Err(self.make_type_mismatch_err::<FnPtr>(
self.map_type_name(fn_ptr.type_name()),
args_expr[0].position(),
));
}
let (name, mut fn_curry) = fn_ptr.cast::<FnPtr>().take_data();
// Append the new curried arguments to the existing list.
args_expr
.iter()
.skip(1)
.try_for_each(|expr| -> Result<(), Box<EvalAltResult>> {
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() // Handle is_def_var()
if name == KEYWORD_IS_DEF_VAR && args_expr.len() == 1 { if name == KEYWORD_IS_DEF_VAR && args_expr.len() == 1 {
let hash_fn = calc_native_fn_hash(empty(), name, once(TypeId::of::<ImmutableString>())); let hash_fn = calc_native_fn_hash(empty(), name, once(TypeId::of::<ImmutableString>()));
@ -1055,8 +1054,9 @@ impl Engine {
// No arguments // No arguments
args = Default::default(); args = Default::default();
} else { } else {
// If the first argument is a variable, and there is no curried arguments, convert to method-call style // If the first argument is a variable, and there is no curried arguments,
// in order to leverage potential &mut first argument and avoid cloning the value // 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() { if curry.is_empty() && args_expr[0].get_variable_access(false).is_some() {
// func(x, ...) -> x.func(...) // func(x, ...) -> x.func(...)
arg_values = args_expr arg_values = args_expr

View File

@ -1036,9 +1036,9 @@ fn parse_primary(
match input.peek().unwrap().0 { match input.peek().unwrap().0 {
// Function call // Function call
Token::LeftParen | Token::Bang => { Token::LeftParen | Token::Bang => {
// Once the identifier consumed we must enable next variables capturing
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
{ {
// Once the identifier consumed we must enable next variables capturing
state.allow_capture = true; state.allow_capture = true;
} }
let var_name_def = Ident { let var_name_def = Ident {
@ -1050,9 +1050,9 @@ fn parse_primary(
// Namespace qualification // Namespace qualification
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
Token::DoubleColon => { Token::DoubleColon => {
// Once the identifier consumed we must enable next variables capturing
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
{ {
// Once the identifier consumed we must enable next variables capturing
state.allow_capture = true; state.allow_capture = true;
} }
let var_name_def = Ident { let var_name_def = Ident {
@ -1082,36 +1082,30 @@ fn parse_primary(
match input.peek().unwrap().0 { match input.peek().unwrap().0 {
// Function call is allowed to have reserved keyword // Function call is allowed to have reserved keyword
Token::LeftParen | Token::Bang => { Token::LeftParen | Token::Bang if is_keyword_function(&s) => {
if is_keyword_function(&s) {
let var_name_def = Ident { let var_name_def = Ident {
name: state.get_interned_string(s), name: state.get_interned_string(s),
pos: settings.pos, pos: settings.pos,
}; };
Expr::Variable(Box::new((None, None, var_name_def))) Expr::Variable(Box::new((None, None, var_name_def)))
} else {
return Err(PERR::Reserved(s).into_err(settings.pos));
} }
// 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)))
} }
// Access to `this` as a variable is OK // Cannot access to `this` as a variable not in a function scope
_ if s == KEYWORD_THIS => { _ if s == KEYWORD_THIS => {
if !settings.is_function_scope {
let msg = format!("'{}' can only be used in functions", s); let msg = format!("'{}' can only be used in functions", s);
return Err(LexError::ImproperSymbol(s, msg).into_err(settings.pos)); 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)))
}
} }
_ if is_valid_identifier(s.chars()) => { _ if is_valid_identifier(s.chars()) => {
return Err(PERR::Reserved(s).into_err(settings.pos)); return Err(PERR::Reserved(s).into_err(settings.pos))
}
_ => {
return Err(LexError::UnexpectedInput(s).into_err(settings.pos));
} }
_ => return Err(LexError::UnexpectedInput(s).into_err(settings.pos)),
} }
} }
@ -1125,9 +1119,7 @@ fn parse_primary(
} }
_ => { _ => {
return Err( return Err(LexError::UnexpectedInput(token.syntax().to_string()).into_err(settings.pos))
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)), (_, 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 name = ...
let expr = if match_token(input, Token::Equals).0 { let expr = if match_token(input, Token::Equals).0 {
// let name = expr // let name = expr
@ -2283,21 +2281,13 @@ fn parse_let(
None None
}; };
state.stack.push((name, var_type));
match var_type { match var_type {
// let name = expr // let name = expr
AccessMode::ReadWrite => { AccessMode::ReadWrite => Ok(Stmt::Let(Box::new(var_def), expr, export, settings.pos)),
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))
}
// const name = { expr:constant } // const name = { expr:constant }
AccessMode::ReadOnly => { AccessMode::ReadOnly => Ok(Stmt::Const(Box::new(var_def), expr, export, settings.pos)),
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))
}
} }
} }