Fix positions.
This commit is contained in:
parent
3050e38c5e
commit
d23d1159ab
@ -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(),
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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),
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -940,7 +940,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
||||
while n < x.len() - 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(); }
|
||||
(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(); }
|
||||
(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(); }
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -257,16 +257,19 @@ impl fmt::Display for Position {
|
||||
|
||||
impl fmt::Debug for Position {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
#[cfg(not(feature = "no_position"))]
|
||||
if self.is_beginning_of_line() {
|
||||
write!(f, "{}", self.line)?;
|
||||
if self.is_none() {
|
||||
f.write_str("none")
|
||||
} else {
|
||||
write!(f, "{}:{}", self.line, self.pos)?;
|
||||
}
|
||||
#[cfg(feature = "no_position")]
|
||||
f.write_str("none")?;
|
||||
#[cfg(not(feature = "no_position"))]
|
||||
if self.is_beginning_of_line() {
|
||||
write!(f, "{}", self.line)
|
||||
} else {
|
||||
write!(f, "{}:{}", self.line, self.pos)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
#[cfg(feature = "no_position")]
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user