Check if function calls cannot be scripted.
This commit is contained in:
parent
ea63c66cf0
commit
ac05f0a0a8
@ -181,7 +181,7 @@ impl FnCallHashes {
|
|||||||
|
|
||||||
/// _(internals)_ A function call.
|
/// _(internals)_ A function call.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
#[derive(Clone, Default, Hash)]
|
#[derive(Clone, Hash)]
|
||||||
pub struct FnCallExpr {
|
pub struct FnCallExpr {
|
||||||
/// Namespace of the function, if any.
|
/// Namespace of the function, if any.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
@ -196,6 +196,9 @@ pub struct FnCallExpr {
|
|||||||
pub capture_parent_scope: bool,
|
pub capture_parent_scope: bool,
|
||||||
/// Is this function call a native operator?
|
/// Is this function call a native operator?
|
||||||
pub operator_token: Option<Token>,
|
pub operator_token: Option<Token>,
|
||||||
|
/// Can this function call be a scripted function?
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
pub can_be_script: bool,
|
||||||
/// [Position] of the function name.
|
/// [Position] of the function name.
|
||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
}
|
}
|
||||||
@ -215,6 +218,10 @@ impl fmt::Debug for FnCallExpr {
|
|||||||
if let Some(ref token) = self.operator_token {
|
if let Some(ref token) = self.operator_token {
|
||||||
ff.field("operator_token", token);
|
ff.field("operator_token", token);
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
if self.can_be_script {
|
||||||
|
ff.field("can_be_script", &self.can_be_script);
|
||||||
|
}
|
||||||
ff.field("hash", &self.hashes)
|
ff.field("hash", &self.hashes)
|
||||||
.field("name", &self.name)
|
.field("name", &self.name)
|
||||||
.field("args", &self.args);
|
.field("args", &self.args);
|
||||||
@ -684,6 +691,8 @@ impl Expr {
|
|||||||
args: once(Self::StringConstant(f.fn_name().into(), pos)).collect(),
|
args: once(Self::StringConstant(f.fn_name().into(), pos)).collect(),
|
||||||
capture_parent_scope: false,
|
capture_parent_scope: false,
|
||||||
operator_token: None,
|
operator_token: None,
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
can_be_script: true,
|
||||||
pos,
|
pos,
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
|
@ -223,9 +223,16 @@ impl Engine {
|
|||||||
hashes,
|
hashes,
|
||||||
args,
|
args,
|
||||||
operator_token,
|
operator_token,
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
can_be_script,
|
||||||
..
|
..
|
||||||
} = expr;
|
} = expr;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
let native = !can_be_script;
|
||||||
|
#[cfg(feature = "no_function")]
|
||||||
|
let native = true;
|
||||||
|
|
||||||
// Short-circuit native binary operator call if under Fast Operators mode
|
// Short-circuit native binary operator call if under Fast Operators mode
|
||||||
if operator_token.is_some() && self.fast_operators() && args.len() == 2 {
|
if operator_token.is_some() && self.fast_operators() && args.len() == 2 {
|
||||||
let mut lhs = self
|
let mut lhs = self
|
||||||
@ -251,7 +258,8 @@ impl Engine {
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
.exec_fn_call(
|
.exec_fn_call(
|
||||||
None, global, caches, lib, name, *hashes, operands, false, false, pos, level,
|
None, global, caches, lib, name, native, *hashes, operands, false, false, pos,
|
||||||
|
level,
|
||||||
)
|
)
|
||||||
.map(|(v, ..)| v);
|
.map(|(v, ..)| v);
|
||||||
}
|
}
|
||||||
@ -280,6 +288,7 @@ impl Engine {
|
|||||||
lib,
|
lib,
|
||||||
this_ptr,
|
this_ptr,
|
||||||
name,
|
name,
|
||||||
|
native,
|
||||||
first_arg,
|
first_arg,
|
||||||
args,
|
args,
|
||||||
*hashes,
|
*hashes,
|
||||||
|
@ -578,6 +578,7 @@ impl Engine {
|
|||||||
caches: &mut Caches,
|
caches: &mut Caches,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
|
_native_only: bool,
|
||||||
hashes: FnCallHashes,
|
hashes: FnCallHashes,
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
is_ref_mut: bool,
|
is_ref_mut: bool,
|
||||||
@ -644,11 +645,11 @@ impl Engine {
|
|||||||
|
|
||||||
let level = level + 1;
|
let level = level + 1;
|
||||||
|
|
||||||
// Script-defined function call?
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
if !_native_only {
|
||||||
|
// Script-defined function call?
|
||||||
let local_entry = &mut None;
|
let local_entry = &mut None;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
if let Some(FnResolutionCacheEntry { func, ref source }) = self
|
if let Some(FnResolutionCacheEntry { func, ref source }) = self
|
||||||
.resolve_fn(
|
.resolve_fn(
|
||||||
global,
|
global,
|
||||||
@ -728,6 +729,7 @@ impl Engine {
|
|||||||
|
|
||||||
return Ok((result?, false));
|
return Ok((result?, false));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Native function call
|
// Native function call
|
||||||
let hash = hashes.native;
|
let hash = hashes.native;
|
||||||
@ -836,6 +838,7 @@ impl Engine {
|
|||||||
caches,
|
caches,
|
||||||
lib,
|
lib,
|
||||||
fn_name,
|
fn_name,
|
||||||
|
false,
|
||||||
new_hash,
|
new_hash,
|
||||||
&mut args,
|
&mut args,
|
||||||
false,
|
false,
|
||||||
@ -881,6 +884,7 @@ impl Engine {
|
|||||||
caches,
|
caches,
|
||||||
lib,
|
lib,
|
||||||
fn_name,
|
fn_name,
|
||||||
|
false,
|
||||||
new_hash,
|
new_hash,
|
||||||
&mut args,
|
&mut args,
|
||||||
is_ref_mut,
|
is_ref_mut,
|
||||||
@ -968,6 +972,7 @@ impl Engine {
|
|||||||
caches,
|
caches,
|
||||||
lib,
|
lib,
|
||||||
fn_name,
|
fn_name,
|
||||||
|
false,
|
||||||
hash,
|
hash,
|
||||||
&mut args,
|
&mut args,
|
||||||
is_ref_mut,
|
is_ref_mut,
|
||||||
@ -995,6 +1000,7 @@ impl Engine {
|
|||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
|
native_only: bool,
|
||||||
first_arg: Option<&Expr>,
|
first_arg: Option<&Expr>,
|
||||||
args_expr: &[Expr],
|
args_expr: &[Expr],
|
||||||
hashes: FnCallHashes,
|
hashes: FnCallHashes,
|
||||||
@ -1003,6 +1009,7 @@ impl Engine {
|
|||||||
pos: Position,
|
pos: Position,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
|
let native = native_only;
|
||||||
let mut first_arg = first_arg;
|
let mut first_arg = first_arg;
|
||||||
let mut a_expr = args_expr;
|
let mut a_expr = args_expr;
|
||||||
let mut total_args = if first_arg.is_some() { 1 } else { 0 } + a_expr.len();
|
let mut total_args = if first_arg.is_some() { 1 } else { 0 } + a_expr.len();
|
||||||
@ -1199,8 +1206,8 @@ impl Engine {
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
.exec_fn_call(
|
.exec_fn_call(
|
||||||
scope, global, caches, lib, name, hashes, &mut args, is_ref_mut, false, pos,
|
scope, global, caches, lib, name, native, hashes, &mut args, is_ref_mut, false,
|
||||||
level,
|
pos, level,
|
||||||
)
|
)
|
||||||
.map(|(v, ..)| v);
|
.map(|(v, ..)| v);
|
||||||
}
|
}
|
||||||
@ -1262,7 +1269,8 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
None, global, caches, lib, name, hashes, &mut args, is_ref_mut, false, pos, level,
|
None, global, caches, lib, name, native, hashes, &mut args, is_ref_mut, false, pos,
|
||||||
|
level,
|
||||||
)
|
)
|
||||||
.map(|(v, ..)| v)
|
.map(|(v, ..)| v)
|
||||||
}
|
}
|
||||||
|
@ -422,6 +422,7 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
caches,
|
caches,
|
||||||
self.lib,
|
self.lib,
|
||||||
fn_name,
|
fn_name,
|
||||||
|
false,
|
||||||
hash,
|
hash,
|
||||||
args,
|
args,
|
||||||
is_ref_mut,
|
is_ref_mut,
|
||||||
|
@ -897,24 +897,17 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
Stmt::Expr(expr) => {
|
Stmt::Expr(expr) => {
|
||||||
optimize_expr(expr, state, false);
|
optimize_expr(expr, state, false);
|
||||||
|
|
||||||
match &mut **expr {
|
if matches!(**expr, Expr::FnCall(..) | Expr::Stmt(..)) {
|
||||||
// func(...)
|
|
||||||
Expr::FnCall(x, pos) => {
|
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*stmt = Stmt::FnCall(mem::take(x), *pos);
|
*stmt = match *mem::take(expr) {
|
||||||
}
|
// func(...);
|
||||||
|
Expr::FnCall(x, pos) => Stmt::FnCall(x, pos),
|
||||||
|
// {};
|
||||||
|
Expr::Stmt(x) if x.is_empty() => Stmt::Noop(x.position()),
|
||||||
// {...};
|
// {...};
|
||||||
Expr::Stmt(x) => {
|
Expr::Stmt(x) => (*x).into(),
|
||||||
if x.is_empty() {
|
_ => unreachable!(),
|
||||||
state.set_dirty();
|
};
|
||||||
*stmt = Stmt::Noop(x.position());
|
|
||||||
} else {
|
|
||||||
state.set_dirty();
|
|
||||||
*stmt = mem::take(&mut **x).into();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// expr;
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +193,6 @@ impl<'e> ParseState<'e> {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
let is_func_name = _lib.values().any(|f| f.name == name);
|
let is_func_name = _lib.values().any(|f| f.name == name);
|
||||||
|
|
||||||
#[cfg(feature = "no_function")]
|
#[cfg(feature = "no_function")]
|
||||||
let is_func_name = false;
|
let is_func_name = false;
|
||||||
|
|
||||||
@ -600,7 +599,9 @@ impl Engine {
|
|||||||
#[cfg(feature = "no_module")]
|
#[cfg(feature = "no_module")]
|
||||||
let hash = calc_fn_hash(None, &id, 0);
|
let hash = calc_fn_hash(None, &id, 0);
|
||||||
|
|
||||||
let hashes = if is_valid_function_name(&id) {
|
let is_valid_function_name = is_valid_function_name(&id);
|
||||||
|
|
||||||
|
let hashes = if is_valid_function_name {
|
||||||
hash.into()
|
hash.into()
|
||||||
} else {
|
} else {
|
||||||
FnCallHashes::from_native(hash)
|
FnCallHashes::from_native(hash)
|
||||||
@ -612,6 +613,8 @@ impl Engine {
|
|||||||
name: state.get_interned_string(id),
|
name: state.get_interned_string(id),
|
||||||
capture_parent_scope,
|
capture_parent_scope,
|
||||||
operator_token: None,
|
operator_token: None,
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
can_be_script: is_valid_function_name,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
namespace,
|
namespace,
|
||||||
hashes,
|
hashes,
|
||||||
@ -668,7 +671,9 @@ impl Engine {
|
|||||||
#[cfg(feature = "no_module")]
|
#[cfg(feature = "no_module")]
|
||||||
let hash = calc_fn_hash(None, &id, args.len());
|
let hash = calc_fn_hash(None, &id, args.len());
|
||||||
|
|
||||||
let hashes = if is_valid_function_name(&id) {
|
let is_valid_function_name = is_valid_function_name(&id);
|
||||||
|
|
||||||
|
let hashes = if is_valid_function_name {
|
||||||
hash.into()
|
hash.into()
|
||||||
} else {
|
} else {
|
||||||
FnCallHashes::from_native(hash)
|
FnCallHashes::from_native(hash)
|
||||||
@ -680,6 +685,8 @@ impl Engine {
|
|||||||
name: state.get_interned_string(id),
|
name: state.get_interned_string(id),
|
||||||
capture_parent_scope,
|
capture_parent_scope,
|
||||||
operator_token: None,
|
operator_token: None,
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
can_be_script: is_valid_function_name,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
namespace,
|
namespace,
|
||||||
hashes,
|
hashes,
|
||||||
@ -1912,12 +1919,14 @@ impl Engine {
|
|||||||
args.shrink_to_fit();
|
args.shrink_to_fit();
|
||||||
|
|
||||||
Ok(FnCallExpr {
|
Ok(FnCallExpr {
|
||||||
|
namespace: Default::default(),
|
||||||
name: state.get_interned_string("-"),
|
name: state.get_interned_string("-"),
|
||||||
hashes: FnCallHashes::from_native(calc_fn_hash(None, "-", 1)),
|
hashes: FnCallHashes::from_native(calc_fn_hash(None, "-", 1)),
|
||||||
args,
|
args,
|
||||||
pos,
|
pos,
|
||||||
operator_token: Some(token),
|
operator_token: Some(token),
|
||||||
..Default::default()
|
capture_parent_scope: false,
|
||||||
|
can_be_script: false,
|
||||||
}
|
}
|
||||||
.into_fn_call_expr(pos))
|
.into_fn_call_expr(pos))
|
||||||
}
|
}
|
||||||
@ -1940,12 +1949,14 @@ impl Engine {
|
|||||||
args.shrink_to_fit();
|
args.shrink_to_fit();
|
||||||
|
|
||||||
Ok(FnCallExpr {
|
Ok(FnCallExpr {
|
||||||
|
namespace: Default::default(),
|
||||||
name: state.get_interned_string("+"),
|
name: state.get_interned_string("+"),
|
||||||
hashes: FnCallHashes::from_native(calc_fn_hash(None, "+", 1)),
|
hashes: FnCallHashes::from_native(calc_fn_hash(None, "+", 1)),
|
||||||
args,
|
args,
|
||||||
pos,
|
pos,
|
||||||
operator_token: Some(token),
|
operator_token: Some(token),
|
||||||
..Default::default()
|
capture_parent_scope: false,
|
||||||
|
can_be_script: false,
|
||||||
}
|
}
|
||||||
.into_fn_call_expr(pos))
|
.into_fn_call_expr(pos))
|
||||||
}
|
}
|
||||||
@ -1961,12 +1972,14 @@ impl Engine {
|
|||||||
args.shrink_to_fit();
|
args.shrink_to_fit();
|
||||||
|
|
||||||
Ok(FnCallExpr {
|
Ok(FnCallExpr {
|
||||||
|
namespace: Default::default(),
|
||||||
name: state.get_interned_string("!"),
|
name: state.get_interned_string("!"),
|
||||||
hashes: FnCallHashes::from_native(calc_fn_hash(None, "!", 1)),
|
hashes: FnCallHashes::from_native(calc_fn_hash(None, "!", 1)),
|
||||||
args,
|
args,
|
||||||
pos,
|
pos,
|
||||||
operator_token: Some(token),
|
operator_token: Some(token),
|
||||||
..Default::default()
|
capture_parent_scope: false,
|
||||||
|
can_be_script: false,
|
||||||
}
|
}
|
||||||
.into_fn_call_expr(pos))
|
.into_fn_call_expr(pos))
|
||||||
}
|
}
|
||||||
@ -2335,18 +2348,22 @@ impl Engine {
|
|||||||
|
|
||||||
let op = op_token.syntax();
|
let op = op_token.syntax();
|
||||||
let hash = calc_fn_hash(None, &op, 2);
|
let hash = calc_fn_hash(None, &op, 2);
|
||||||
let operator_token = if is_valid_function_name(&op) {
|
let is_function = is_valid_function_name(&op);
|
||||||
|
let operator_token = if is_function {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(op_token.clone())
|
Some(op_token.clone())
|
||||||
};
|
};
|
||||||
|
|
||||||
let op_base = FnCallExpr {
|
let op_base = FnCallExpr {
|
||||||
|
namespace: Default::default(),
|
||||||
name: state.get_interned_string(op.as_ref()),
|
name: state.get_interned_string(op.as_ref()),
|
||||||
hashes: FnCallHashes::from_native(hash),
|
hashes: FnCallHashes::from_native(hash),
|
||||||
|
args: StaticVec::new_const(),
|
||||||
pos,
|
pos,
|
||||||
operator_token,
|
operator_token,
|
||||||
..Default::default()
|
capture_parent_scope: false,
|
||||||
|
can_be_script: is_function,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut args = StaticVec::new_const();
|
let mut args = StaticVec::new_const();
|
||||||
@ -2432,7 +2449,7 @@ impl Engine {
|
|||||||
let pos = args[0].start_position();
|
let pos = args[0].start_position();
|
||||||
|
|
||||||
FnCallExpr {
|
FnCallExpr {
|
||||||
hashes: if is_valid_function_name(&s) {
|
hashes: if is_function {
|
||||||
hash.into()
|
hash.into()
|
||||||
} else {
|
} else {
|
||||||
FnCallHashes::from_native(hash)
|
FnCallHashes::from_native(hash)
|
||||||
@ -3659,6 +3676,7 @@ impl Engine {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let expr = FnCallExpr {
|
let expr = FnCallExpr {
|
||||||
|
namespace: Default::default(),
|
||||||
name: state.get_interned_string(crate::engine::KEYWORD_FN_PTR_CURRY),
|
name: state.get_interned_string(crate::engine::KEYWORD_FN_PTR_CURRY),
|
||||||
hashes: FnCallHashes::from_native(calc_fn_hash(
|
hashes: FnCallHashes::from_native(calc_fn_hash(
|
||||||
None,
|
None,
|
||||||
@ -3667,7 +3685,9 @@ impl Engine {
|
|||||||
)),
|
)),
|
||||||
args,
|
args,
|
||||||
pos,
|
pos,
|
||||||
..Default::default()
|
operator_token: None,
|
||||||
|
capture_parent_scope: false,
|
||||||
|
can_be_script: false,
|
||||||
}
|
}
|
||||||
.into_fn_call_expr(pos);
|
.into_fn_call_expr(pos);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user