Fix positions.

This commit is contained in:
Stephen Chung 2022-02-10 17:55:32 +08:00
parent 3050e38c5e
commit d23d1159ab
10 changed files with 95 additions and 53 deletions

View File

@ -879,7 +879,7 @@ impl Eq for ASTNode<'_> {}
impl ASTNode<'_> { impl ASTNode<'_> {
/// Get the [`Position`] of this [`ASTNode`]. /// Get the [`Position`] of this [`ASTNode`].
pub const fn position(&self) -> Position { pub fn position(&self) -> Position {
match self { match self {
ASTNode::Stmt(stmt) => stmt.position(), ASTNode::Stmt(stmt) => stmt.position(),
ASTNode::Expr(expr) => expr.position(), ASTNode::Expr(expr) => expr.position(),

View File

@ -440,7 +440,7 @@ impl Default for Expr {
impl fmt::Debug for Expr { impl fmt::Debug for Expr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut display_pos = self.start_position(); let mut display_pos = format!(" @ {:?}", self.start_position());
match self { match self {
Self::DynamicConstant(value, ..) => write!(f, "{:?}", value), Self::DynamicConstant(value, ..) => write!(f, "{:?}", value),
@ -470,24 +470,34 @@ impl fmt::Debug for Expr {
f.write_str("Variable(")?; f.write_str("Variable(")?;
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
if let Some((.., ref namespace)) = x.1 { if let Some((ref namespace, ..)) = x.1 {
write!(f, "{}{}", namespace, Token::DoubleColon.literal_syntax())? write!(f, "{}{}", namespace, Token::DoubleColon.literal_syntax())?;
let pos = namespace.position();
if !pos.is_none() {
display_pos = format!(" @ {:?}", pos);
}
} }
f.write_str(&x.2)?; f.write_str(&x.2)?;
if let Some(n) = i.map_or_else(|| x.0, |n| NonZeroUsize::new(n.get() as usize)) { if let Some(n) = i.map_or_else(|| x.0, |n| NonZeroUsize::new(n.get() as usize)) {
write!(f, " #{}", n)? write!(f, " #{}", n)?;
} }
f.write_str(")") f.write_str(")")
} }
Self::Property(x, ..) => write!(f, "Property({})", x.2), Self::Property(x, ..) => write!(f, "Property({})", x.2),
Self::Stack(x, ..) => write!(f, "ConstantArg[{}]", x), Self::Stack(x, ..) => write!(f, "ConstantArg[{}]", x),
Self::Stmt(x) => { Self::Stmt(x) => {
let pos = x.span();
if !pos.is_none() {
display_pos = format!(" @ {:?}", pos);
}
f.write_str("ExprStmtBlock")?; f.write_str("ExprStmtBlock")?;
f.debug_list().entries(x.iter()).finish() f.debug_list().entries(x.iter()).finish()
} }
Self::FnCall(x, ..) => fmt::Debug::fmt(x, f), Self::FnCall(x, ..) => fmt::Debug::fmt(x, f),
Self::Index(x, term, pos) => { Self::Index(x, term, pos) => {
display_pos = *pos; if !pos.is_none() {
display_pos = format!(" @ {:?}", pos);
}
f.debug_struct("Index") f.debug_struct("Index")
.field("lhs", &x.lhs) .field("lhs", &x.lhs)
@ -506,7 +516,9 @@ impl fmt::Debug for Expr {
), ),
}; };
display_pos = *pos; if !pos.is_none() {
display_pos = format!(" @ {:?}", pos);
}
f.debug_struct(op_name) f.debug_struct(op_name)
.field("lhs", &x.lhs) .field("lhs", &x.lhs)
@ -516,7 +528,7 @@ impl fmt::Debug for Expr {
Self::Custom(x, ..) => f.debug_tuple("Custom").field(x).finish(), Self::Custom(x, ..) => f.debug_tuple("Custom").field(x).finish(),
}?; }?;
display_pos.debug_print(f) f.write_str(&display_pos)
} }
} }
@ -708,8 +720,16 @@ impl Expr {
/// For a binary expression, this will be the left-most LHS instead of the operator. /// For a binary expression, this will be the left-most LHS instead of the operator.
#[inline] #[inline]
#[must_use] #[must_use]
pub const fn start_position(&self) -> Position { pub fn start_position(&self) -> Position {
match self { match self {
#[cfg(not(feature = "no_module"))]
Self::Variable(.., x) => {
if let Some((ref namespace, ..)) = x.1 {
namespace.position()
} else {
self.position()
}
}
Self::And(x, ..) | Self::Or(x, ..) | Self::Index(x, ..) | Self::Dot(x, ..) => { Self::And(x, ..) | Self::Or(x, ..) | Self::Index(x, ..) | Self::Dot(x, ..) => {
x.lhs.start_position() x.lhs.start_position()
} }

View File

@ -402,7 +402,7 @@ impl Stmt {
} }
/// Get the [position][Position] of this statement. /// Get the [position][Position] of this statement.
#[must_use] #[must_use]
pub const fn position(&self) -> Position { pub fn position(&self) -> Position {
match self { match self {
Self::Noop(pos) Self::Noop(pos)
| Self::BreakLoop(.., pos) | Self::BreakLoop(.., pos)

View File

@ -325,7 +325,13 @@ fn main() {
exit(0); exit(0);
} }
["node", ..] => { ["node", ..] => {
println!("{:?} {}@{:?}", node, source.unwrap_or_default(), pos); if pos.is_none() {
println!("{:?}", node);
} else if let Some(source) = source {
println!("{:?} {} @ {:?}", node, source, pos);
} else {
println!("{:?} @ {:?}", node, pos);
}
println!(); println!();
} }
["list" | "l", ..] => print_current_source(context, source, pos, &lines), ["list" | "l", ..] => print_current_source(context, source, pos, &lines),

View File

@ -147,7 +147,6 @@ impl Engine {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
ChainType::Indexing => { ChainType::Indexing => {
let pos = rhs.start_position(); let pos = rhs.start_position();
let root_pos = idx_val.position();
let idx_val = idx_val.into_index_value().expect("`ChainType::Index`"); let idx_val = idx_val.into_index_value().expect("`ChainType::Index`");
match rhs { match rhs {
@ -190,7 +189,7 @@ impl Engine {
) )
.or_else(|idx_err| match *idx_err { .or_else(|idx_err| match *idx_err {
ERR::ErrorIndexingType(..) => Ok((Dynamic::UNIT, false)), ERR::ErrorIndexingType(..) => Ok((Dynamic::UNIT, false)),
_ => Err(idx_err.fill_position(root_pos)), _ => Err(idx_err),
})?; })?;
} }
@ -231,8 +230,7 @@ impl Engine {
let new_val = &mut new_val; let new_val = &mut new_val;
self.call_indexer_set( self.call_indexer_set(
global, state, lib, target, idx, new_val, is_ref_mut, level, global, state, lib, target, idx, new_val, is_ref_mut, level,
) )?;
.map_err(|err| err.fill_position(root_pos))?;
} }
Ok((Dynamic::UNIT, true)) Ok((Dynamic::UNIT, true))
@ -506,7 +504,7 @@ impl Engine {
.map_err( .map_err(
|idx_err| match *idx_err { |idx_err| match *idx_err {
ERR::ErrorIndexingType(..) => err, ERR::ErrorIndexingType(..) => err,
_ => idx_err.fill_position(pos), _ => idx_err,
}, },
) )
} }
@ -553,12 +551,12 @@ impl Engine {
is_ref_mut, level, is_ref_mut, level,
) )
.or_else(|idx_err| match *idx_err { .or_else(|idx_err| match *idx_err {
// If there is no setter, no need to feed it
// back because the property is read-only
ERR::ErrorIndexingType(..) => { ERR::ErrorIndexingType(..) => {
// If there is no setter, no need to feed it back because
// the property is read-only
Ok((Dynamic::UNIT, false)) Ok((Dynamic::UNIT, false))
} }
_ => Err(idx_err.fill_position(pos)), _ => Err(idx_err),
}) })
} }
_ => Err(err), _ => Err(err),
@ -872,7 +870,7 @@ impl Engine {
lib: &[&Module], lib: &[&Module],
target: &'t mut Dynamic, target: &'t mut Dynamic,
idx: Dynamic, idx: Dynamic,
pos: Position, idx_pos: Position,
add_if_not_found: bool, add_if_not_found: bool,
use_indexers: bool, use_indexers: bool,
level: usize, level: usize,
@ -889,10 +887,10 @@ impl Engine {
// val_array[idx] // val_array[idx]
let index = idx let index = idx
.as_int() .as_int()
.map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, pos))?; .map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, idx_pos))?;
let len = arr.len(); let len = arr.len();
let arr_idx = super::calc_index(len, index, true, || { let arr_idx = super::calc_index(len, index, true, || {
ERR::ErrorArrayBounds(len, index, pos).into() ERR::ErrorArrayBounds(len, index, idx_pos).into()
})?; })?;
Ok(arr.get_mut(arr_idx).map(Target::from).unwrap()) Ok(arr.get_mut(arr_idx).map(Target::from).unwrap())
@ -903,10 +901,10 @@ impl Engine {
// val_blob[idx] // val_blob[idx]
let index = idx let index = idx
.as_int() .as_int()
.map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, pos))?; .map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, idx_pos))?;
let len = arr.len(); let len = arr.len();
let arr_idx = super::calc_index(len, index, true, || { let arr_idx = super::calc_index(len, index, true, || {
ERR::ErrorArrayBounds(len, index, pos).into() ERR::ErrorArrayBounds(len, index, idx_pos).into()
})?; })?;
let value = arr.get(arr_idx).map(|&v| (v as crate::INT).into()).unwrap(); let value = arr.get(arr_idx).map(|&v| (v as crate::INT).into()).unwrap();
@ -922,7 +920,7 @@ impl Engine {
Dynamic(Union::Map(map, ..)) => { Dynamic(Union::Map(map, ..)) => {
// val_map[idx] // val_map[idx]
let index = idx.read_lock::<crate::ImmutableString>().ok_or_else(|| { let index = idx.read_lock::<crate::ImmutableString>().ok_or_else(|| {
self.make_type_mismatch_err::<crate::ImmutableString>(idx.type_name(), pos) self.make_type_mismatch_err::<crate::ImmutableString>(idx.type_name(), idx_pos)
})?; })?;
if _add_if_not_found && !map.contains_key(index.as_str()) { if _add_if_not_found && !map.contains_key(index.as_str()) {
@ -932,7 +930,7 @@ impl Engine {
if let Some(value) = map.get_mut(index.as_str()) { if let Some(value) = map.get_mut(index.as_str()) {
Ok(Target::from(value)) Ok(Target::from(value))
} else if self.fail_on_invalid_map_property() { } else if self.fail_on_invalid_map_property() {
Err(ERR::ErrorPropertyNotFound(index.to_string(), pos).into()) Err(ERR::ErrorPropertyNotFound(index.to_string(), idx_pos).into())
} else { } else {
Ok(Target::from(Dynamic::UNIT)) Ok(Target::from(Dynamic::UNIT))
} }
@ -950,10 +948,10 @@ impl Engine {
let end = range.end; let end = range.end;
let start = super::calc_index(BITS, start, false, || { let start = super::calc_index(BITS, start, false, || {
ERR::ErrorBitFieldBounds(BITS, start, pos).into() ERR::ErrorBitFieldBounds(BITS, start, idx_pos).into()
})?; })?;
let end = super::calc_index(BITS, end, false, || { let end = super::calc_index(BITS, end, false, || {
ERR::ErrorBitFieldBounds(BITS, end, pos).into() ERR::ErrorBitFieldBounds(BITS, end, idx_pos).into()
})?; })?;
if end <= start { if end <= start {
@ -975,10 +973,10 @@ impl Engine {
let end = *range.end(); let end = *range.end();
let start = super::calc_index(BITS, start, false, || { let start = super::calc_index(BITS, start, false, || {
ERR::ErrorBitFieldBounds(BITS, start, pos).into() ERR::ErrorBitFieldBounds(BITS, start, idx_pos).into()
})?; })?;
let end = super::calc_index(BITS, end, false, || { let end = super::calc_index(BITS, end, false, || {
ERR::ErrorBitFieldBounds(BITS, end, pos).into() ERR::ErrorBitFieldBounds(BITS, end, idx_pos).into()
})?; })?;
if end < start { if end < start {
@ -1014,12 +1012,12 @@ impl Engine {
// val_int[idx] // val_int[idx]
let index = idx let index = idx
.as_int() .as_int()
.map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, pos))?; .map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, idx_pos))?;
const BITS: usize = std::mem::size_of::<crate::INT>() * 8; const BITS: usize = std::mem::size_of::<crate::INT>() * 8;
let bit = super::calc_index(BITS, index, true, || { let bit = super::calc_index(BITS, index, true, || {
ERR::ErrorBitFieldBounds(BITS, index, pos).into() ERR::ErrorBitFieldBounds(BITS, index, idx_pos).into()
})?; })?;
let bit_value = (*value & (1 << bit)) != 0; let bit_value = (*value & (1 << bit)) != 0;
@ -1036,14 +1034,14 @@ impl Engine {
// val_string[idx] // val_string[idx]
let index = idx let index = idx
.as_int() .as_int()
.map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, pos))?; .map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, idx_pos))?;
let (ch, offset) = if index >= 0 { let (ch, offset) = if index >= 0 {
let offset = index as usize; let offset = index as usize;
( (
s.chars().nth(offset).ok_or_else(|| { s.chars().nth(offset).ok_or_else(|| {
let chars_len = s.chars().count(); let chars_len = s.chars().count();
ERR::ErrorStringBounds(chars_len, index, pos) ERR::ErrorStringBounds(chars_len, index, idx_pos)
})?, })?,
offset, offset,
) )
@ -1053,13 +1051,13 @@ impl Engine {
// Count from end if negative // Count from end if negative
s.chars().rev().nth(offset - 1).ok_or_else(|| { s.chars().rev().nth(offset - 1).ok_or_else(|| {
let chars_len = s.chars().count(); let chars_len = s.chars().count();
ERR::ErrorStringBounds(chars_len, index, pos) ERR::ErrorStringBounds(chars_len, index, idx_pos)
})?, })?,
offset, offset,
) )
} else { } else {
let chars_len = s.chars().count(); let chars_len = s.chars().count();
return Err(ERR::ErrorStringBounds(chars_len, index, pos).into()); return Err(ERR::ErrorStringBounds(chars_len, index, idx_pos).into());
}; };
Ok(Target::StringChar { Ok(Target::StringChar {

View File

@ -327,8 +327,7 @@ impl Engine {
Expr::Unit(..) => Ok(Dynamic::UNIT), Expr::Unit(..) => Ok(Dynamic::UNIT),
// `... ${...} ...` // `... ${...} ...`
Expr::InterpolatedString(x, pos) => { Expr::InterpolatedString(x, _) => {
let mut pos = *pos;
let mut concat: Dynamic = self.const_empty_string().into(); let mut concat: Dynamic = self.const_empty_string().into();
let mut result = Ok(Dynamic::UNIT); let mut result = Ok(Dynamic::UNIT);
@ -347,7 +346,7 @@ impl Engine {
state, state,
lib, lib,
Some(OpAssignment::new(OP_CONCAT)), Some(OpAssignment::new(OP_CONCAT)),
pos, expr.start_position(),
&mut (&mut concat).into(), &mut (&mut concat).into(),
("", Position::NONE), ("", Position::NONE),
item, item,
@ -356,8 +355,6 @@ impl Engine {
result = Err(err.fill_position(expr.start_position())); result = Err(err.fill_position(expr.start_position()));
break; break;
} }
pos = expr.start_position();
} }
result.map(|_| concat) result.map(|_| concat)

View File

@ -3,7 +3,7 @@
use crate::ast::Ident; use crate::ast::Ident;
use crate::tokenizer::Token; use crate::tokenizer::Token;
use crate::StaticVec; use crate::{Position, StaticVec};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
use std::{ use std::{
@ -114,4 +114,12 @@ impl Namespace {
pub(crate) fn set_index(&mut self, index: Option<NonZeroUsize>) { pub(crate) fn set_index(&mut self, index: Option<NonZeroUsize>) {
self.index = index self.index = index
} }
/// Get the [position][Position] of this [`NameSpace`].
///
/// # Panics
///
/// Panics if the path is empty.
pub fn position(&self) -> Position {
self.path[0].pos
}
} }

View File

@ -940,7 +940,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
while n < x.len() - 1 { while n < x.len() - 1 {
match (mem::take(&mut x[n]), mem::take(&mut x[n+1])) { match (mem::take(&mut x[n]), mem::take(&mut x[n+1])) {
(Expr::StringConstant(mut s1, pos), Expr::StringConstant(s2, ..)) => { s1 += s2; x[n] = Expr::StringConstant(s1, pos); x.remove(n+1); state.set_dirty(); } (Expr::StringConstant(mut s1, pos), Expr::StringConstant(s2, ..)) => { s1 += s2; x[n] = Expr::StringConstant(s1, pos); x.remove(n+1); state.set_dirty(); }
(expr1, Expr::Unit(..)) => { x[n] = expr1; x.remove(n+1); state.set_dirty(); } (expr1, Expr::Unit(..)) => { x[n] = expr1; x.remove(n+1); state.set_dirty(); }
(Expr::Unit(..), expr2) => { x[n+1] = expr2; x.remove(n); state.set_dirty(); } (Expr::Unit(..), expr2) => { x[n+1] = expr2; x.remove(n); state.set_dirty(); }
(expr1, Expr::StringConstant(s, ..)) if s.is_empty() => { x[n] = expr1; x.remove(n+1); state.set_dirty(); } (expr1, Expr::StringConstant(s, ..)) if s.is_empty() => { x[n] = expr1; x.remove(n+1); state.set_dirty(); }
(Expr::StringConstant(s, ..), expr2) if s.is_empty()=> { x[n+1] = expr2; x.remove(n); state.set_dirty(); } (Expr::StringConstant(s, ..), expr2) if s.is_empty()=> { x[n+1] = expr2; x.remove(n); state.set_dirty(); }

View File

@ -1291,8 +1291,9 @@ fn parse_primary(
let mut segments = StaticVec::<Expr>::new(); let mut segments = StaticVec::<Expr>::new();
match input.next().expect(NEVER_ENDS) { match input.next().expect(NEVER_ENDS) {
(Token::InterpolatedString(s), ..) if s.is_empty() => (),
(Token::InterpolatedString(s), pos) => { (Token::InterpolatedString(s), pos) => {
segments.push(Expr::StringConstant(s.into(), pos)); segments.push(Expr::StringConstant(s.into(), pos))
} }
token => unreachable!("Token::InterpolatedString expected but gets {:?}", token), token => unreachable!("Token::InterpolatedString expected but gets {:?}", token),
} }
@ -1302,7 +1303,10 @@ fn parse_primary(
block @ Stmt::Block(..) => Expr::Stmt(Box::new(block.into())), block @ Stmt::Block(..) => Expr::Stmt(Box::new(block.into())),
stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt), stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt),
}; };
segments.push(expr); match expr {
Expr::StringConstant(s, ..) if s.is_empty() => (),
_ => segments.push(expr),
}
// Make sure to parse the following as text // Make sure to parse the following as text
let mut control = state.tokenizer_control.get(); let mut control = state.tokenizer_control.get();
@ -1332,6 +1336,12 @@ fn parse_primary(
} }
} }
if segments.is_empty() {
segments.push(Expr::StringConstant(
state.get_interned_string("", ""),
settings.pos,
));
}
segments.shrink_to_fit(); segments.shrink_to_fit();
Expr::InterpolatedString(segments.into(), settings.pos) Expr::InterpolatedString(segments.into(), settings.pos)
} }

View File

@ -257,16 +257,19 @@ impl fmt::Display for Position {
impl fmt::Debug for Position { impl fmt::Debug for Position {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(not(feature = "no_position"))] if self.is_none() {
if self.is_beginning_of_line() { f.write_str("none")
write!(f, "{}", self.line)?;
} else { } else {
write!(f, "{}:{}", self.line, self.pos)?; #[cfg(not(feature = "no_position"))]
} if self.is_beginning_of_line() {
#[cfg(feature = "no_position")] write!(f, "{}", self.line)
f.write_str("none")?; } else {
write!(f, "{}:{}", self.line, self.pos)
}
Ok(()) #[cfg(feature = "no_position")]
unreachable!();
}
} }
} }