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<'_> {
/// Get the [`Position`] of this [`ASTNode`].
pub const fn position(&self) -> Position {
pub fn position(&self) -> Position {
match self {
ASTNode::Stmt(stmt) => stmt.position(),
ASTNode::Expr(expr) => expr.position(),

View File

@ -440,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.start_position();
let mut display_pos = format!(" @ {:?}", self.start_position());
match self {
Self::DynamicConstant(value, ..) => write!(f, "{:?}", value),
@ -470,24 +470,34 @@ impl fmt::Debug for Expr {
f.write_str("Variable(")?;
#[cfg(not(feature = "no_module"))]
if let Some((.., ref namespace)) = x.1 {
write!(f, "{}{}", namespace, Token::DoubleColon.literal_syntax())?
if let Some((ref namespace, ..)) = x.1 {
write!(f, "{}{}", namespace, Token::DoubleColon.literal_syntax())?;
let pos = namespace.position();
if !pos.is_none() {
display_pos = format!(" @ {:?}", pos);
}
}
f.write_str(&x.2)?;
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(")")
}
Self::Property(x, ..) => write!(f, "Property({})", x.2),
Self::Stack(x, ..) => write!(f, "ConstantArg[{}]", x),
Self::Stmt(x) => {
let pos = x.span();
if !pos.is_none() {
display_pos = format!(" @ {:?}", pos);
}
f.write_str("ExprStmtBlock")?;
f.debug_list().entries(x.iter()).finish()
}
Self::FnCall(x, ..) => fmt::Debug::fmt(x, f),
Self::Index(x, term, pos) => {
display_pos = *pos;
if !pos.is_none() {
display_pos = format!(" @ {:?}", pos);
}
f.debug_struct("Index")
.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)
.field("lhs", &x.lhs)
@ -516,7 +528,7 @@ impl fmt::Debug for Expr {
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.
#[inline]
#[must_use]
pub const fn start_position(&self) -> Position {
pub fn start_position(&self) -> Position {
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, ..) => {
x.lhs.start_position()
}

View File

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

View File

@ -325,7 +325,13 @@ fn main() {
exit(0);
}
["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!();
}
["list" | "l", ..] => print_current_source(context, source, pos, &lines),

View File

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

View File

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

View File

@ -3,7 +3,7 @@
use crate::ast::Ident;
use crate::tokenizer::Token;
use crate::StaticVec;
use crate::{Position, StaticVec};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{
@ -114,4 +114,12 @@ impl Namespace {
pub(crate) fn set_index(&mut self, index: Option<NonZeroUsize>) {
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

@ -1291,8 +1291,9 @@ fn parse_primary(
let mut segments = StaticVec::<Expr>::new();
match input.next().expect(NEVER_ENDS) {
(Token::InterpolatedString(s), ..) if s.is_empty() => (),
(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),
}
@ -1302,7 +1303,10 @@ fn parse_primary(
block @ Stmt::Block(..) => Expr::Stmt(Box::new(block.into())),
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
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();
Expr::InterpolatedString(segments.into(), settings.pos)
}

View File

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