diff --git a/src/ast.rs b/src/ast.rs index f5f72c5a..04bae51a 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -2003,7 +2003,7 @@ impl fmt::Debug for Expr { Self::Variable(i, _, x) => { f.write_str("Variable(")?; if let Some((_, ref namespace)) = x.1 { - write!(f, "{}", namespace)? + write!(f, "{}{}", namespace, Token::DoubleColon.literal_syntax())? } f.write_str(&x.2)?; if let Some(n) = i.map_or_else(|| x.0, |n| NonZeroUsize::new(n.get() as usize)) { diff --git a/src/engine.rs b/src/engine.rs index 9e512b18..6e9a847a 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1181,38 +1181,54 @@ impl Engine { Expr::Variable(None, var_pos, v) => match v.as_ref() { // Normal variable access (_, None, _) => self.search_scope_only(scope, mods, state, lib, this_ptr, expr), - // Qualified variable + // Qualified variable access (_, Some((namespace, hash_var)), var_name) => { if let Some(module) = self.search_imports(mods, state, namespace) { - let target = module.get_qualified_var(*hash_var).map_err(|mut err| { - match *err { - EvalAltResult::ErrorVariableNotFound(ref mut err_name, _) => { - *err_name = format!("{}{}", namespace, var_name); - } - _ => (), + // foo:bar::baz::VARIABLE + match module.get_qualified_var(*hash_var) { + Ok(target) => { + let mut target = target.clone(); + // Module variables are constant + target.set_access_mode(AccessMode::ReadOnly); + Ok((target.into(), *var_pos)) } - err.fill_position(*var_pos) - })?; - - // Module variables are constant - let mut target = target.clone(); - target.set_access_mode(AccessMode::ReadOnly); - Ok((target.into(), *var_pos)) + Err(mut err) => { + match *err { + EvalAltResult::ErrorVariableNotFound(ref mut err_name, _) => { + *err_name = format!( + "{}{}{}", + namespace, + Token::DoubleColon.literal_syntax(), + var_name + ); + } + _ => (), + } + Err(err.fill_position(*var_pos)) + } + } } else if namespace.len() == 1 && namespace[0].name == KEYWORD_GLOBAL { + // global::VARIABLE if let Some(value) = state.global_constants.get_mut(var_name) { let mut target: Target = value.clone().into(); + // Module variables are constant target.set_access_mode(AccessMode::ReadOnly); Ok((target.into(), *var_pos)) } else { Err(EvalAltResult::ErrorVariableNotFound( - format!("{}{}", namespace, var_name), + format!( + "{}{}{}", + namespace, + Token::DoubleColon.literal_syntax(), + var_name + ), namespace[0].pos, ) .into()) } } else { Err(EvalAltResult::ErrorModuleNotFound( - namespace[0].name.to_string(), + namespace.to_string(), namespace[0].pos, ) .into()) diff --git a/src/error.rs b/src/error.rs index 4cf608fa..f38a971c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -122,11 +122,11 @@ impl fmt::Display for EvalAltResult { Self::ErrorInModule(s, err, _) if s.is_empty() => { write!(f, "Error in module: {}", err)? } - Self::ErrorInModule(s, err, _) => write!(f, "Error in module '{}': {}", s, err)?, + Self::ErrorInModule(s, err, _) => write!(f, "Error in module {}: {}", s, err)?, Self::ErrorFunctionNotFound(s, _) => write!(f, "Function not found: {}", s)?, Self::ErrorVariableNotFound(s, _) => write!(f, "Variable not found: {}", s)?, - Self::ErrorModuleNotFound(s, _) => write!(f, "Module not found: '{}'", s)?, + Self::ErrorModuleNotFound(s, _) => write!(f, "Module not found: {}", s)?, Self::ErrorDataRace(s, _) => { write!(f, "Data race detected when accessing variable: {}", s)? } @@ -134,7 +134,7 @@ impl fmt::Display for EvalAltResult { "" => f.write_str("Malformed dot expression"), s => f.write_str(s), }?, - Self::ErrorIndexingType(s, _) => write!(f, "Indexer not registered for '{}'", s)?, + Self::ErrorIndexingType(s, _) => write!(f, "Indexer not registered for {}", s)?, Self::ErrorUnboundThis(_) => f.write_str("'this' is not bound")?, Self::ErrorFor(_) => f.write_str("For loop expects a type with an iterator defined")?, Self::ErrorTooManyOperations(_) => f.write_str("Too many operations")?, diff --git a/src/fn_call.rs b/src/fn_call.rs index 2bafb66b..6a1b688f 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -9,14 +9,13 @@ use crate::engine::{ use crate::fn_builtin::{get_builtin_binary_op_fn, get_builtin_op_assignment_fn}; use crate::fn_native::FnAny; use crate::module::NamespaceRef; +use crate::token::Token; use crate::{ ast::{Expr, Stmt}, + calc_fn_hash, calc_fn_params_hash, combine_hashes, fn_native::CallableFunction, - RhaiResult, -}; -use crate::{ - calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, EvalAltResult, FnPtr, - Identifier, ImmutableString, Module, ParseErrorType, Position, Scope, StaticVec, + Dynamic, Engine, EvalAltResult, FnPtr, Identifier, ImmutableString, Module, ParseErrorType, + Position, RhaiResult, Scope, StaticVec, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -135,8 +134,13 @@ impl Engine { args: &[&mut Dynamic], ) -> String { format!( - "{}{} ({})", + "{}{}{} ({})", namespace.map_or(String::new(), |ns| ns.to_string()), + if namespace.is_some() { + Token::DoubleColon.literal_syntax() + } else { + "" + }, fn_name, args.iter() .map(|a| if a.is::() { @@ -1393,7 +1397,7 @@ impl Engine { } let module = self.search_imports(mods, state, namespace).ok_or_else(|| { - EvalAltResult::ErrorModuleNotFound(namespace[0].name.to_string(), namespace[0].pos) + EvalAltResult::ErrorModuleNotFound(namespace.to_string(), namespace[0].pos) })?; // First search in script-defined functions (can override built-in) diff --git a/src/module/mod.rs b/src/module/mod.rs index 0a9ebe39..f917e907 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -1677,17 +1677,21 @@ impl fmt::Debug for NamespaceRef { .iter() .map(|Ident { name, .. }| name.as_str()) .collect::>() - .join("::"), + .join(Token::DoubleColon.literal_syntax()), ) } } impl fmt::Display for NamespaceRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for Ident { name, .. } in self.path.iter() { - write!(f, "{}{}", name, Token::DoubleColon.syntax())?; - } - Ok(()) + f.write_str( + &self + .path + .iter() + .map(|Ident { name, .. }| name.as_str()) + .collect::>() + .join(Token::DoubleColon.literal_syntax()), + ) } } diff --git a/src/packages/fn_basic.rs b/src/packages/fn_basic.rs index a40c7b73..58430c82 100644 --- a/src/packages/fn_basic.rs +++ b/src/packages/fn_basic.rs @@ -107,7 +107,12 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array { list.push(make_metadata(dict, Some(namespace.clone()), f).into()) }); module.iter_sub_modules().for_each(|(ns, m)| { - let ns = format!("{}::{}", namespace, ns); + let ns = format!( + "{}{}{}", + namespace, + crate::token::Token::DoubleColon.literal_syntax(), + ns + ); scan_module(list, dict, ns.into(), m.as_ref()) }); }