diff --git a/CHANGELOG.md b/CHANGELOG.md index 436e20df..3f7a2997 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,9 @@ Enhancements * Debug display of `AST` is improved. * `NativeCallContext::call_level()` is added to give the current nesting level of function calls. * A new feature, `bin-features`, pulls in all the required features for `bin` tools. +* `AST` position display is improved: + * `Expr::start_position` is added to give the beginning of the expression (not the operator's position). + * `StmtBlock` and `Stmt::Block` now keep the position of the closing `}` as well. REPL tool changes ----------------- diff --git a/src/ast/ast.rs b/src/ast/ast.rs index 18b02cff..6fb96e85 100644 --- a/src/ast/ast.rs +++ b/src/ast/ast.rs @@ -91,7 +91,7 @@ impl AST { ) -> Self { Self { source: Identifier::new_const(), - body: StmtBlock::new(statements, Position::NONE), + body: StmtBlock::new(statements, Position::NONE, Position::NONE), #[cfg(not(feature = "no_function"))] lib: functions.into(), #[cfg(not(feature = "no_module"))] diff --git a/src/ast/expr.rs b/src/ast/expr.rs index a9881804..dffacf42 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -191,6 +191,8 @@ pub struct FnCallExpr { pub constants: StaticVec, /// Does this function call capture the parent scope? pub capture_parent_scope: bool, + /// [Position] of the function name. + pub pos: Position, } impl fmt::Debug for FnCallExpr { @@ -207,6 +209,7 @@ impl fmt::Debug for FnCallExpr { if self.capture_parent_scope { ff.field("capture_parent_scope", &self.capture_parent_scope); } + ff.field("pos", &self.pos); ff.finish() } } @@ -437,7 +440,7 @@ impl Default for Expr { impl fmt::Debug for Expr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut display_pos = self.position(); + let mut display_pos = self.start_position(); match self { Self::DynamicConstant(value, _) => write!(f, "{:?}", value), @@ -629,6 +632,7 @@ impl Expr { args: once(Self::Stack(0, pos)).collect(), constants: once(f.fn_name().into()).collect(), capture_parent_scope: false, + pos, } .into(), pos, @@ -685,15 +689,30 @@ impl Expr { | Self::Map(_, pos) | Self::Variable(_, pos, _) | Self::Stack(_, pos) - | Self::FnCall(_, pos) + | Self::And(_, pos) + | Self::Or(_, pos) | Self::Index(_, _, pos) + | Self::Dot(_, _, pos) | Self::Custom(_, pos) | Self::InterpolatedString(_, pos) | Self::Property(_, pos) => *pos, - Self::Stmt(x) => x.position(), + Self::FnCall(x, _) => x.pos, - Self::And(x, _) | Self::Or(x, _) | Self::Dot(x, _, _) => x.lhs.position(), + Self::Stmt(x) => x.position(), + } + } + /// Get the starting [position][Position] of the expression. + /// For a binary expression, this will be the left-most LHS instead of the operator. + #[inline] + #[must_use] + pub const fn start_position(&self) -> Position { + match self { + Self::And(x, _) | Self::Or(x, _) | Self::Index(x, _, _) | Self::Dot(x, _, _) => { + x.lhs.start_position() + } + Self::FnCall(_, pos) => *pos, + _ => self.position(), } } /// Override the [position][Position] of the expression. @@ -722,7 +741,7 @@ impl Expr { | Self::InterpolatedString(_, pos) | Self::Property(_, pos) => *pos = new_pos, - Self::Stmt(x) => x.set_position(new_pos), + Self::Stmt(x) => x.set_position(new_pos, Position::NONE), } self diff --git a/src/ast/stmt.rs b/src/ast/stmt.rs index f9f6717c..ca82fb8f 100644 --- a/src/ast/stmt.rs +++ b/src/ast/stmt.rs @@ -134,7 +134,7 @@ pub struct TryCatchBlock { /// _(internals)_ A scoped block of statements. /// Exported under the `internals` feature only. #[derive(Clone, Hash, Default)] -pub struct StmtBlock(StaticVec, Position); +pub struct StmtBlock(StaticVec, (Position, Position)); impl StmtBlock { /// A [`StmtBlock`] that does not exist. @@ -142,16 +142,20 @@ impl StmtBlock { /// Create a new [`StmtBlock`]. #[must_use] - pub fn new(statements: impl IntoIterator, pos: Position) -> Self { + pub fn new( + statements: impl IntoIterator, + start_pos: Position, + end_pos: Position, + ) -> Self { let mut statements: StaticVec<_> = statements.into_iter().collect(); statements.shrink_to_fit(); - Self(statements, pos) + Self(statements, (start_pos, end_pos)) } /// Create an empty [`StmtBlock`]. #[inline(always)] #[must_use] pub const fn empty(pos: Position) -> Self { - Self(StaticVec::new_const(), pos) + Self(StaticVec::new_const(), (pos, pos)) } /// Is this statements block empty? #[inline(always)] @@ -183,16 +187,42 @@ impl StmtBlock { pub fn iter(&self) -> impl Iterator { self.0.iter() } - /// Get the position (location of the beginning `{`) of this statements block. + /// Get the start position (location of the beginning `{`) of this statements block. #[inline(always)] #[must_use] pub const fn position(&self) -> Position { + (self.1).0 + } + /// Get the end position (location of the ending `}`) of this statements block. + #[inline(always)] + #[must_use] + pub const fn end_position(&self) -> Position { + (self.1).1 + } + /// Get the positions (locations of the beginning `{` and ending `}`) of this statements block. + #[inline(always)] + #[must_use] + pub const fn positions(&self) -> (Position, Position) { self.1 } - /// Set the position (location of the beginning `{`) of this statements block. + /// Get the positions (locations of the beginning `{` and ending `}`) of this statements block + /// or a default. #[inline(always)] - pub fn set_position(&mut self, pos: Position) { - self.1 = pos; + #[must_use] + pub const fn positions_or_else( + &self, + def_start_pos: Position, + def_end_pos: Position, + ) -> (Position, Position) { + ( + (self.1).0.or_else(def_start_pos), + (self.1).1.or_else(def_end_pos), + ) + } + /// Set the positions of this statements block. + #[inline(always)] + pub fn set_position(&mut self, start_pos: Position, end_pos: Position) { + self.1 = (start_pos, end_pos); } } @@ -230,7 +260,12 @@ impl fmt::Debug for StmtBlock { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Block")?; fmt::Debug::fmt(&self.0, f)?; - self.1.debug_print(f) + (self.1).0.debug_print(f)?; + #[cfg(not(feature = "no_position"))] + if !(self.1).1.is_none() { + write!(f, "-{:?}", (self.1).1)?; + } + Ok(()) } } @@ -239,10 +274,10 @@ impl From for StmtBlock { fn from(stmt: Stmt) -> Self { match stmt { Stmt::Block(mut block, pos) => Self(block.iter_mut().map(mem::take).collect(), pos), - Stmt::Noop(pos) => Self(StaticVec::new_const(), pos), + Stmt::Noop(pos) => Self(StaticVec::new_const(), (pos, pos)), _ => { let pos = stmt.position(); - Self(vec![stmt].into(), pos) + Self(vec![stmt].into(), (pos, Position::NONE)) } } } @@ -309,7 +344,7 @@ pub enum Stmt { /// function call forming one statement. FnCall(Box, Position), /// `{` stmt`;` ... `}` - Block(Box<[Stmt]>, Position), + Block(Box<[Stmt]>, (Position, Position)), /// `try` `{` stmt; ... `}` `catch` `(` var `)` `{` stmt; ... `}` TryCatch(Box, Position), /// [expression][Expr] @@ -377,7 +412,7 @@ impl Stmt { match self { Self::Noop(pos) | Self::BreakLoop(_, pos) - | Self::Block(_, pos) + | Self::Block(_, (pos, _)) | Self::Assignment(_, pos) | Self::FnCall(_, pos) | Self::If(_, _, pos) @@ -389,7 +424,7 @@ impl Stmt { | Self::Var(_, _, _, pos) | Self::TryCatch(_, pos) => *pos, - Self::Expr(x) => x.position(), + Self::Expr(x) => x.start_position(), #[cfg(not(feature = "no_module"))] Self::Import(_, _, pos) => *pos, @@ -405,7 +440,7 @@ impl Stmt { match self { Self::Noop(pos) | Self::BreakLoop(_, pos) - | Self::Block(_, pos) + | Self::Block(_, (pos, _)) | Self::Assignment(_, pos) | Self::FnCall(_, pos) | Self::If(_, _, pos) diff --git a/src/eval/chaining.rs b/src/eval/chaining.rs index aada9039..c681ce5a 100644 --- a/src/eval/chaining.rs +++ b/src/eval/chaining.rs @@ -146,7 +146,7 @@ impl Engine { match chain_type { #[cfg(not(feature = "no_index"))] ChainType::Indexing => { - let pos = rhs.position(); + let pos = rhs.start_position(); let root_pos = idx_val.position(); let idx_val = idx_val.into_index_value().expect("`ChainType::Index`"); @@ -159,7 +159,7 @@ impl Engine { self.run_debugger(scope, global, state, lib, this_ptr, _parent, level)?; let mut idx_val_for_setter = idx_val.clone(); - let idx_pos = x.lhs.position(); + let idx_pos = x.lhs.start_position(); let rhs_chain = rhs.into(); let (try_setter, result) = { @@ -629,7 +629,7 @@ impl Engine { } } // Syntax error - _ => Err(ERR::ErrorDotExpr("".into(), rhs.position()).into()), + _ => Err(ERR::ErrorDotExpr("".into(), rhs.start_position()).into()), } } } @@ -691,7 +691,7 @@ impl Engine { expr => { let value = self.eval_expr(scope, global, state, lib, this_ptr, expr, level)?; let obj_ptr = &mut value.into(); - let root = ("", expr.position()); + let root = ("", expr.start_position()); self.eval_dot_index_chain_helper( global, state, lib, this_ptr, obj_ptr, root, expr, rhs, term, idx_values, chain_type, level, new_val, @@ -804,7 +804,10 @@ impl Engine { _ if _parent_chain_type == ChainType::Indexing => self .eval_expr(scope, global, state, lib, this_ptr, lhs, level) .map(|v| { - super::ChainArgument::from_index_value(v.flatten(), lhs.position()) + super::ChainArgument::from_index_value( + v.flatten(), + lhs.start_position(), + ) })?, expr => unreachable!("unknown chained expression: {:?}", expr), }; @@ -828,7 +831,7 @@ impl Engine { _ if _parent_chain_type == ChainType::Indexing => idx_values.push( self.eval_expr(scope, global, state, lib, this_ptr, expr, level) .map(|v| { - super::ChainArgument::from_index_value(v.flatten(), expr.position()) + super::ChainArgument::from_index_value(v.flatten(), expr.start_position()) })?, ), _ => unreachable!("unknown chained expression: {:?}", expr), diff --git a/src/eval/expr.rs b/src/eval/expr.rs index 520f8283..dcbb830b 100644 --- a/src/eval/expr.rs +++ b/src/eval/expr.rs @@ -148,7 +148,7 @@ impl Engine { Err(ERR::ErrorUnboundThis(*pos).into()) } } - _ if state.always_search_scope => (0, expr.position()), + _ if state.always_search_scope => (0, expr.start_position()), Expr::Variable(Some(i), pos, _) => (i.get() as usize, *pos), Expr::Variable(None, pos, v) => (v.0.map(NonZeroUsize::get).unwrap_or(0), *pos), _ => unreachable!("Expr::Variable expected but gets {:?}", expr), @@ -347,11 +347,11 @@ impl Engine { item, level, ) { - result = Err(err.fill_position(expr.position())); + result = Err(err.fill_position(expr.start_position())); break; } - pos = expr.position(); + pos = expr.start_position(); } result.map(|_| concat) @@ -504,7 +504,7 @@ impl Engine { let result = (custom_def.func)(&mut context, &expressions); - self.check_return_value(result, expr.position()) + self.check_return_value(result, expr.start_position()) } Expr::Stmt(x) if x.is_empty() => Ok(Dynamic::UNIT), diff --git a/src/eval/stmt.rs b/src/eval/stmt.rs index 065e251a..8e1e7c5c 100644 --- a/src/eval/stmt.rs +++ b/src/eval/stmt.rs @@ -267,7 +267,7 @@ impl Engine { rhs_val, level, ) - .map_err(|err| err.fill_position(rhs.position())) + .map_err(|err| err.fill_position(rhs.start_position())) .map(|_| Dynamic::UNIT) } else { search_result.map(|_| Dynamic::UNIT) @@ -283,7 +283,7 @@ impl Engine { .map(Dynamic::flatten); if let Ok(rhs_val) = rhs_result { - let _new_val = Some(((rhs_val, rhs.position()), (*op_info, *op_pos))); + let _new_val = Some(((rhs_val, rhs.start_position()), (*op_info, *op_pos))); // Must be either `var[index] op= val` or `var.prop op= val` match lhs { @@ -686,7 +686,7 @@ impl Engine { loop_result } else { - Err(ERR::ErrorFor(expr.position()).into()) + Err(ERR::ErrorFor(expr.start_position()).into()) } } else { iter_result @@ -869,9 +869,10 @@ impl Engine { let path_result = self .eval_expr(scope, global, state, lib, this_ptr, &expr, level) .and_then(|v| { + let typ = v.type_name(); v.try_cast::().ok_or_else(|| { self.make_type_mismatch_err::( - "", + typ, expr.position(), ) }) @@ -880,7 +881,7 @@ impl Engine { if let Ok(path) = path_result { use crate::ModuleResolver; - let path_pos = expr.position(); + let path_pos = expr.start_position(); let resolver = global.embedded_module_resolver.clone(); diff --git a/src/func/call.rs b/src/func/call.rs index ab719c14..292bd33f 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -426,23 +426,26 @@ impl Engine { }; #[cfg(feature = "debugging")] - if self.debugger.is_some() { - match global.debugger.status { - crate::eval::DebuggerStatus::FunctionExit(n) if n >= level => { - let scope = &mut &mut Scope::new(); - let node = crate::ast::Stmt::Noop(pos); - let node = (&node).into(); - let event = match _result { - Ok(ref r) => crate::eval::DebuggerEvent::FunctionExitWithValue(r), - Err(ref err) => crate::eval::DebuggerEvent::FunctionExitWithError(err), - }; - if let Err(err) = self.run_debugger_raw( - scope, global, state, lib, &mut None, node, event, level, - ) { - _result = Err(err); - } + { + let trigger = match global.debugger.status { + crate::eval::DebuggerStatus::FunctionExit(n) => n >= level, + crate::eval::DebuggerStatus::Next(_, true) => true, + _ => false, + }; + if trigger { + let scope = &mut &mut Scope::new(); + let node = crate::ast::Stmt::Noop(pos); + let node = (&node).into(); + let event = match _result { + Ok(ref r) => crate::eval::DebuggerEvent::FunctionExitWithValue(r), + Err(ref err) => crate::eval::DebuggerEvent::FunctionExitWithError(err), + }; + match self + .run_debugger_raw(scope, global, state, lib, &mut None, node, event, level) + { + Ok(_) => (), + Err(err) => _result = Err(err), } - _ => (), } // Pop the call stack @@ -977,7 +980,7 @@ impl Engine { result? }, - arg_expr.position(), + arg_expr.start_position(), )) } @@ -1378,24 +1381,17 @@ impl Engine { #[cfg(not(feature = "no_function"))] Some(f) if f.is_script() => { let fn_def = f.get_script_fn_def().expect("script-defined function"); + let new_scope = &mut Scope::new(); + let mut source = module.id_raw().clone(); + mem::swap(&mut global.source, &mut source); - if fn_def.body.is_empty() { - Ok(Dynamic::UNIT) - } else { - let new_scope = &mut Scope::new(); + let result = self.call_script_fn( + new_scope, global, state, lib, &mut None, fn_def, &mut args, true, pos, level, + ); - let mut source = module.id_raw().clone(); - mem::swap(&mut global.source, &mut source); + global.source = source; - let result = self.call_script_fn( - new_scope, global, state, lib, &mut None, fn_def, &mut args, true, pos, - level, - ); - - global.source = source; - - result - } + result } Some(f) if f.is_plugin_fn() => { diff --git a/src/func/script.rs b/src/func/script.rs index 77397f1e..7b4236a8 100644 --- a/src/func/script.rs +++ b/src/func/script.rs @@ -182,22 +182,24 @@ impl Engine { }); #[cfg(feature = "debugging")] - if self.debugger.is_some() { - match global.debugger.status { - crate::eval::DebuggerStatus::FunctionExit(n) if n >= level => { - let node = crate::ast::Stmt::Noop(pos); - let node = (&node).into(); - let event = match _result { - Ok(ref r) => crate::eval::DebuggerEvent::FunctionExitWithValue(r), - Err(ref err) => crate::eval::DebuggerEvent::FunctionExitWithError(err), - }; - if let Err(err) = self - .run_debugger_raw(scope, global, state, lib, this_ptr, node, event, level) - { - _result = Err(err); - } + { + let trigger = match global.debugger.status { + crate::eval::DebuggerStatus::FunctionExit(n) => n >= level, + crate::eval::DebuggerStatus::Next(_, true) => true, + _ => false, + }; + if trigger { + let node = crate::ast::Stmt::Noop(fn_def.body.end_position().or_else(pos)); + let node = (&node).into(); + let event = match _result { + Ok(ref r) => crate::eval::DebuggerEvent::FunctionExitWithValue(r), + Err(ref err) => crate::eval::DebuggerEvent::FunctionExitWithError(err), + }; + match self.run_debugger_raw(scope, global, state, lib, this_ptr, node, event, level) + { + Ok(_) => (), + Err(err) => _result = Err(err), } - _ => (), } // Pop the call stack diff --git a/src/optimizer.rs b/src/optimizer.rs index acae357e..df9bc26d 100644 --- a/src/optimizer.rs +++ b/src/optimizer.rs @@ -463,13 +463,16 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b Stmt::If(condition, x, _) if x.0.is_empty() && x.1.is_empty() => { state.set_dirty(); - let pos = condition.position(); + let pos = condition.start_position(); let mut expr = mem::take(condition); optimize_expr(&mut expr, state, false); *stmt = if preserve_result { // -> { expr, Noop } - Stmt::Block([Stmt::Expr(expr), Stmt::Noop(pos)].into(), pos) + Stmt::Block( + [Stmt::Expr(expr), Stmt::Noop(pos)].into(), + (pos, Position::NONE), + ) } else { // -> expr Stmt::Expr(expr) @@ -487,7 +490,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b match optimize_stmt_block(mem::take(&mut *x.1), state, preserve_result, true, false) { statements if statements.is_empty() => Stmt::Noop(x.1.position()), - statements => Stmt::Block(statements.into_boxed_slice(), x.1.position()), + statements => Stmt::Block(statements.into_boxed_slice(), x.1.positions()), } } // if true { if_block } else { else_block } -> if_block @@ -497,7 +500,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b match optimize_stmt_block(mem::take(&mut *x.0), state, preserve_result, true, false) { statements if statements.is_empty() => Stmt::Noop(x.0.position()), - statements => Stmt::Block(statements.into_boxed_slice(), x.0.position()), + statements => Stmt::Block(statements.into_boxed_slice(), x.0.positions()), } } // if expr { if_block } else { else_block } @@ -531,11 +534,11 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b mem::take(&mut block.statements), Stmt::Block( def_stmt.into_boxed_slice(), - x.def_case.position().or_else(*pos), + x.def_case.positions_or_else(*pos, Position::NONE), ) .into(), )), - match_expr.position(), + match_expr.start_position(), ); } else { // Promote the matched case @@ -546,7 +549,8 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b true, false, ); - *stmt = Stmt::Block(statements.into_boxed_slice(), block.statements.position()); + *stmt = + Stmt::Block(statements.into_boxed_slice(), block.statements.positions()); } state.set_dirty(); @@ -586,11 +590,11 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b mem::take(&mut block.statements), Stmt::Block( def_stmt.into_boxed_slice(), - x.def_case.position().or_else(*pos), + x.def_case.positions_or_else(*pos, Position::NONE), ) .into(), )), - match_expr.position(), + match_expr.start_position(), ); } else { // Promote the matched case @@ -599,7 +603,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b optimize_stmt_block(statements, state, true, true, false); *stmt = Stmt::Block( statements.into_boxed_slice(), - block.statements.position(), + block.statements.positions(), ); } @@ -647,7 +651,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b optimize_stmt_block(mem::take(&mut x.def_case), state, true, true, false); *stmt = Stmt::Block( def_stmt.into_boxed_slice(), - x.def_case.position().or_else(*pos), + x.def_case.positions_or_else(*pos, Position::NONE), ); } // switch @@ -704,7 +708,8 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b if preserve_result { statements.push(Stmt::Noop(pos)) } - *stmt = Stmt::Block(statements.into_boxed_slice(), pos); + *stmt = + Stmt::Block(statements.into_boxed_slice(), (pos, Position::NONE)); } else { *stmt = Stmt::Noop(pos); }; @@ -721,7 +726,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b *stmt = Stmt::Block( optimize_stmt_block(mem::take(&mut **body), state, false, true, false) .into_boxed_slice(), - body.position(), + body.positions(), ); } // do { block } while|until expr @@ -749,7 +754,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b match block.as_mut_slice() { [] => { state.set_dirty(); - *stmt = Stmt::Noop(*pos); + *stmt = Stmt::Noop(pos.0); } // Only one statement which is not block-dependent - promote [s] if !s.is_block_dependent() => { @@ -766,7 +771,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b *stmt = Stmt::Block( optimize_stmt_block(mem::take(&mut *x.try_block), state, false, true, false) .into_boxed_slice(), - x.try_block.position(), + x.try_block.positions(), ); } // try { try_block } catch ( var ) { catch_block } @@ -1073,7 +1078,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) { if let Some(value) = arg.get_literal_value() { state.set_dirty(); constants.push(value); - *arg = Expr::Stack(constants.len()-1, arg.position()); + *arg = Expr::Stack(constants.len()-1, arg.start_position()); } }); } @@ -1121,7 +1126,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) { if let Some(value) = arg.get_literal_value() { state.set_dirty(); x.constants.push(value); - *arg = Expr::Stack(x.constants.len()-1, arg.position()); + *arg = Expr::Stack(x.constants.len()-1, arg.start_position()); } }, diff --git a/src/parser.rs b/src/parser.rs index 2efdccee..878e7ddd 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -306,7 +306,7 @@ impl Expr { Err( PERR::MismatchedType("a boolean expression".to_string(), type_name.to_string()) - .into_err(self.position()), + .into_err(self.start_position()), ) } /// Raise an error if the expression can never yield an iterable value. @@ -326,7 +326,7 @@ impl Expr { Err( PERR::MismatchedType("an iterable value".to_string(), type_name.to_string()) - .into_err(self.position()), + .into_err(self.start_position()), ) } } @@ -521,6 +521,7 @@ fn parse_fn_call( namespace, hashes, args, + pos: settings.pos, ..Default::default() } .into_fn_call_expr(settings.pos)); @@ -585,6 +586,7 @@ fn parse_fn_call( namespace, hashes, args, + pos: settings.pos, ..Default::default() } .into_fn_call_expr(settings.pos)); @@ -652,7 +654,7 @@ fn parse_index_chain( return Err(PERR::MalformedIndexExpr( "Only arrays, object maps and strings can be indexed".into(), ) - .into_err(lhs.position())) + .into_err(lhs.start_position())) } Expr::CharConstant(_, _) @@ -663,7 +665,7 @@ fn parse_index_chain( return Err(PERR::MalformedIndexExpr( "Only arrays, object maps and strings can be indexed".into(), ) - .into_err(lhs.position())) + .into_err(lhs.start_position())) } _ => (), @@ -677,7 +679,7 @@ fn parse_index_chain( return Err(PERR::MalformedIndexExpr( "Array or string expects numeric index, not a string".into(), ) - .into_err(idx_expr.position())) + .into_err(idx_expr.start_position())) } #[cfg(not(feature = "no_float"))] @@ -685,7 +687,7 @@ fn parse_index_chain( return Err(PERR::MalformedIndexExpr( "Only arrays, object maps and strings can be indexed".into(), ) - .into_err(lhs.position())) + .into_err(lhs.start_position())) } Expr::CharConstant(_, _) @@ -696,7 +698,7 @@ fn parse_index_chain( return Err(PERR::MalformedIndexExpr( "Only arrays, object maps and strings can be indexed".into(), ) - .into_err(lhs.position())) + .into_err(lhs.start_position())) } _ => (), @@ -708,35 +710,35 @@ fn parse_index_chain( return Err(PERR::MalformedIndexExpr( "Array access expects integer index, not a float".into(), ) - .into_err(x.position())) + .into_err(x.start_position())) } // lhs[char] x @ Expr::CharConstant(_, _) => { return Err(PERR::MalformedIndexExpr( "Array access expects integer index, not a character".into(), ) - .into_err(x.position())) + .into_err(x.start_position())) } // lhs[()] x @ Expr::Unit(_) => { return Err(PERR::MalformedIndexExpr( "Array access expects integer index, not ()".into(), ) - .into_err(x.position())) + .into_err(x.start_position())) } // lhs[??? && ???], lhs[??? || ???] x @ Expr::And(_, _) | x @ Expr::Or(_, _) => { return Err(PERR::MalformedIndexExpr( "Array access expects integer index, not a boolean".into(), ) - .into_err(x.position())) + .into_err(x.start_position())) } // lhs[true], lhs[false] x @ Expr::BoolConstant(_, _) => { return Err(PERR::MalformedIndexExpr( "Array access expects integer index, not a boolean".into(), ) - .into_err(x.position())) + .into_err(x.start_position())) } // All other expressions _ => (), @@ -1048,7 +1050,7 @@ fn parse_switch( let (hash, range) = if let Some(expr) = expr { let value = expr.get_literal_value().ok_or_else(|| { - PERR::ExprExpected("a literal".to_string()).into_err(expr.position()) + PERR::ExprExpected("a literal".to_string()).into_err(expr.start_position()) })?; let guard = value.read_lock::(); @@ -1058,14 +1060,14 @@ fn parse_switch( } else if let Some(range) = value.read_lock::() { (None, Some((*range.start(), *range.end(), true))) } else if value.is::() && !ranges.is_empty() { - return Err(PERR::WrongSwitchIntegerCase.into_err(expr.position())); + return Err(PERR::WrongSwitchIntegerCase.into_err(expr.start_position())); } else { let hasher = &mut get_hasher(); value.hash(hasher); let hash = hasher.finish(); if cases.contains_key(&hash) { - return Err(PERR::DuplicatedSwitchCase.into_err(expr.position())); + return Err(PERR::DuplicatedSwitchCase.into_err(expr.start_position())); } (Some(hash), None) } @@ -1682,6 +1684,7 @@ fn parse_unary( name: state.get_identifier("", "-"), hashes: FnCallHashes::from_native(calc_fn_hash("-", 1)), args, + pos, ..Default::default() } .into_fn_call_expr(pos)) @@ -1708,6 +1711,7 @@ fn parse_unary( name: state.get_identifier("", "+"), hashes: FnCallHashes::from_native(calc_fn_hash("+", 1)), args, + pos, ..Default::default() } .into_fn_call_expr(pos)) @@ -1725,6 +1729,7 @@ fn parse_unary( name: state.get_identifier("", "!"), hashes: FnCallHashes::from_native(calc_fn_hash("!", 1)), args, + pos, ..Default::default() } .into_fn_call_expr(pos)) @@ -1753,7 +1758,7 @@ fn make_assignment_stmt( } Expr::Property(_, _) => None, // Anything other than a property after dotting (e.g. a method call) is not an l-value - ref e => Some(e.position()), + ref e => Some(e.start_position()), }, Expr::Index(x, term, _) | Expr::Dot(x, term, _) => match x.lhs { Expr::Property(_, _) => unreachable!("unexpected Expr::Property in indexing"), @@ -1762,7 +1767,7 @@ fn make_assignment_stmt( }, Expr::Property(_, _) if parent_is_dot => None, Expr::Property(_, _) => unreachable!("unexpected Expr::Property in indexing"), - e if parent_is_dot => Some(e.position()), + e if parent_is_dot => Some(e.start_position()), _ => None, } } @@ -1772,7 +1777,7 @@ fn make_assignment_stmt( match lhs { // const_expr = rhs ref expr if expr.is_constant() => { - Err(PERR::AssignmentToConstant("".into()).into_err(lhs.position())) + Err(PERR::AssignmentToConstant("".into()).into_err(lhs.start_position())) } // var (non-indexed) = rhs Expr::Variable(None, _, ref x) if x.0.is_none() => Ok(Stmt::Assignment( @@ -1814,10 +1819,8 @@ fn make_assignment_stmt( op_pos, )), // expr[???] = rhs, expr.??? = rhs - ref expr => { - Err(PERR::AssignmentToInvalidLHS("".to_string()) - .into_err(expr.position())) - } + ref expr => Err(PERR::AssignmentToInvalidLHS("".to_string()) + .into_err(expr.start_position())), } } Some(err_pos) => { @@ -1832,7 +1835,7 @@ fn make_assignment_stmt( ) .into_err(op_pos)), // expr = rhs - _ => Err(PERR::AssignmentToInvalidLHS("".to_string()).into_err(lhs.position())), + _ => Err(PERR::AssignmentToInvalidLHS("".to_string()).into_err(lhs.start_position())), } } @@ -1983,7 +1986,7 @@ fn make_dot_expr( Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos)) } // lhs.rhs - (_, rhs) => Err(PERR::PropertyExpected.into_err(rhs.position())), + (_, rhs) => Err(PERR::PropertyExpected.into_err(rhs.start_position())), } } @@ -2065,6 +2068,7 @@ fn parse_binary_op( let op_base = FnCallExpr { name: state.get_identifier("", op), hashes: FnCallHashes::from_native(hash), + pos, ..Default::default() }; @@ -2082,7 +2086,10 @@ fn parse_binary_op( | Token::LessThan | Token::LessThanEqualsTo | Token::GreaterThan - | Token::GreaterThanEqualsTo => FnCallExpr { args, ..op_base }.into_fn_call_expr(pos), + | Token::GreaterThanEqualsTo => { + let pos = args[0].start_position(); + FnCallExpr { args, ..op_base }.into_fn_call_expr(pos) + } Token::Or => { let rhs = args.pop().unwrap(); @@ -2111,6 +2118,7 @@ fn parse_binary_op( Token::In => { // Swap the arguments let current_lhs = args.remove(0); + let pos = current_lhs.start_position(); args.push(current_lhs); args.shrink_to_fit(); @@ -2132,6 +2140,7 @@ fn parse_binary_op( .map_or(false, Option::is_some) => { let hash = calc_fn_hash(&s, 2); + let pos = args[0].start_position(); FnCallExpr { hashes: if is_valid_function_name(&s) { @@ -2145,7 +2154,10 @@ fn parse_binary_op( .into_fn_call_expr(pos) } - _ => FnCallExpr { args, ..op_base }.into_fn_call_expr(pos), + _ => { + let pos = args[0].start_position(); + FnCallExpr { args, ..op_base }.into_fn_call_expr(pos) + } }; } } @@ -2734,13 +2746,10 @@ fn parse_block( #[cfg(not(feature = "no_module"))] let orig_imports_len = state.imports.len(); - loop { + let end_pos = loop { // Terminated? match input.peek().expect(NEVER_ENDS) { - (Token::RightBrace, _) => { - eat_token(input, Token::RightBrace); - break; - } + (Token::RightBrace, _) => break eat_token(input, Token::RightBrace), (Token::EOF, pos) => { return Err(PERR::MissingToken( Token::RightBrace.into(), @@ -2767,10 +2776,7 @@ fn parse_block( match input.peek().expect(NEVER_ENDS) { // { ... stmt } - (Token::RightBrace, _) => { - eat_token(input, Token::RightBrace); - break; - } + (Token::RightBrace, _) => break eat_token(input, Token::RightBrace), // { ... stmt; (Token::SemiColon, _) if need_semicolon => { eat_token(input, Token::SemiColon); @@ -2793,7 +2799,7 @@ fn parse_block( .into_err(*pos)); } } - } + }; state.stack.truncate(state.entry_stack_len); state.entry_stack_len = prev_entry_stack_len; @@ -2801,7 +2807,10 @@ fn parse_block( #[cfg(not(feature = "no_module"))] state.imports.truncate(orig_imports_len); - Ok(Stmt::Block(statements.into_boxed_slice(), settings.pos)) + Ok(Stmt::Block( + statements.into_boxed_slice(), + (settings.pos, end_pos), + )) } /// Parse an expression as a statement. @@ -3244,6 +3253,7 @@ fn make_curry_from_externals( num_externals + 1, )), args, + pos, ..Default::default() } .into_fn_call_expr(pos); @@ -3253,7 +3263,7 @@ fn make_curry_from_externals( let mut statements = StaticVec::with_capacity(externals.len() + 1); statements.extend(externals.into_iter().map(Stmt::Share)); statements.push(Stmt::Expr(expr)); - Expr::Stmt(crate::ast::StmtBlock::new(statements, pos).into()) + Expr::Stmt(crate::ast::StmtBlock::new(statements, pos, Position::NONE).into()) } /// Parse an anonymous function definition.