Reducce panic messages.
This commit is contained in:
parent
c8aab47f50
commit
38884ede46
51
src/ast.rs
51
src/ast.rs
@ -1651,7 +1651,7 @@ impl Stmt {
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
path.pop().expect("`path` contains current node");
|
path.pop().expect("contains current node");
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -1727,7 +1727,7 @@ impl OpAssignment<'_> {
|
|||||||
pub fn new(op: Token) -> Self {
|
pub fn new(op: Token) -> Self {
|
||||||
let op_raw = op
|
let op_raw = op
|
||||||
.map_op_assignment()
|
.map_op_assignment()
|
||||||
.expect("token is op-assignment operator")
|
.expect("op-assignment")
|
||||||
.literal_syntax();
|
.literal_syntax();
|
||||||
let op_assignment = op.literal_syntax();
|
let op_assignment = op.literal_syntax();
|
||||||
|
|
||||||
@ -1842,13 +1842,19 @@ pub struct FnCallExpr {
|
|||||||
pub args: StaticVec<Expr>,
|
pub args: StaticVec<Expr>,
|
||||||
/// List of function call arguments that are constants.
|
/// List of function call arguments that are constants.
|
||||||
///
|
///
|
||||||
/// Any arguments in `args` that is [`Expr::Stack`][Expr::Stack] indexes into this
|
/// Any arguments in `args` that is [`Expr::Stack`] indexes into this
|
||||||
/// array to find the constant for use as its argument value.
|
/// array to find the constant for use as its argument value.
|
||||||
|
///
|
||||||
|
/// # Notes
|
||||||
|
///
|
||||||
|
/// Constant arguments are very common in function calls, and keeping each constant in
|
||||||
|
/// an [`Expr::DynamicConstant`] involves an additional allocation. Keeping the constant
|
||||||
|
/// values in an inlined array avoids these extra allocations.
|
||||||
pub constants: smallvec::SmallVec<[Dynamic; 2]>,
|
pub constants: smallvec::SmallVec<[Dynamic; 2]>,
|
||||||
/// Function name.
|
/// Function name.
|
||||||
pub name: Identifier,
|
pub name: Identifier,
|
||||||
/// Does this function call capture the parent scope?
|
/// Does this function call capture the parent scope?
|
||||||
pub capture: bool,
|
pub capture_parent_scope: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FnCallExpr {
|
impl FnCallExpr {
|
||||||
@ -1858,7 +1864,7 @@ impl FnCallExpr {
|
|||||||
pub const fn is_qualified(&self) -> bool {
|
pub const fn is_qualified(&self) -> bool {
|
||||||
self.namespace.is_some()
|
self.namespace.is_some()
|
||||||
}
|
}
|
||||||
/// Convert this into a [`FnCall`][Expr::FnCall].
|
/// Convert this into an [`Expr::FnCall`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn into_fn_call_expr(self, pos: Position) -> Expr {
|
pub fn into_fn_call_expr(self, pos: Position) -> Expr {
|
||||||
@ -1996,8 +2002,9 @@ impl FloatWrapper<FLOAT> {
|
|||||||
#[derive(Clone, Hash)]
|
#[derive(Clone, Hash)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
/// Dynamic constant.
|
/// Dynamic constant.
|
||||||
/// Used to hold either an [`Array`] or [`Map`][crate::Map] literal for quick cloning.
|
///
|
||||||
/// All other primitive data types should use the appropriate variants for better speed.
|
/// Used to hold complex constants such as [`Array`] or [`Map`][crate::Map] for quick cloning.
|
||||||
|
/// Primitive data types should use the appropriate variants to avoid an allocation.
|
||||||
DynamicConstant(Box<Dynamic>, Position),
|
DynamicConstant(Box<Dynamic>, Position),
|
||||||
/// Boolean constant.
|
/// Boolean constant.
|
||||||
BoolConstant(bool, Position),
|
BoolConstant(bool, Position),
|
||||||
@ -2045,13 +2052,11 @@ pub enum Expr {
|
|||||||
(ImmutableString, Position),
|
(ImmutableString, Position),
|
||||||
)>,
|
)>,
|
||||||
),
|
),
|
||||||
/// Stack slot
|
/// Stack slot for function calls. See [`FnCallExpr`] for more details.
|
||||||
///
|
///
|
||||||
/// # Notes
|
/// This variant does not map to any language structure. It is used in function calls with
|
||||||
///
|
/// constant arguments where the `usize` number indexes into an array containing a list of
|
||||||
/// This variant does not map to any language structure. It is currently only used in function
|
/// constant arguments for the function call.
|
||||||
/// calls with constant arguments where the `usize` number indexes into an array containing a
|
|
||||||
/// list of constant arguments for the function call. See [`FnCallExpr`] for more details.
|
|
||||||
Stack(usize, Position),
|
Stack(usize, Position),
|
||||||
/// { [statement][Stmt] ... }
|
/// { [statement][Stmt] ... }
|
||||||
Stmt(Box<StmtBlock>),
|
Stmt(Box<StmtBlock>),
|
||||||
@ -2130,8 +2135,8 @@ impl fmt::Debug for Expr {
|
|||||||
if !x.constants.is_empty() {
|
if !x.constants.is_empty() {
|
||||||
ff.field("constants", &x.constants);
|
ff.field("constants", &x.constants);
|
||||||
}
|
}
|
||||||
if x.capture {
|
if x.capture_parent_scope {
|
||||||
ff.field("capture", &x.capture);
|
ff.field("capture_parent_scope", &x.capture_parent_scope);
|
||||||
}
|
}
|
||||||
ff.finish()
|
ff.finish()
|
||||||
}
|
}
|
||||||
@ -2186,10 +2191,10 @@ impl Expr {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Self::Array(x, _) if self.is_constant() => {
|
Self::Array(x, _) if self.is_constant() => {
|
||||||
let mut arr = Array::with_capacity(x.len());
|
let mut arr = Array::with_capacity(x.len());
|
||||||
arr.extend(x.iter().map(|v| {
|
arr.extend(
|
||||||
v.get_literal_value()
|
x.iter()
|
||||||
.expect("constant array has constant value")
|
.map(|v| v.get_literal_value().expect("constant value")),
|
||||||
}));
|
);
|
||||||
Dynamic::from_array(arr)
|
Dynamic::from_array(arr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2197,10 +2202,8 @@ impl Expr {
|
|||||||
Self::Map(x, _) if self.is_constant() => {
|
Self::Map(x, _) if self.is_constant() => {
|
||||||
let mut map = x.1.clone();
|
let mut map = x.1.clone();
|
||||||
x.0.iter().for_each(|(k, v)| {
|
x.0.iter().for_each(|(k, v)| {
|
||||||
*map.get_mut(k.name.as_str())
|
*map.get_mut(k.name.as_str()).expect("contains all keys") =
|
||||||
.expect("template contains all keys") = v
|
v.get_literal_value().expect("constant value")
|
||||||
.get_literal_value()
|
|
||||||
.expect("constant map has constant value")
|
|
||||||
});
|
});
|
||||||
Dynamic::from_map(map)
|
Dynamic::from_map(map)
|
||||||
}
|
}
|
||||||
@ -2479,7 +2482,7 @@ impl Expr {
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
path.pop().expect("`path` contains current node");
|
path.pop().expect("contains current node");
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -228,12 +228,8 @@ impl Imports {
|
|||||||
self.global_constants = Some(dict.into());
|
self.global_constants = Some(dict.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::fn_native::shared_write_lock(
|
crate::fn_native::shared_write_lock(self.global_constants.as_mut().expect("`Some`"))
|
||||||
self.global_constants
|
.insert(name.into(), value);
|
||||||
.as_mut()
|
|
||||||
.expect("`global_constants` is `Some`"),
|
|
||||||
)
|
|
||||||
.insert(name.into(), value);
|
|
||||||
}
|
}
|
||||||
/// Get the pre-calculated index getter hash.
|
/// Get the pre-calculated index getter hash.
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
@ -600,9 +596,7 @@ impl<'a> Target<'a> {
|
|||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let value = &mut *value
|
let value = &mut *value.write_lock::<crate::INT>().expect("`INT`");
|
||||||
.write_lock::<crate::INT>()
|
|
||||||
.expect("`BitField` holds `INT`");
|
|
||||||
|
|
||||||
let index = *index;
|
let index = *index;
|
||||||
|
|
||||||
@ -630,7 +624,7 @@ impl<'a> Target<'a> {
|
|||||||
|
|
||||||
let s = &mut *s
|
let s = &mut *s
|
||||||
.write_lock::<ImmutableString>()
|
.write_lock::<ImmutableString>()
|
||||||
.expect("`StringChar` holds `ImmutableString`");
|
.expect("`ImmutableString`");
|
||||||
|
|
||||||
let index = *index;
|
let index = *index;
|
||||||
|
|
||||||
@ -653,10 +647,7 @@ impl<'a> From<&'a mut Dynamic> for Target<'a> {
|
|||||||
if value.is_shared() {
|
if value.is_shared() {
|
||||||
// Cloning is cheap for a shared value
|
// Cloning is cheap for a shared value
|
||||||
let container = value.clone();
|
let container = value.clone();
|
||||||
return Self::LockGuard((
|
return Self::LockGuard((value.write_lock::<Dynamic>().expect("`Dynamic`"), container));
|
||||||
value.write_lock::<Dynamic>().expect("cast to `Dynamic`"),
|
|
||||||
container,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::RefMut(value)
|
Self::RefMut(value)
|
||||||
@ -786,9 +777,7 @@ impl EvalState {
|
|||||||
// Push a new function resolution cache if the stack is empty
|
// Push a new function resolution cache if the stack is empty
|
||||||
self.push_fn_resolution_cache();
|
self.push_fn_resolution_cache();
|
||||||
}
|
}
|
||||||
self.fn_resolution_caches
|
self.fn_resolution_caches.last_mut().expect("not empty")
|
||||||
.last_mut()
|
|
||||||
.expect("at least one function resolution cache")
|
|
||||||
}
|
}
|
||||||
/// 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)]
|
||||||
@ -803,9 +792,7 @@ impl EvalState {
|
|||||||
/// Panics if there is no more function resolution cache in the stack.
|
/// Panics if there is no more function resolution cache in the stack.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn pop_fn_resolution_cache(&mut self) {
|
pub fn pop_fn_resolution_cache(&mut self) {
|
||||||
self.fn_resolution_caches
|
self.fn_resolution_caches.pop().expect("not empty");
|
||||||
.pop()
|
|
||||||
.expect("at least one function resolution cache");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1188,10 +1175,10 @@ impl Engine {
|
|||||||
|
|
||||||
if let Some(index) = index {
|
if let Some(index) = index {
|
||||||
let offset = mods.len() - index.get();
|
let offset = mods.len() - index.get();
|
||||||
Some(mods.get(offset).expect("offset within range"))
|
Some(mods.get(offset).expect("within range"))
|
||||||
} else {
|
} else {
|
||||||
mods.find(root)
|
mods.find(root)
|
||||||
.map(|n| mods.get(n).expect("index is valid"))
|
.map(|n| mods.get(n).expect("valid index"))
|
||||||
.or_else(|| self.global_sub_modules.get(root).cloned())
|
.or_else(|| self.global_sub_modules.get(root).cloned())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1327,7 +1314,7 @@ impl Engine {
|
|||||||
level: 0,
|
level: 0,
|
||||||
};
|
};
|
||||||
match resolve_var(
|
match resolve_var(
|
||||||
expr.get_variable_name(true).expect("`expr` is `Variable`"),
|
expr.get_variable_name(true).expect("`Variable`"),
|
||||||
index,
|
index,
|
||||||
&context,
|
&context,
|
||||||
) {
|
) {
|
||||||
@ -1344,7 +1331,7 @@ impl Engine {
|
|||||||
scope.len() - index
|
scope.len() - index
|
||||||
} else {
|
} else {
|
||||||
// Find the variable in the scope
|
// Find the variable in the scope
|
||||||
let var_name = expr.get_variable_name(true).expect("`expr` is `Variable`");
|
let var_name = expr.get_variable_name(true).expect("`Variable`");
|
||||||
scope
|
scope
|
||||||
.get_index(var_name)
|
.get_index(var_name)
|
||||||
.ok_or_else(|| EvalAltResult::ErrorVariableNotFound(var_name.to_string(), var_pos))?
|
.ok_or_else(|| EvalAltResult::ErrorVariableNotFound(var_name.to_string(), var_pos))?
|
||||||
@ -1378,16 +1365,14 @@ impl Engine {
|
|||||||
let _terminate_chaining = terminate_chaining;
|
let _terminate_chaining = terminate_chaining;
|
||||||
|
|
||||||
// Pop the last index value
|
// Pop the last index value
|
||||||
let idx_val = idx_values.pop().expect("index chain is never empty");
|
let idx_val = idx_values.pop().expect("not empty");
|
||||||
|
|
||||||
match chain_type {
|
match chain_type {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
ChainType::Indexing => {
|
ChainType::Indexing => {
|
||||||
let pos = rhs.position();
|
let pos = rhs.position();
|
||||||
let root_pos = idx_val.position();
|
let root_pos = idx_val.position();
|
||||||
let idx_val = idx_val
|
let idx_val = idx_val.into_index_value().expect("`ChainType::Index`");
|
||||||
.into_index_value()
|
|
||||||
.expect("`chain_type` is `ChainType::Index`");
|
|
||||||
|
|
||||||
match rhs {
|
match rhs {
|
||||||
// xxx[idx].expr... | xxx[idx][expr]...
|
// xxx[idx].expr... | xxx[idx][expr]...
|
||||||
@ -1440,8 +1425,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
// xxx[rhs] op= new_val
|
// xxx[rhs] op= new_val
|
||||||
_ if new_val.is_some() => {
|
_ if new_val.is_some() => {
|
||||||
let ((new_val, new_pos), (op_info, op_pos)) =
|
let ((new_val, new_pos), (op_info, op_pos)) = new_val.expect("`Some`");
|
||||||
new_val.expect("`new_val` is `Some`");
|
|
||||||
let mut idx_val_for_setter = idx_val.clone();
|
let mut idx_val_for_setter = idx_val.clone();
|
||||||
|
|
||||||
let try_setter = match self.get_indexed_mut(
|
let try_setter = match self.get_indexed_mut(
|
||||||
@ -1495,7 +1479,7 @@ impl Engine {
|
|||||||
let FnCallExpr { name, hashes, .. } = x.as_ref();
|
let FnCallExpr { name, hashes, .. } = x.as_ref();
|
||||||
let call_args = &mut idx_val
|
let call_args = &mut idx_val
|
||||||
.into_fn_call_args()
|
.into_fn_call_args()
|
||||||
.expect("`chain_type` is `ChainType::Dot` with `Expr::FnCallExpr`");
|
.expect("`ChainType::Dot` with `Expr::FnCallExpr`");
|
||||||
self.make_method_call(
|
self.make_method_call(
|
||||||
mods, state, lib, name, *hashes, target, call_args, *pos, level,
|
mods, state, lib, name, *hashes, target, call_args, *pos, level,
|
||||||
)
|
)
|
||||||
@ -1511,8 +1495,7 @@ impl Engine {
|
|||||||
// {xxx:map}.id op= ???
|
// {xxx:map}.id op= ???
|
||||||
Expr::Property(x) if target.is::<Map>() && new_val.is_some() => {
|
Expr::Property(x) if target.is::<Map>() && new_val.is_some() => {
|
||||||
let (name, pos) = &x.2;
|
let (name, pos) = &x.2;
|
||||||
let ((new_val, new_pos), (op_info, op_pos)) =
|
let ((new_val, new_pos), (op_info, op_pos)) = new_val.expect("`Some`");
|
||||||
new_val.expect("`new_val` is `Some`");
|
|
||||||
let index = name.into();
|
let index = name.into();
|
||||||
{
|
{
|
||||||
let val_target = &mut self.get_indexed_mut(
|
let val_target = &mut self.get_indexed_mut(
|
||||||
@ -1539,8 +1522,7 @@ impl Engine {
|
|||||||
// xxx.id op= ???
|
// xxx.id op= ???
|
||||||
Expr::Property(x) if new_val.is_some() => {
|
Expr::Property(x) if new_val.is_some() => {
|
||||||
let ((getter, hash_get), (setter, hash_set), (name, pos)) = x.as_ref();
|
let ((getter, hash_get), (setter, hash_set), (name, pos)) = x.as_ref();
|
||||||
let ((mut new_val, new_pos), (op_info, op_pos)) =
|
let ((mut new_val, new_pos), (op_info, op_pos)) = new_val.expect("`Some`");
|
||||||
new_val.expect("`new_val` is `Some`");
|
|
||||||
|
|
||||||
if op_info.is_some() {
|
if op_info.is_some() {
|
||||||
let hash = FnCallHashes::from_native(*hash_get);
|
let hash = FnCallHashes::from_native(*hash_get);
|
||||||
@ -2281,9 +2263,7 @@ impl Engine {
|
|||||||
Expr::Map(x, _) => {
|
Expr::Map(x, _) => {
|
||||||
let mut map = x.1.clone();
|
let mut map = x.1.clone();
|
||||||
for (Ident { name: key, .. }, expr) in &x.0 {
|
for (Ident { name: key, .. }, expr) in &x.0 {
|
||||||
let value_ref = map
|
let value_ref = map.get_mut(key.as_str()).expect("contains all keys");
|
||||||
.get_mut(key.as_str())
|
|
||||||
.expect("template contains all keys");
|
|
||||||
*value_ref = self
|
*value_ref = self
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
||||||
.flatten();
|
.flatten();
|
||||||
@ -2313,7 +2293,7 @@ impl Engine {
|
|||||||
Expr::FnCall(x, pos) => {
|
Expr::FnCall(x, pos) => {
|
||||||
let FnCallExpr {
|
let FnCallExpr {
|
||||||
name,
|
name,
|
||||||
capture,
|
capture_parent_scope: capture,
|
||||||
hashes,
|
hashes,
|
||||||
args,
|
args,
|
||||||
constants,
|
constants,
|
||||||
@ -2356,14 +2336,8 @@ impl Engine {
|
|||||||
|
|
||||||
Expr::Custom(custom, _) => {
|
Expr::Custom(custom, _) => {
|
||||||
let expressions: StaticVec<_> = custom.inputs.iter().map(Into::into).collect();
|
let expressions: StaticVec<_> = custom.inputs.iter().map(Into::into).collect();
|
||||||
let key_token = custom
|
let key_token = custom.tokens.first().expect("not empty");
|
||||||
.tokens
|
let custom_def = self.custom_syntax.get(key_token).expect("must match");
|
||||||
.first()
|
|
||||||
.expect("custom syntax stream contains at least one token");
|
|
||||||
let custom_def = self
|
|
||||||
.custom_syntax
|
|
||||||
.get(key_token)
|
|
||||||
.expect("custom syntax leading token matches with definition");
|
|
||||||
let mut context = EvalContext {
|
let mut context = EvalContext {
|
||||||
engine: self,
|
engine: self,
|
||||||
scope,
|
scope,
|
||||||
@ -2497,7 +2471,7 @@ impl Engine {
|
|||||||
let target_is_shared = false;
|
let target_is_shared = false;
|
||||||
|
|
||||||
if target_is_shared {
|
if target_is_shared {
|
||||||
lock_guard = target.write_lock::<Dynamic>().expect("cast to `Dynamic`");
|
lock_guard = target.write_lock::<Dynamic>().expect("`Dynamic`");
|
||||||
lhs_ptr_inner = &mut *lock_guard;
|
lhs_ptr_inner = &mut *lock_guard;
|
||||||
} else {
|
} else {
|
||||||
lhs_ptr_inner = &mut *target;
|
lhs_ptr_inner = &mut *target;
|
||||||
@ -2567,9 +2541,7 @@ impl Engine {
|
|||||||
let (mut lhs_ptr, pos) =
|
let (mut lhs_ptr, pos) =
|
||||||
self.search_namespace(scope, mods, state, lib, this_ptr, lhs_expr)?;
|
self.search_namespace(scope, mods, state, lib, this_ptr, lhs_expr)?;
|
||||||
|
|
||||||
let var_name = lhs_expr
|
let var_name = lhs_expr.get_variable_name(false).expect("`Variable`");
|
||||||
.get_variable_name(false)
|
|
||||||
.expect("`lhs_ptr` is `Variable`");
|
|
||||||
|
|
||||||
if !lhs_ptr.is_ref() {
|
if !lhs_ptr.is_ref() {
|
||||||
return Err(EvalAltResult::ErrorAssignmentToConstant(
|
return Err(EvalAltResult::ErrorAssignmentToConstant(
|
||||||
@ -2829,7 +2801,7 @@ impl Engine {
|
|||||||
if x > INT::MAX as usize {
|
if x > INT::MAX as usize {
|
||||||
return Err(EvalAltResult::ErrorArithmetic(
|
return Err(EvalAltResult::ErrorArithmetic(
|
||||||
format!("for-loop counter overflow: {}", x),
|
format!("for-loop counter overflow: {}", x),
|
||||||
counter.as_ref().expect("`counter` is `Some`").pos,
|
counter.as_ref().expect("`Some`").pos,
|
||||||
)
|
)
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
@ -2837,7 +2809,7 @@ impl Engine {
|
|||||||
let mut counter_var = scope
|
let mut counter_var = scope
|
||||||
.get_mut_by_index(c)
|
.get_mut_by_index(c)
|
||||||
.write_lock::<INT>()
|
.write_lock::<INT>()
|
||||||
.expect("counter holds `INT`");
|
.expect("`INT`");
|
||||||
*counter_var = x as INT;
|
*counter_var = x as INT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2850,7 +2822,7 @@ impl Engine {
|
|||||||
let loop_var_is_shared = false;
|
let loop_var_is_shared = false;
|
||||||
|
|
||||||
if loop_var_is_shared {
|
if loop_var_is_shared {
|
||||||
let mut value_ref = loop_var.write_lock().expect("cast to `Dynamic`");
|
let mut value_ref = loop_var.write_lock().expect("`Dynamic`");
|
||||||
*value_ref = value;
|
*value_ref = value;
|
||||||
} else {
|
} else {
|
||||||
*loop_var = value;
|
*loop_var = value;
|
||||||
@ -2911,7 +2883,7 @@ impl Engine {
|
|||||||
Stmt::FnCall(x, pos) => {
|
Stmt::FnCall(x, pos) => {
|
||||||
let FnCallExpr {
|
let FnCallExpr {
|
||||||
name,
|
name,
|
||||||
capture,
|
capture_parent_scope: capture,
|
||||||
hashes,
|
hashes,
|
||||||
args,
|
args,
|
||||||
constants,
|
constants,
|
||||||
@ -2958,16 +2930,11 @@ impl Engine {
|
|||||||
if err_pos.is_none() {
|
if err_pos.is_none() {
|
||||||
// No position info
|
// No position info
|
||||||
} else {
|
} else {
|
||||||
let line = err_pos
|
let line = err_pos.line().expect("line number") as INT;
|
||||||
.line()
|
|
||||||
.expect("non-NONE `Position` has line number")
|
|
||||||
as INT;
|
|
||||||
let position = if err_pos.is_beginning_of_line() {
|
let position = if err_pos.is_beginning_of_line() {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
err_pos
|
err_pos.position().expect("character position")
|
||||||
.position()
|
|
||||||
.expect("non-NONE `Position` has character position")
|
|
||||||
} as INT;
|
} as INT;
|
||||||
err_map.insert("line".into(), line.into());
|
err_map.insert("line".into(), line.into());
|
||||||
err_map.insert("position".into(), position.into());
|
err_map.insert("position".into(), position.into());
|
||||||
|
@ -25,20 +25,13 @@ impl Engine {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) fn global_namespace(&self) -> &Module {
|
pub(crate) fn global_namespace(&self) -> &Module {
|
||||||
self.global_modules
|
self.global_modules.first().expect("not empty")
|
||||||
.first()
|
|
||||||
.expect("global_modules not empty")
|
|
||||||
}
|
}
|
||||||
/// Get a mutable reference to the global namespace module
|
/// Get a mutable reference to the global namespace module
|
||||||
/// (which is the first module in `global_modules`).
|
/// (which is the first module in `global_modules`).
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn global_namespace_mut(&mut self) -> &mut Module {
|
pub(crate) fn global_namespace_mut(&mut self) -> &mut Module {
|
||||||
Shared::get_mut(
|
Shared::get_mut(self.global_modules.first_mut().expect("not empty")).expect("not shared")
|
||||||
self.global_modules
|
|
||||||
.first_mut()
|
|
||||||
.expect("global_modules not empty"),
|
|
||||||
)
|
|
||||||
.expect("global namespace never shared")
|
|
||||||
}
|
}
|
||||||
/// Register a custom function with the [`Engine`].
|
/// Register a custom function with the [`Engine`].
|
||||||
///
|
///
|
||||||
@ -957,8 +950,8 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut iter = name.as_ref().splitn(2, separator.as_ref());
|
let mut iter = name.as_ref().splitn(2, separator.as_ref());
|
||||||
let sub_module = iter.next().expect("name contains separator").trim();
|
let sub_module = iter.next().expect("contains separator").trim();
|
||||||
let remainder = iter.next().expect("name contains separator").trim();
|
let remainder = iter.next().expect("contains separator").trim();
|
||||||
|
|
||||||
if !root.contains_key(sub_module) {
|
if !root.contains_key(sub_module) {
|
||||||
let mut m = Module::new();
|
let mut m = Module::new();
|
||||||
@ -966,9 +959,7 @@ impl Engine {
|
|||||||
m.build_index();
|
m.build_index();
|
||||||
root.insert(sub_module.into(), m.into());
|
root.insert(sub_module.into(), m.into());
|
||||||
} else {
|
} else {
|
||||||
let m = root
|
let m = root.remove(sub_module).expect("contains sub-module");
|
||||||
.remove(sub_module)
|
|
||||||
.expect("root contains the sub-module");
|
|
||||||
let mut m = crate::fn_native::shared_take_or_clone(m);
|
let mut m = crate::fn_native::shared_take_or_clone(m);
|
||||||
register_static_module_raw(m.sub_modules_mut(), remainder, module);
|
register_static_module_raw(m.sub_modules_mut(), remainder, module);
|
||||||
m.build_index();
|
m.build_index();
|
||||||
@ -1073,7 +1064,7 @@ impl Engine {
|
|||||||
imports: &mut BTreeSet<Identifier>,
|
imports: &mut BTreeSet<Identifier>,
|
||||||
) {
|
) {
|
||||||
ast.walk(
|
ast.walk(
|
||||||
&mut |path| match path.last().expect("`path` contains the current node") {
|
&mut |path| match path.last().expect("contains current node") {
|
||||||
// Collect all `import` statements with a string constant path
|
// Collect all `import` statements with a string constant path
|
||||||
ASTNode::Stmt(Stmt::Import(Expr::StringConstant(s, _), _, _))
|
ASTNode::Stmt(Stmt::Import(Expr::StringConstant(s, _), _, _))
|
||||||
if !resolver.contains_path(s) && !imports.contains(s.as_str()) =>
|
if !resolver.contains_path(s) && !imports.contains(s.as_str()) =>
|
||||||
|
@ -255,7 +255,7 @@ impl Engine {
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
let (first_arg, rest_args) =
|
let (first_arg, rest_args) =
|
||||||
args.split_first().expect("has two arguments");
|
args.split_first().expect("two arguments");
|
||||||
|
|
||||||
get_builtin_op_assignment_fn(fn_name, *first_arg, rest_args[0])
|
get_builtin_op_assignment_fn(fn_name, *first_arg, rest_args[0])
|
||||||
.map(|f| FnResolutionCacheEntry {
|
.map(|f| FnResolutionCacheEntry {
|
||||||
@ -273,7 +273,7 @@ impl Engine {
|
|||||||
None => {
|
None => {
|
||||||
let hash_params = calc_fn_params_hash(
|
let hash_params = calc_fn_params_hash(
|
||||||
args.as_ref()
|
args.as_ref()
|
||||||
.expect("no permutations if no arguments")
|
.expect("no permutations")
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, a)| {
|
.map(|(i, a)| {
|
||||||
@ -333,7 +333,7 @@ impl Engine {
|
|||||||
backup = Some(ArgBackup::new());
|
backup = Some(ArgBackup::new());
|
||||||
backup
|
backup
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.expect("`backup` is `Some`")
|
.expect("`Some`")
|
||||||
.change_first_arg_to_copy(args);
|
.change_first_arg_to_copy(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -680,10 +680,8 @@ impl Engine {
|
|||||||
crate::engine::KEYWORD_IS_DEF_FN
|
crate::engine::KEYWORD_IS_DEF_FN
|
||||||
if args.len() == 2 && args[0].is::<FnPtr>() && args[1].is::<crate::INT>() =>
|
if args.len() == 2 && args[0].is::<FnPtr>() && args[1].is::<crate::INT>() =>
|
||||||
{
|
{
|
||||||
let fn_name = args[0]
|
let fn_name = args[0].read_lock::<ImmutableString>().expect("`FnPtr`");
|
||||||
.read_lock::<ImmutableString>()
|
let num_params = args[1].as_int().expect("`INT`");
|
||||||
.expect("`args[0]` is `FnPtr`");
|
|
||||||
let num_params = args[1].as_int().expect("`args[1]` is `INT`");
|
|
||||||
|
|
||||||
return Ok((
|
return Ok((
|
||||||
if num_params < 0 {
|
if num_params < 0 {
|
||||||
@ -736,7 +734,7 @@ impl Engine {
|
|||||||
|
|
||||||
let result = if _is_method_call {
|
let result = if _is_method_call {
|
||||||
// Method call of script function - map first argument to `this`
|
// Method call of script function - map first argument to `this`
|
||||||
let (first_arg, rest_args) = args.split_first_mut().expect("has arguments");
|
let (first_arg, rest_args) = args.split_first_mut().expect("not empty");
|
||||||
|
|
||||||
let orig_source = mods.source.take();
|
let orig_source = mods.source.take();
|
||||||
mods.source = source;
|
mods.source = source;
|
||||||
@ -767,7 +765,7 @@ impl Engine {
|
|||||||
backup = Some(ArgBackup::new());
|
backup = Some(ArgBackup::new());
|
||||||
backup
|
backup
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.expect("`backup` is `Some`")
|
.expect("`Some`")
|
||||||
.change_first_arg_to_copy(args);
|
.change_first_arg_to_copy(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -883,7 +881,7 @@ impl Engine {
|
|||||||
let (result, updated) = match fn_name {
|
let (result, updated) = match fn_name {
|
||||||
KEYWORD_FN_PTR_CALL if target.is::<FnPtr>() => {
|
KEYWORD_FN_PTR_CALL if target.is::<FnPtr>() => {
|
||||||
// FnPtr call
|
// FnPtr call
|
||||||
let fn_ptr = target.read_lock::<FnPtr>().expect("`obj` is `FnPtr`");
|
let fn_ptr = target.read_lock::<FnPtr>().expect("`FnPtr`");
|
||||||
// Redirect function name
|
// Redirect function name
|
||||||
let fn_name = fn_ptr.fn_name();
|
let fn_name = fn_ptr.fn_name();
|
||||||
let args_len = call_args.len() + fn_ptr.curry().len();
|
let args_len = call_args.len() + fn_ptr.curry().len();
|
||||||
@ -948,7 +946,7 @@ impl Engine {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let fn_ptr = target.read_lock::<FnPtr>().expect("`obj` is `FnPtr`");
|
let fn_ptr = target.read_lock::<FnPtr>().expect("`FnPtr`");
|
||||||
|
|
||||||
// Curry call
|
// Curry call
|
||||||
Ok((
|
Ok((
|
||||||
@ -1243,7 +1241,7 @@ impl Engine {
|
|||||||
// avoid cloning the value
|
// avoid cloning the value
|
||||||
if curry.is_empty() && !args_expr.is_empty() && args_expr[0].is_variable_access(false) {
|
if curry.is_empty() && !args_expr.is_empty() && args_expr[0].is_variable_access(false) {
|
||||||
// func(x, ...) -> x.func(...)
|
// func(x, ...) -> x.func(...)
|
||||||
let (first_expr, rest_expr) = args_expr.split_first().expect("has arguments");
|
let (first_expr, rest_expr) = args_expr.split_first().expect("not empty");
|
||||||
|
|
||||||
for index in 0..rest_expr.len() {
|
for index in 0..rest_expr.len() {
|
||||||
let (value, _) = self.get_arg_value(
|
let (value, _) = self.get_arg_value(
|
||||||
@ -1273,7 +1271,7 @@ impl Engine {
|
|||||||
} else {
|
} else {
|
||||||
// Turn it into a method call only if the object is not shared and not a simple value
|
// Turn it into a method call only if the object is not shared and not a simple value
|
||||||
is_ref_mut = true;
|
is_ref_mut = true;
|
||||||
let obj_ref = target.take_ref().expect("`target` is reference");
|
let obj_ref = target.take_ref().expect("reference");
|
||||||
args.push(obj_ref);
|
args.push(obj_ref);
|
||||||
args.extend(arg_values.iter_mut());
|
args.extend(arg_values.iter_mut());
|
||||||
}
|
}
|
||||||
@ -1352,9 +1350,9 @@ impl Engine {
|
|||||||
args.extend(arg_values.iter_mut());
|
args.extend(arg_values.iter_mut());
|
||||||
} else {
|
} else {
|
||||||
// Turn it into a method call only if the object is not shared and not a simple value
|
// Turn it into a method call only if the object is not shared and not a simple value
|
||||||
let (first, rest) = arg_values.split_first_mut().expect("has arguments");
|
let (first, rest) = arg_values.split_first_mut().expect("not empty");
|
||||||
first_arg_value = Some(first);
|
first_arg_value = Some(first);
|
||||||
let obj_ref = target.take_ref().expect("`target` is reference");
|
let obj_ref = target.take_ref().expect("reference");
|
||||||
args.push(obj_ref);
|
args.push(obj_ref);
|
||||||
args.extend(rest.iter_mut());
|
args.extend(rest.iter_mut());
|
||||||
}
|
}
|
||||||
|
@ -298,9 +298,7 @@ pub fn shared_try_take<T>(value: Shared<T>) -> Result<T, Shared<T>> {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn shared_take<T>(value: Shared<T>) -> T {
|
pub fn shared_take<T>(value: Shared<T>) -> T {
|
||||||
shared_try_take(value)
|
shared_try_take(value).ok().expect("not shared")
|
||||||
.ok()
|
|
||||||
.expect("no outstanding references")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lock a [`Shared`] resource.
|
/// Lock a [`Shared`] resource.
|
||||||
|
@ -34,7 +34,7 @@ pub struct Mut<T>(T);
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn by_ref<T: Variant + Clone>(data: &mut Dynamic) -> DynamicWriteLock<T> {
|
pub fn by_ref<T: Variant + Clone>(data: &mut Dynamic) -> DynamicWriteLock<T> {
|
||||||
// Directly cast the &mut Dynamic into DynamicWriteLock to access the underlying data.
|
// Directly cast the &mut Dynamic into DynamicWriteLock to access the underlying data.
|
||||||
data.write_lock::<T>().expect("data type was checked")
|
data.write_lock::<T>().expect("checked")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dereference into value.
|
/// Dereference into value.
|
||||||
@ -44,15 +44,13 @@ pub fn by_value<T: Variant + Clone>(data: &mut Dynamic) -> T {
|
|||||||
if TypeId::of::<T>() == TypeId::of::<&str>() {
|
if TypeId::of::<T>() == TypeId::of::<&str>() {
|
||||||
// If T is `&str`, data must be `ImmutableString`, so map directly to it
|
// If T is `&str`, data must be `ImmutableString`, so map directly to it
|
||||||
data.flatten_in_place();
|
data.flatten_in_place();
|
||||||
let ref_str = data.as_str_ref().expect("argument type is &str");
|
let ref_str = data.as_str_ref().expect("&str");
|
||||||
let ref_t = unsafe { mem::transmute::<_, &T>(&ref_str) };
|
let ref_t = unsafe { mem::transmute::<_, &T>(&ref_str) };
|
||||||
ref_t.clone()
|
ref_t.clone()
|
||||||
} else if TypeId::of::<T>() == TypeId::of::<String>() {
|
} else if TypeId::of::<T>() == TypeId::of::<String>() {
|
||||||
// If T is `String`, data must be `ImmutableString`, so map directly to it
|
// If T is `String`, data must be `ImmutableString`, so map directly to it
|
||||||
let value = mem::take(data)
|
let value = mem::take(data).into_string().expect("`ImmutableString`");
|
||||||
.into_string()
|
unsafe_try_cast(value).expect("checked")
|
||||||
.expect("data type was checked");
|
|
||||||
unsafe_try_cast(value).expect("data type was checked")
|
|
||||||
} else {
|
} else {
|
||||||
// We consume the argument and then replace it with () - the argument is not supposed to be used again.
|
// We consume the argument and then replace it with () - the argument is not supposed to be used again.
|
||||||
// This way, we avoid having to clone the argument again, because it is already a clone when passed here.
|
// This way, we avoid having to clone the argument again, because it is already a clone when passed here.
|
||||||
@ -99,6 +97,8 @@ fn is_setter(_fn_name: &str) -> bool {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const EXPECT_ARGS: &str = "arguments";
|
||||||
|
|
||||||
macro_rules! def_register {
|
macro_rules! def_register {
|
||||||
() => {
|
() => {
|
||||||
def_register!(imp from_pure :);
|
def_register!(imp from_pure :);
|
||||||
@ -128,7 +128,7 @@ macro_rules! def_register {
|
|||||||
|
|
||||||
// The arguments are assumed to be of the correct number and types!
|
// The arguments are assumed to be of the correct number and types!
|
||||||
let mut _drain = args.iter_mut();
|
let mut _drain = args.iter_mut();
|
||||||
$($let $par = ($clone)(_drain.next().expect("arguments list is fixed")); )*
|
$($let $par = ($clone)(_drain.next().expect(EXPECT_ARGS)); )*
|
||||||
|
|
||||||
// Call the function with each argument value
|
// Call the function with each argument value
|
||||||
let r = self($($arg),*);
|
let r = self($($arg),*);
|
||||||
@ -156,7 +156,7 @@ macro_rules! def_register {
|
|||||||
|
|
||||||
// The arguments are assumed to be of the correct number and types!
|
// The arguments are assumed to be of the correct number and types!
|
||||||
let mut _drain = args.iter_mut();
|
let mut _drain = args.iter_mut();
|
||||||
$($let $par = ($clone)(_drain.next().expect("arguments list is fixed")); )*
|
$($let $par = ($clone)(_drain.next().expect(EXPECT_ARGS)); )*
|
||||||
|
|
||||||
// Call the function with each argument value
|
// Call the function with each argument value
|
||||||
let r = self(ctx, $($arg),*);
|
let r = self(ctx, $($arg),*);
|
||||||
@ -184,7 +184,7 @@ macro_rules! def_register {
|
|||||||
|
|
||||||
// The arguments are assumed to be of the correct number and types!
|
// The arguments are assumed to be of the correct number and types!
|
||||||
let mut _drain = args.iter_mut();
|
let mut _drain = args.iter_mut();
|
||||||
$($let $par = ($clone)(_drain.next().expect("arguments list is fixed")); )*
|
$($let $par = ($clone)(_drain.next().expect(EXPECT_ARGS)); )*
|
||||||
|
|
||||||
// Call the function with each argument value
|
// Call the function with each argument value
|
||||||
self($($arg),*).map(Dynamic::from)
|
self($($arg),*).map(Dynamic::from)
|
||||||
@ -209,7 +209,7 @@ macro_rules! def_register {
|
|||||||
|
|
||||||
// The arguments are assumed to be of the correct number and types!
|
// The arguments are assumed to be of the correct number and types!
|
||||||
let mut _drain = args.iter_mut();
|
let mut _drain = args.iter_mut();
|
||||||
$($let $par = ($clone)(_drain.next().expect("arguments list is fixed")); )*
|
$($let $par = ($clone)(_drain.next().expect(EXPECT_ARGS)); )*
|
||||||
|
|
||||||
// Call the function with each argument value
|
// Call the function with each argument value
|
||||||
self(ctx, $($arg),*).map(Dynamic::from)
|
self(ctx, $($arg),*).map(Dynamic::from)
|
||||||
|
@ -1426,7 +1426,7 @@ impl Module {
|
|||||||
match aliases.len() {
|
match aliases.len() {
|
||||||
0 => (),
|
0 => (),
|
||||||
1 => {
|
1 => {
|
||||||
let alias = aliases.pop().expect("list has one item");
|
let alias = aliases.pop().expect("not empty");
|
||||||
module.set_var(alias, value);
|
module.set_var(alias, value);
|
||||||
}
|
}
|
||||||
_ => aliases.into_iter().for_each(|alias| {
|
_ => aliases.into_iter().for_each(|alias| {
|
||||||
|
@ -288,23 +288,18 @@ fn optimize_stmt_block(
|
|||||||
&& !last_stmt.returns_value() =>
|
&& !last_stmt.returns_value() =>
|
||||||
{
|
{
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
statements
|
statements.pop().expect(">= 2 elements");
|
||||||
.pop()
|
|
||||||
.expect("`statements` contains at least two elements");
|
|
||||||
}
|
}
|
||||||
// { ...; return val; } -> { ...; val }
|
// { ...; return val; } -> { ...; val }
|
||||||
[.., Stmt::Return(options, ref mut expr, pos)]
|
[.., Stmt::Return(options, ref mut expr, pos)]
|
||||||
if reduce_return && !options.contains(AST_OPTION_BREAK_OUT) =>
|
if reduce_return && !options.contains(AST_OPTION_BREAK_OUT) =>
|
||||||
{
|
{
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*statements
|
*statements.last_mut().expect(">= 2 elements") = if let Some(expr) = expr {
|
||||||
.last_mut()
|
Stmt::Expr(mem::take(expr))
|
||||||
.expect("`statements` contains at least two elements") =
|
} else {
|
||||||
if let Some(expr) = expr {
|
Stmt::Noop(pos)
|
||||||
Stmt::Expr(mem::take(expr))
|
};
|
||||||
} else {
|
|
||||||
Stmt::Noop(pos)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
// { ...; stmt; noop } -> done
|
// { ...; stmt; noop } -> done
|
||||||
[.., ref second_last_stmt, Stmt::Noop(_)]
|
[.., ref second_last_stmt, Stmt::Noop(_)]
|
||||||
@ -319,14 +314,10 @@ fn optimize_stmt_block(
|
|||||||
{
|
{
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
if second_last_stmt.returns_value() {
|
if second_last_stmt.returns_value() {
|
||||||
*statements
|
*statements.last_mut().expect(">= 2 elements") =
|
||||||
.last_mut()
|
|
||||||
.expect("`statements` contains at least two elements") =
|
|
||||||
Stmt::Noop(last_stmt.position());
|
Stmt::Noop(last_stmt.position());
|
||||||
} else {
|
} else {
|
||||||
statements
|
statements.pop().expect(">= 2 elements");
|
||||||
.pop()
|
|
||||||
.expect("`statements` contains at least two elements");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => break,
|
_ => break,
|
||||||
@ -344,9 +335,7 @@ fn optimize_stmt_block(
|
|||||||
if reduce_return && !options.contains(AST_OPTION_BREAK_OUT) =>
|
if reduce_return && !options.contains(AST_OPTION_BREAK_OUT) =>
|
||||||
{
|
{
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
statements
|
statements.pop().expect(">= 2 elements");
|
||||||
.pop()
|
|
||||||
.expect("`statements` contains at least two elements");
|
|
||||||
}
|
}
|
||||||
// { ...; return pure_val; } -> { ... }
|
// { ...; return pure_val; } -> { ... }
|
||||||
[.., Stmt::Return(options, Some(ref expr), _)]
|
[.., Stmt::Return(options, Some(ref expr), _)]
|
||||||
@ -355,15 +344,11 @@ fn optimize_stmt_block(
|
|||||||
&& expr.is_pure() =>
|
&& expr.is_pure() =>
|
||||||
{
|
{
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
statements
|
statements.pop().expect(">= 2 elements");
|
||||||
.pop()
|
|
||||||
.expect("`statements` contains at least two elements");
|
|
||||||
}
|
}
|
||||||
[.., ref last_stmt] if is_pure(last_stmt) => {
|
[.., ref last_stmt] if is_pure(last_stmt) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
statements
|
statements.pop().expect("not empty");
|
||||||
.pop()
|
|
||||||
.expect("`statements` contains at least one element");
|
|
||||||
}
|
}
|
||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
@ -405,18 +390,14 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
match x.2 {
|
match x.2 {
|
||||||
Expr::FnCall(ref mut x2, _) => {
|
Expr::FnCall(ref mut x2, _) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
let op = Token::lookup_from_syntax(&x2.name).expect("`x2` is operator");
|
let op = Token::lookup_from_syntax(&x2.name).expect("operator");
|
||||||
let op_assignment = op.make_op_assignment().expect("`op` is operator");
|
let op_assignment = op.make_op_assignment().expect("operator");
|
||||||
x.1 = Some(OpAssignment::new(op_assignment));
|
x.1 = Some(OpAssignment::new(op_assignment));
|
||||||
|
|
||||||
let value = mem::take(&mut x2.args[1]);
|
let value = mem::take(&mut x2.args[1]);
|
||||||
|
|
||||||
if let Expr::Stack(slot, pos) = value {
|
if let Expr::Stack(slot, pos) = value {
|
||||||
let value = mem::take(
|
let value = mem::take(x2.constants.get_mut(slot).expect("valid slot"));
|
||||||
x2.constants
|
|
||||||
.get_mut(slot)
|
|
||||||
.expect("`constants[slot]` is valid"),
|
|
||||||
);
|
|
||||||
x.2 = Expr::from_dynamic(value, pos);
|
x.2 = Expr::from_dynamic(value, pos);
|
||||||
} else {
|
} else {
|
||||||
x.2 = value;
|
x.2 = value;
|
||||||
@ -804,13 +785,13 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
|||||||
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, _)) if *i >= 0 && (*i as usize) < s.chars().count() => {
|
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, _)) if *i >= 0 && (*i as usize) < s.chars().count() => {
|
||||||
// String literal indexing - get the character
|
// String literal indexing - get the character
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = Expr::CharConstant(s.chars().nth(*i as usize).expect("character position is valid"), *pos);
|
*expr = Expr::CharConstant(s.chars().nth(*i as usize).expect("valid index"), *pos);
|
||||||
}
|
}
|
||||||
// string[-int]
|
// string[-int]
|
||||||
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, _)) if *i < 0 && i.checked_abs().map(|n| n as usize <= s.chars().count()).unwrap_or(false) => {
|
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, _)) if *i < 0 && i.checked_abs().map(|n| n as usize <= s.chars().count()).unwrap_or(false) => {
|
||||||
// String literal indexing - get the character
|
// String literal indexing - get the character
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = Expr::CharConstant(s.chars().rev().nth(i.abs() as usize - 1).expect("character position is valid"), *pos);
|
*expr = Expr::CharConstant(s.chars().rev().nth(i.abs() as usize - 1).expect("valid index"), *pos);
|
||||||
}
|
}
|
||||||
// var[rhs]
|
// var[rhs]
|
||||||
(Expr::Variable(_, _, _), rhs) => optimize_expr(rhs, state, true),
|
(Expr::Variable(_, _, _), rhs) => optimize_expr(rhs, state, true),
|
||||||
@ -960,7 +941,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
|||||||
if fn_name.is::<ImmutableString>() {
|
if fn_name.is::<ImmutableString>() {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
let fn_ptr = FnPtr::new_unchecked(
|
let fn_ptr = FnPtr::new_unchecked(
|
||||||
fn_name.as_str_ref().expect("`fn_name` is `ImmutableString`").into(),
|
fn_name.as_str_ref().expect("`ImmutableString`").into(),
|
||||||
StaticVec::new()
|
StaticVec::new()
|
||||||
);
|
);
|
||||||
*expr = Expr::DynamicConstant(Box::new(fn_ptr.into()), *pos);
|
*expr = Expr::DynamicConstant(Box::new(fn_ptr.into()), *pos);
|
||||||
@ -1004,7 +985,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
|||||||
if let Some(result) = get_builtin_binary_op_fn(x.name.as_ref(), &arg_values[0], &arg_values[1])
|
if let Some(result) = get_builtin_binary_op_fn(x.name.as_ref(), &arg_values[0], &arg_values[1])
|
||||||
.and_then(|f| {
|
.and_then(|f| {
|
||||||
let context = (state.engine, x.name.as_ref(), state.lib).into();
|
let context = (state.engine, x.name.as_ref(), state.lib).into();
|
||||||
let (first, second) = arg_values.split_first_mut().expect("`arg_values` is not empty");
|
let (first, second) = arg_values.split_first_mut().expect("not empty");
|
||||||
(f)(context, &mut [ first, &mut second[0] ]).ok()
|
(f)(context, &mut [ first, &mut second[0] ]).ok()
|
||||||
}) {
|
}) {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
@ -1077,7 +1058,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
|||||||
// constant-name
|
// constant-name
|
||||||
Expr::Variable(_, pos, x) if x.1.is_none() && state.find_constant(&x.2).is_some() => {
|
Expr::Variable(_, pos, x) if x.1.is_none() && state.find_constant(&x.2).is_some() => {
|
||||||
// Replace constant with value
|
// Replace constant with value
|
||||||
*expr = Expr::from_dynamic(state.find_constant(&x.2).expect("constant exists").clone(), *pos);
|
*expr = Expr::from_dynamic(state.find_constant(&x.2).expect("exists").clone(), *pos);
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -849,16 +849,16 @@ mod array_functions {
|
|||||||
|
|
||||||
if type_id == TypeId::of::<INT>() {
|
if type_id == TypeId::of::<INT>() {
|
||||||
array.sort_by(|a, b| {
|
array.sort_by(|a, b| {
|
||||||
let a = a.as_int().expect("a is INT");
|
let a = a.as_int().expect("`INT`");
|
||||||
let b = b.as_int().expect("b is INT");
|
let b = b.as_int().expect("`INT`");
|
||||||
a.cmp(&b)
|
a.cmp(&b)
|
||||||
});
|
});
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if type_id == TypeId::of::<char>() {
|
if type_id == TypeId::of::<char>() {
|
||||||
array.sort_by(|a, b| {
|
array.sort_by(|a, b| {
|
||||||
let a = a.as_char().expect("a is char");
|
let a = a.as_char().expect("char");
|
||||||
let b = b.as_char().expect("b is char");
|
let b = b.as_char().expect("char");
|
||||||
a.cmp(&b)
|
a.cmp(&b)
|
||||||
});
|
});
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -866,20 +866,16 @@ mod array_functions {
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
if type_id == TypeId::of::<crate::FLOAT>() {
|
if type_id == TypeId::of::<crate::FLOAT>() {
|
||||||
array.sort_by(|a, b| {
|
array.sort_by(|a, b| {
|
||||||
let a = a.as_float().expect("a is FLOAT");
|
let a = a.as_float().expect("`FLOAT`");
|
||||||
let b = b.as_float().expect("b is FLOAT");
|
let b = b.as_float().expect("`FLOAT`");
|
||||||
a.partial_cmp(&b).unwrap_or(Ordering::Equal)
|
a.partial_cmp(&b).unwrap_or(Ordering::Equal)
|
||||||
});
|
});
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if type_id == TypeId::of::<ImmutableString>() {
|
if type_id == TypeId::of::<ImmutableString>() {
|
||||||
array.sort_by(|a, b| {
|
array.sort_by(|a, b| {
|
||||||
let a = a
|
let a = a.read_lock::<ImmutableString>().expect("`ImmutableString`");
|
||||||
.read_lock::<ImmutableString>()
|
let b = b.read_lock::<ImmutableString>().expect("`ImmutableString`");
|
||||||
.expect("a is ImmutableString");
|
|
||||||
let b = b
|
|
||||||
.read_lock::<ImmutableString>()
|
|
||||||
.expect("b is ImmutableString");
|
|
||||||
a.as_str().cmp(b.as_str())
|
a.as_str().cmp(b.as_str())
|
||||||
});
|
});
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -887,16 +883,16 @@ mod array_functions {
|
|||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
if type_id == TypeId::of::<rust_decimal::Decimal>() {
|
if type_id == TypeId::of::<rust_decimal::Decimal>() {
|
||||||
array.sort_by(|a, b| {
|
array.sort_by(|a, b| {
|
||||||
let a = a.as_decimal().expect("a is Decimal");
|
let a = a.as_decimal().expect("`Decimal`");
|
||||||
let b = b.as_decimal().expect("b is Decimal");
|
let b = b.as_decimal().expect("`Decimal`");
|
||||||
a.cmp(&b)
|
a.cmp(&b)
|
||||||
});
|
});
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if type_id == TypeId::of::<bool>() {
|
if type_id == TypeId::of::<bool>() {
|
||||||
array.sort_by(|a, b| {
|
array.sort_by(|a, b| {
|
||||||
let a = a.as_bool().expect("a is bool");
|
let a = a.as_bool().expect("`bool`");
|
||||||
let b = b.as_bool().expect("b is bool");
|
let b = b.as_bool().expect("`bool`");
|
||||||
a.cmp(&b)
|
a.cmp(&b)
|
||||||
});
|
});
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -31,9 +31,9 @@ pub fn print_with_func(
|
|||||||
value: &mut Dynamic,
|
value: &mut Dynamic,
|
||||||
) -> crate::ImmutableString {
|
) -> crate::ImmutableString {
|
||||||
match ctx.call_fn_raw(fn_name, true, false, &mut [value]) {
|
match ctx.call_fn_raw(fn_name, true, false, &mut [value]) {
|
||||||
Ok(result) if result.is::<crate::ImmutableString>() => result
|
Ok(result) if result.is::<crate::ImmutableString>() => {
|
||||||
.into_immutable_string()
|
result.into_immutable_string().expect("`ImmutableString`")
|
||||||
.expect("result is `ImmutableString`"),
|
}
|
||||||
Ok(result) => ctx.engine().map_type_name(result.type_name()).into(),
|
Ok(result) => ctx.engine().map_type_name(result.type_name()).into(),
|
||||||
Err(_) => ctx.engine().map_type_name(value.type_name()).into(),
|
Err(_) => ctx.engine().map_type_name(value.type_name()).into(),
|
||||||
}
|
}
|
||||||
|
@ -175,7 +175,7 @@ mod string_functions {
|
|||||||
#[rhai_fn(name = "to_upper")]
|
#[rhai_fn(name = "to_upper")]
|
||||||
pub fn to_upper_char(character: char) -> char {
|
pub fn to_upper_char(character: char) -> char {
|
||||||
let mut stream = character.to_uppercase();
|
let mut stream = character.to_uppercase();
|
||||||
let ch = stream.next().expect("at least one character");
|
let ch = stream.next().expect("not empty");
|
||||||
if stream.next().is_some() {
|
if stream.next().is_some() {
|
||||||
character
|
character
|
||||||
} else {
|
} else {
|
||||||
@ -189,9 +189,7 @@ mod string_functions {
|
|||||||
#[rhai_fn(name = "to_lower")]
|
#[rhai_fn(name = "to_lower")]
|
||||||
pub fn to_lower_char(character: char) -> char {
|
pub fn to_lower_char(character: char) -> char {
|
||||||
let mut stream = character.to_lowercase();
|
let mut stream = character.to_lowercase();
|
||||||
let ch = stream
|
let ch = stream.next().expect("not empty");
|
||||||
.next()
|
|
||||||
.expect("there should be at least one character");
|
|
||||||
if stream.next().is_some() {
|
if stream.next().is_some() {
|
||||||
character
|
character
|
||||||
} else {
|
} else {
|
||||||
|
28
src/parse.rs
28
src/parse.rs
@ -456,7 +456,7 @@ fn parse_fn_call(
|
|||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
id: Identifier,
|
id: Identifier,
|
||||||
capture: bool,
|
capture_parent_scope: bool,
|
||||||
namespace: Option<NamespaceRef>,
|
namespace: Option<NamespaceRef>,
|
||||||
settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
@ -503,7 +503,7 @@ fn parse_fn_call(
|
|||||||
|
|
||||||
return Ok(FnCallExpr {
|
return Ok(FnCallExpr {
|
||||||
name: state.get_identifier(id),
|
name: state.get_identifier(id),
|
||||||
capture,
|
capture_parent_scope,
|
||||||
namespace,
|
namespace,
|
||||||
hashes,
|
hashes,
|
||||||
args,
|
args,
|
||||||
@ -553,7 +553,7 @@ fn parse_fn_call(
|
|||||||
|
|
||||||
return Ok(FnCallExpr {
|
return Ok(FnCallExpr {
|
||||||
name: state.get_identifier(id),
|
name: state.get_identifier(id),
|
||||||
capture,
|
capture_parent_scope,
|
||||||
namespace,
|
namespace,
|
||||||
hashes,
|
hashes,
|
||||||
args,
|
args,
|
||||||
@ -1727,9 +1727,7 @@ fn make_dot_expr(
|
|||||||
}
|
}
|
||||||
// lhs.module::id - syntax error
|
// lhs.module::id - syntax error
|
||||||
(_, Expr::Variable(_, _, x)) => {
|
(_, Expr::Variable(_, _, x)) => {
|
||||||
return Err(
|
return Err(PERR::PropertyExpected.into_err(x.1.expect("`Some`").0[0].pos))
|
||||||
PERR::PropertyExpected.into_err(x.1.expect("the namespace is `Some`").0[0].pos)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
// lhs.prop
|
// lhs.prop
|
||||||
(lhs, prop @ Expr::Property(_)) => {
|
(lhs, prop @ Expr::Property(_)) => {
|
||||||
@ -1801,7 +1799,7 @@ fn make_dot_expr(
|
|||||||
.into_err(pos))
|
.into_err(pos))
|
||||||
}
|
}
|
||||||
// lhs.func!(...)
|
// lhs.func!(...)
|
||||||
(_, Expr::FnCall(x, pos)) if x.capture => {
|
(_, Expr::FnCall(x, pos)) if x.capture_parent_scope => {
|
||||||
return Err(PERR::MalformedCapture(
|
return Err(PERR::MalformedCapture(
|
||||||
"method-call style does not support capturing".into(),
|
"method-call style does not support capturing".into(),
|
||||||
)
|
)
|
||||||
@ -1901,7 +1899,6 @@ fn parse_binary_op(
|
|||||||
let op_base = FnCallExpr {
|
let op_base = FnCallExpr {
|
||||||
name: state.get_identifier(op.as_ref()),
|
name: state.get_identifier(op.as_ref()),
|
||||||
hashes: FnCallHashes::from_native(hash),
|
hashes: FnCallHashes::from_native(hash),
|
||||||
capture: false,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1934,8 +1931,8 @@ fn parse_binary_op(
|
|||||||
| Token::GreaterThanEqualsTo => FnCallExpr { args, ..op_base }.into_fn_call_expr(pos),
|
| Token::GreaterThanEqualsTo => FnCallExpr { args, ..op_base }.into_fn_call_expr(pos),
|
||||||
|
|
||||||
Token::Or => {
|
Token::Or => {
|
||||||
let rhs = args.pop().expect("`||` has two arguments");
|
let rhs = args.pop().expect("two arguments");
|
||||||
let current_lhs = args.pop().expect("`||` has two arguments");
|
let current_lhs = args.pop().expect("two arguments");
|
||||||
Expr::Or(
|
Expr::Or(
|
||||||
BinaryExpr {
|
BinaryExpr {
|
||||||
lhs: current_lhs.ensure_bool_expr()?,
|
lhs: current_lhs.ensure_bool_expr()?,
|
||||||
@ -1946,8 +1943,8 @@ fn parse_binary_op(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
Token::And => {
|
Token::And => {
|
||||||
let rhs = args.pop().expect("`&&` has two arguments");
|
let rhs = args.pop().expect("two arguments");
|
||||||
let current_lhs = args.pop().expect("`&&` has two arguments");
|
let current_lhs = args.pop().expect("two arguments");
|
||||||
Expr::And(
|
Expr::And(
|
||||||
BinaryExpr {
|
BinaryExpr {
|
||||||
lhs: current_lhs.ensure_bool_expr()?,
|
lhs: current_lhs.ensure_bool_expr()?,
|
||||||
@ -2423,7 +2420,7 @@ fn parse_for(
|
|||||||
},
|
},
|
||||||
counter_var.map(|name| Ident {
|
counter_var.map(|name| Ident {
|
||||||
name,
|
name,
|
||||||
pos: counter_pos.expect("`counter_var` is `Some`"),
|
pos: counter_pos.expect("`Some`"),
|
||||||
}),
|
}),
|
||||||
body.into(),
|
body.into(),
|
||||||
)),
|
)),
|
||||||
@ -2980,10 +2977,7 @@ fn parse_try_catch(
|
|||||||
|
|
||||||
if err_var.is_some() {
|
if err_var.is_some() {
|
||||||
// Remove the error variable from the stack
|
// Remove the error variable from the stack
|
||||||
state
|
state.stack.pop().expect("not empty");
|
||||||
.stack
|
|
||||||
.pop()
|
|
||||||
.expect("stack contains at least one entry");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Stmt::TryCatch(
|
Ok(Stmt::TryCatch(
|
||||||
|
@ -405,7 +405,7 @@ impl<'a> Scope<'a> {
|
|||||||
self.push(name, value);
|
self.push(name, value);
|
||||||
}
|
}
|
||||||
Some((index, AccessMode::ReadWrite)) => {
|
Some((index, AccessMode::ReadWrite)) => {
|
||||||
let value_ref = self.values.get_mut(index).expect("index is valid");
|
let value_ref = self.values.get_mut(index).expect("valid index");
|
||||||
*value_ref = Dynamic::from(value);
|
*value_ref = Dynamic::from(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -445,7 +445,7 @@ impl<'a> Scope<'a> {
|
|||||||
}
|
}
|
||||||
Some((_, AccessMode::ReadOnly)) => panic!("variable {} is constant", name.as_ref()),
|
Some((_, AccessMode::ReadOnly)) => panic!("variable {} is constant", name.as_ref()),
|
||||||
Some((index, AccessMode::ReadWrite)) => {
|
Some((index, AccessMode::ReadWrite)) => {
|
||||||
let value_ref = self.values.get_mut(index).expect("index is valid");
|
let value_ref = self.values.get_mut(index).expect("valid index");
|
||||||
*value_ref = Dynamic::from(value);
|
*value_ref = Dynamic::from(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -491,7 +491,7 @@ impl<'a> Scope<'a> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn get_mut_by_index(&mut self, index: usize) -> &mut Dynamic {
|
pub(crate) fn get_mut_by_index(&mut self, index: usize) -> &mut Dynamic {
|
||||||
self.values.get_mut(index).expect("index is out of bounds")
|
self.values.get_mut(index).expect("valid index")
|
||||||
}
|
}
|
||||||
/// Update the access type of an entry in the [`Scope`].
|
/// Update the access type of an entry in the [`Scope`].
|
||||||
///
|
///
|
||||||
@ -501,7 +501,7 @@ impl<'a> Scope<'a> {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn add_entry_alias(&mut self, index: usize, alias: Identifier) -> &mut Self {
|
pub(crate) fn add_entry_alias(&mut self, index: usize, alias: Identifier) -> &mut Self {
|
||||||
let (_, aliases) = self.names.get_mut(index).expect("index is out of bounds");
|
let (_, aliases) = self.names.get_mut(index).expect("valid index");
|
||||||
match aliases {
|
match aliases {
|
||||||
None => {
|
None => {
|
||||||
let mut list = StaticVec::new();
|
let mut list = StaticVec::new();
|
||||||
|
@ -568,7 +568,7 @@ where
|
|||||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
// Deserialize each value item coming out of the iterator.
|
// Deserialize each value item coming out of the iterator.
|
||||||
seed.deserialize(&mut DynamicDeserializer::from_dynamic(
|
seed.deserialize(&mut DynamicDeserializer::from_dynamic(
|
||||||
self.values.next().expect("value should exist"),
|
self.values.next().expect("exists"),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,27 +53,21 @@ struct FnParam {
|
|||||||
|
|
||||||
impl PartialOrd for FnParam {
|
impl PartialOrd for FnParam {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
Some(
|
Some(match self.name.partial_cmp(&other.name).expect("succeed") {
|
||||||
match self
|
Ordering::Less => Ordering::Less,
|
||||||
.name
|
Ordering::Greater => Ordering::Greater,
|
||||||
.partial_cmp(&other.name)
|
Ordering::Equal => match (self.typ.is_none(), other.typ.is_none()) {
|
||||||
.expect("String::partial_cmp should succeed")
|
(true, true) => Ordering::Equal,
|
||||||
{
|
(true, false) => Ordering::Greater,
|
||||||
Ordering::Less => Ordering::Less,
|
(false, true) => Ordering::Less,
|
||||||
Ordering::Greater => Ordering::Greater,
|
(false, false) => self
|
||||||
Ordering::Equal => match (self.typ.is_none(), other.typ.is_none()) {
|
.typ
|
||||||
(true, true) => Ordering::Equal,
|
.as_ref()
|
||||||
(true, false) => Ordering::Greater,
|
.expect("`Some`")
|
||||||
(false, true) => Ordering::Less,
|
.partial_cmp(other.typ.as_ref().expect("`Some`"))
|
||||||
(false, false) => self
|
.expect("succeed"),
|
||||||
.typ
|
|
||||||
.as_ref()
|
|
||||||
.expect("`typ` is not `None`")
|
|
||||||
.partial_cmp(other.typ.as_ref().expect("`typ` is not `None`"))
|
|
||||||
.expect("String::partial_cmp should succeed"),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
23
src/token.rs
23
src/token.rs
@ -1223,9 +1223,7 @@ pub fn parse_string_literal(
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_position"))]
|
#[cfg(not(feature = "no_position"))]
|
||||||
{
|
{
|
||||||
let start_position = start
|
let start_position = start.position().expect("start position");
|
||||||
.position()
|
|
||||||
.expect("string must have starting position");
|
|
||||||
skip_whitespace_until = start_position + 1;
|
skip_whitespace_until = start_position + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1247,8 +1245,7 @@ pub fn parse_string_literal(
|
|||||||
// Whitespace to skip
|
// Whitespace to skip
|
||||||
#[cfg(not(feature = "no_position"))]
|
#[cfg(not(feature = "no_position"))]
|
||||||
_ if next_char.is_whitespace()
|
_ if next_char.is_whitespace()
|
||||||
&& pos.position().expect("character must have position")
|
&& pos.position().expect("position") < skip_whitespace_until => {}
|
||||||
< skip_whitespace_until => {}
|
|
||||||
|
|
||||||
// All other characters
|
// All other characters
|
||||||
_ => {
|
_ => {
|
||||||
@ -1395,14 +1392,10 @@ fn get_next_token_inner(
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
let return_comment =
|
let return_comment = return_comment || is_doc_comment(comment.as_ref().expect("`Some`"));
|
||||||
return_comment || is_doc_comment(comment.as_ref().expect("`include_comments` is true"));
|
|
||||||
|
|
||||||
if return_comment {
|
if return_comment {
|
||||||
return Some((
|
return Some((Token::Comment(comment.expect("`Some`").into()), start_pos));
|
||||||
Token::Comment(comment.expect("`return_comment` is true").into()),
|
|
||||||
start_pos,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
if state.comment_level > 0 {
|
if state.comment_level > 0 {
|
||||||
// Reached EOF without ending comment block
|
// Reached EOF without ending comment block
|
||||||
@ -1452,7 +1445,7 @@ fn get_next_token_inner(
|
|||||||
}
|
}
|
||||||
#[cfg(any(not(feature = "no_float"), feature = "decimal"))]
|
#[cfg(any(not(feature = "no_float"), feature = "decimal"))]
|
||||||
'.' => {
|
'.' => {
|
||||||
stream.get_next().expect("it is `.`");
|
stream.get_next().expect("`.`");
|
||||||
|
|
||||||
// Check if followed by digits or something that cannot start a property name
|
// Check if followed by digits or something that cannot start a property name
|
||||||
match stream.peek_next().unwrap_or('\0') {
|
match stream.peek_next().unwrap_or('\0') {
|
||||||
@ -1486,7 +1479,7 @@ fn get_next_token_inner(
|
|||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
'e' => {
|
'e' => {
|
||||||
stream.get_next().expect("it is `e`");
|
stream.get_next().expect("`e`");
|
||||||
|
|
||||||
// Check if followed by digits or +/-
|
// Check if followed by digits or +/-
|
||||||
match stream.peek_next().unwrap_or('\0') {
|
match stream.peek_next().unwrap_or('\0') {
|
||||||
@ -1499,7 +1492,7 @@ fn get_next_token_inner(
|
|||||||
'+' | '-' => {
|
'+' | '-' => {
|
||||||
result.push(next_char);
|
result.push(next_char);
|
||||||
pos.advance();
|
pos.advance();
|
||||||
result.push(stream.get_next().expect("it is `+` or `-`"));
|
result.push(stream.get_next().expect("`+` or `-`"));
|
||||||
pos.advance();
|
pos.advance();
|
||||||
}
|
}
|
||||||
// Not a floating-point number
|
// Not a floating-point number
|
||||||
@ -1647,7 +1640,7 @@ fn get_next_token_inner(
|
|||||||
|(err, err_pos)| (Token::LexError(err), err_pos),
|
|(err, err_pos)| (Token::LexError(err), err_pos),
|
||||||
|(result, _)| {
|
|(result, _)| {
|
||||||
let mut chars = result.chars();
|
let mut chars = result.chars();
|
||||||
let first = chars.next().expect("`chars` is not empty");
|
let first = chars.next().expect("not empty");
|
||||||
|
|
||||||
if chars.next().is_some() {
|
if chars.next().is_some() {
|
||||||
(
|
(
|
||||||
|
Loading…
Reference in New Issue
Block a user