Skip to content

Commit 4fd828d

Browse files
committed
Don't define namespace under no_module.
1 parent 1cf5efc commit 4fd828d

11 files changed

Lines changed: 226 additions & 183 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ Rhai Release Notes
44
Version 1.18.0
55
==============
66

7+
Bug fixes
8+
---------
9+
10+
* The position of an undefined operation call now points to the operator instead of the first operand.
11+
712
Deprecated API's
813
----------------
914

‎src/api/custom_syntax.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ impl Expression<'_> {
106106
pub fn get_string_value(&self) -> Option<&str> {
107107
match self.0 {
108108
#[cfg(not(feature = "no_module"))]
109-
Expr::Variable(x, ..) if !x.1.is_empty() => None,
110-
Expr::Variable(x, ..) => Some(&x.3),
109+
Expr::Variable(x, ..) if !x.2.is_empty() => None,
110+
Expr::Variable(x, ..) => Some(&x.1),
111111
#[cfg(not(feature = "no_function"))]
112112
Expr::ThisPtr(..) => Some(crate::engine::KEYWORD_THIS),
113113
Expr::StringConstant(x, ..) => Some(x),
@@ -138,7 +138,7 @@ impl Expression<'_> {
138138

139139
Expr::CharConstant(x, ..) => reify! { *x => Option<T> },
140140
Expr::StringConstant(x, ..) => reify! { x.clone() => Option<T> },
141-
Expr::Variable(x, ..) => reify! { x.3.clone() => Option<T> },
141+
Expr::Variable(x, ..) => reify! { x.1.clone() => Option<T> },
142142
Expr::BoolConstant(x, ..) => reify! { *x => Option<T> },
143143
Expr::Unit(..) => reify! { () => Option<T> },
144144

‎src/ast/expr.rs‎

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Module defining script expressions.
22
3-
use super::{ASTFlags, ASTNode, Ident, Namespace, Stmt, StmtBlock};
3+
use super::{ASTFlags, ASTNode, Ident, Stmt, StmtBlock};
44
use crate::engine::KEYWORD_FN_PTR;
55
use crate::tokenizer::Token;
66
use crate::types::dynamic::Union;
@@ -184,7 +184,8 @@ impl FnCallHashes {
184184
#[derive(Clone, Hash)]
185185
pub struct FnCallExpr {
186186
/// Namespace of the function, if any.
187-
pub namespace: Namespace,
187+
#[cfg(not(feature = "no_module"))]
188+
pub namespace: super::Namespace,
188189
/// Function name.
189190
pub name: ImmutableString,
190191
/// Pre-calculated hashes.
@@ -202,13 +203,14 @@ impl fmt::Debug for FnCallExpr {
202203
#[inline(never)]
203204
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204205
let mut ff = f.debug_struct("FnCallExpr");
206+
#[cfg(not(feature = "no_module"))]
205207
if !self.namespace.is_empty() {
206208
ff.field("namespace", &self.namespace);
207209
}
208210
ff.field("hash", &self.hashes)
209211
.field("name", &self.name)
210212
.field("args", &self.args);
211-
if self.op_token.is_some() {
213+
if self.is_operator_call() {
212214
ff.field("op_token", &self.op_token);
213215
}
214216
if self.capture_parent_scope {
@@ -221,12 +223,19 @@ impl fmt::Debug for FnCallExpr {
221223
impl FnCallExpr {
222224
/// Does this function call contain a qualified namespace?
223225
///
224-
/// Always `false` under `no_module`.
226+
/// Not available under [`no_module`]
227+
#[cfg(not(feature = "no_module"))]
225228
#[inline(always)]
226229
#[must_use]
227230
pub fn is_qualified(&self) -> bool {
228231
!self.namespace.is_empty()
229232
}
233+
/// Is this function call an operator expression?
234+
#[inline(always)]
235+
#[must_use]
236+
pub fn is_operator_call(&self) -> bool {
237+
self.op_token.is_some()
238+
}
230239
/// Convert this into an [`Expr::FnCall`].
231240
#[inline(always)]
232241
#[must_use]
@@ -276,13 +285,15 @@ pub enum Expr {
276285
),
277286
/// ()
278287
Unit(Position),
279-
/// Variable access - (optional long index, namespace, namespace hash, variable name), optional short index, position
288+
/// Variable access - (optional long index, variable name, namespace, namespace hash), optional short index, position
280289
///
281290
/// The short index is [`u8`] which is used when the index is <= 255, which should be
282291
/// the vast majority of cases (unless there are more than 255 variables defined!).
283292
/// This is to avoid reading a pointer redirection during each variable access.
284293
Variable(
285-
Box<(Option<NonZeroUsize>, Namespace, u64, ImmutableString)>,
294+
#[cfg(not(feature = "no_module"))]
295+
Box<(Option<NonZeroUsize>, ImmutableString, super::Namespace, u64)>,
296+
#[cfg(feature = "no_module")] Box<(Option<NonZeroUsize>, ImmutableString)>,
286297
Option<NonZeroU8>,
287298
Position,
288299
),
@@ -371,16 +382,16 @@ impl fmt::Debug for Expr {
371382
f.write_str("Variable(")?;
372383

373384
#[cfg(not(feature = "no_module"))]
374-
if !x.1.is_empty() {
385+
if !x.2.is_empty() {
375386
write!(f, "{}{}", x.1, crate::engine::NAMESPACE_SEPARATOR)?;
376-
let pos = x.1.position();
387+
let pos = x.2.position();
377388
if !pos.is_none() {
378389
display_pos = pos;
379390
}
380391
}
381-
f.write_str(&x.3)?;
392+
f.write_str(&x.1)?;
382393
#[cfg(not(feature = "no_module"))]
383-
if let Some(n) = x.1.index {
394+
if let Some(n) = x.2.index {
384395
write!(f, " #{n}")?;
385396
}
386397
if let Some(n) = i.map_or_else(|| x.0, |n| NonZeroUsize::new(n.get() as usize)) {
@@ -495,18 +506,20 @@ impl Expr {
495506
s.into()
496507
}
497508

498-
// Fn
499-
Self::FnCall(ref x, ..)
500-
if !x.is_qualified() && x.args.len() == 1 && x.name == KEYWORD_FN_PTR =>
501-
{
509+
// Qualified function call
510+
#[cfg(not(feature = "no_module"))]
511+
Self::FnCall(x, ..) if x.is_qualified() => return None,
512+
513+
// Function call
514+
Self::FnCall(x, ..) if x.args.len() == 1 && x.name == KEYWORD_FN_PTR => {
502515
match x.args[0] {
503516
Self::StringConstant(ref s, ..) => FnPtr::new(s.clone()).ok()?.into(),
504517
_ => return None,
505518
}
506519
}
507520

508-
// Binary operators
509-
Self::FnCall(x, ..) if !x.is_qualified() && x.args.len() == 2 => {
521+
// Binary operator call
522+
Self::FnCall(x, ..) if x.args.len() == 2 => {
510523
pub const OP_EXCLUSIVE_RANGE: &str = Token::ExclusiveRange.literal_syntax();
511524
pub const OP_INCLUSIVE_RANGE: &str = Token::InclusiveRange.literal_syntax();
512525

@@ -559,7 +572,8 @@ impl Expr {
559572

560573
Union::FnPtr(f, ..) if !f.is_curried() => Self::FnCall(
561574
FnCallExpr {
562-
namespace: Namespace::NONE,
575+
#[cfg(not(feature = "no_module"))]
576+
namespace: super::Namespace::NONE,
563577
name: KEYWORD_FN_PTR.into(),
564578
hashes: FnCallHashes::from_hash(calc_fn_hash(None, f.fn_name(), 1)),
565579
args: once(Self::StringConstant(f.fn_name().into(), pos)).collect(),
@@ -581,8 +595,8 @@ impl Expr {
581595
pub(crate) fn get_variable_name(&self, _non_qualified: bool) -> Option<&str> {
582596
match self {
583597
#[cfg(not(feature = "no_module"))]
584-
Self::Variable(x, ..) if _non_qualified && !x.1.is_empty() => None,
585-
Self::Variable(x, ..) => Some(&x.3),
598+
Self::Variable(x, ..) if _non_qualified && !x.2.is_empty() => None,
599+
Self::Variable(x, ..) => Some(&x.1),
586600
_ => None,
587601
}
588602
}
@@ -661,10 +675,10 @@ impl Expr {
661675
match self {
662676
#[cfg(not(feature = "no_module"))]
663677
Self::Variable(x, ..) => {
664-
if x.1.is_empty() {
678+
if x.2.is_empty() {
665679
self.position()
666680
} else {
667-
x.1.position()
681+
x.2.position()
668682
}
669683
}
670684

‎src/ast/mod.rs‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ pub mod expr;
66
pub mod flags;
77
pub mod ident;
88
pub mod namespace;
9-
pub mod namespace_none;
109
pub mod script_fn;
1110
pub mod stmt;
1211

@@ -18,8 +17,6 @@ pub use flags::{ASTFlags, FnAccess};
1817
pub use ident::Ident;
1918
#[cfg(not(feature = "no_module"))]
2019
pub use namespace::Namespace;
21-
#[cfg(feature = "no_module")]
22-
pub use namespace_none::Namespace;
2320
#[cfg(not(feature = "no_function"))]
2421
pub use script_fn::{ScriptFnMetadata, ScriptFuncDef};
2522
pub use stmt::{

‎src/ast/namespace_none.rs‎

Lines changed: 0 additions & 22 deletions
This file was deleted.

‎src/ast/stmt.rs‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -913,11 +913,16 @@ impl Stmt {
913913

914914
Self::Expr(e) => match &**e {
915915
Expr::Stmt(s) => s.iter().all(Self::is_block_dependent),
916-
Expr::FnCall(x, ..) => !x.is_qualified() && x.name == KEYWORD_EVAL,
916+
#[cfg(not(feature = "no_module"))]
917+
Expr::FnCall(x, ..) if x.is_qualified() => false,
918+
Expr::FnCall(x, ..) => x.name == KEYWORD_EVAL,
917919
_ => false,
918920
},
919921

920-
Self::FnCall(x, ..) => !x.is_qualified() && x.name == KEYWORD_EVAL,
922+
#[cfg(not(feature = "no_module"))]
923+
Self::FnCall(x, ..) if x.is_qualified() => false,
924+
925+
Self::FnCall(x, ..) => x.name == KEYWORD_EVAL,
921926

922927
#[cfg(not(feature = "no_module"))]
923928
Self::Import(..) | Self::Export(..) => true,

‎src/eval/chaining.rs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,7 @@ impl Engine {
462462
match (expr, ChainType::from(parent)) {
463463
#[cfg(not(feature = "no_object"))]
464464
(Expr::MethodCall(x, ..), ChainType::Dotting) => {
465+
#[cfg(not(feature = "no_module"))]
465466
debug_assert!(
466467
!x.is_qualified(),
467468
"method call in dot chain should not be namespace-qualified"
@@ -491,6 +492,7 @@ impl Engine {
491492

492493
#[cfg(not(feature = "no_object"))]
493494
(Expr::MethodCall(x, ..), ChainType::Dotting) => {
495+
#[cfg(not(feature = "no_module"))]
494496
debug_assert!(
495497
!x.is_qualified(),
496498
"method call in dot chain should not be namespace-qualified"
@@ -735,6 +737,7 @@ impl Engine {
735737
}
736738
// xxx.fn_name(arg_expr_list)
737739
(Expr::MethodCall(x, pos), None, ..) => {
740+
#[cfg(not(feature = "no_module"))]
738741
debug_assert!(
739742
!x.is_qualified(),
740743
"method call in dot chain should not be namespace-qualified"
@@ -937,6 +940,7 @@ impl Engine {
937940
}
938941
// {xxx:map}.fn_name(arg_expr_list)[expr] | {xxx:map}.fn_name(arg_expr_list).expr
939942
Expr::MethodCall(ref x, pos) => {
943+
#[cfg(not(feature = "no_module"))]
940944
debug_assert!(
941945
!x.is_qualified(),
942946
"method call in dot chain should not be namespace-qualified"
@@ -1058,6 +1062,7 @@ impl Engine {
10581062
}
10591063
// xxx.fn_name(arg_expr_list)[expr] | xxx.fn_name(arg_expr_list).expr
10601064
Expr::MethodCall(ref f, pos) => {
1065+
#[cfg(not(feature = "no_module"))]
10611066
debug_assert!(
10621067
!f.is_qualified(),
10631068
"method call in dot chain should not be namespace-qualified"

‎src/eval/expr.rs‎

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,19 @@ impl Engine {
6363

6464
Expr::Variable(_, Some(i), ..) => i.get() as usize,
6565
Expr::Variable(v, None, ..) => {
66+
#[cfg(not(feature = "no_module"))]
67+
debug_assert!(v.2.is_empty(), "variable should not be namespace-qualified");
68+
6669
// Scripted function with the same name
6770
#[cfg(not(feature = "no_function"))]
6871
if let Some(fn_def) = global
6972
.lib
7073
.iter()
7174
.flat_map(|m| m.iter_script_fn())
72-
.find_map(|(_, _, f, _, func)| if f == v.3 { Some(func) } else { None })
75+
.find_map(|(_, _, f, _, func)| if f == v.1 { Some(func) } else { None })
7376
{
7477
let val: Dynamic = crate::FnPtr {
75-
name: v.3.clone(),
78+
name: v.1.clone(),
7679
curry: <_>::default(),
7780
environ: None,
7881
fn_def: Some(fn_def.clone()),
@@ -156,14 +159,9 @@ impl Engine {
156159
self.search_scope_only(global, caches, scope, this_ptr, expr)
157160
}
158161
Expr::Variable(v, None, ..) => match &**v {
159-
// Normal variable access
160-
(_, ns, ..) if ns.is_empty() => {
161-
self.search_scope_only(global, caches, scope, this_ptr, expr)
162-
}
163-
164162
// Qualified variable access
165163
#[cfg(not(feature = "no_module"))]
166-
(_, ns, hash_var, var_name) => {
164+
(_, var_name, ns, hash_var) if !ns.is_empty() => {
167165
// foo:bar::baz::VARIABLE
168166
if let Some(module) = self.search_imports(global, ns) {
169167
return module.get_qualified_var(*hash_var).map_or_else(
@@ -211,8 +209,8 @@ impl Engine {
211209
Err(ERR::ErrorModuleNotFound(ns.to_string(), ns.position()).into())
212210
}
213211

214-
#[cfg(feature = "no_module")]
215-
_ => unreachable!("Invalid expression {:?}", expr),
212+
// Normal variable access
213+
_ => self.search_scope_only(global, caches, scope, this_ptr, expr),
216214
},
217215
_ => unreachable!("Expr::Variable expected but gets {:?}", expr),
218216
}

‎src/eval/stmt.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ impl Engine {
336336
// Cannot assign to temp result from expression
337337
if is_temp_result {
338338
return Err(ERR::ErrorAssignmentToConstant(
339-
x.3.to_string(),
339+
x.1.to_string(),
340340
lhs.position(),
341341
)
342342
.into());
@@ -850,7 +850,7 @@ impl Engine {
850850
if scope.len() >= self.max_variables() {
851851
return Err(ERR::ErrorTooManyVariables(catch_var.position()).into());
852852
}
853-
scope.push(x.3.clone(), err_value);
853+
scope.push(x.1.clone(), err_value);
854854
}
855855

856856
let this_ptr = this_ptr.as_deref_mut();

0 commit comments

Comments
 (0)