Skip to content

Replace row/column based Location with byte-offsets. #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ include = ["LICENSE", "Cargo.toml", "src/**/*.rs"]
resolver = "2"
members = [
"ast", "core", "literal", "parser",
"ruff_text_size",
]

[workspace.dependencies]
Expand Down
65 changes: 49 additions & 16 deletions ast/asdl_rs.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,13 +238,18 @@ def visitField(self, field, parent, vis, depth, constructor=None):
if fieldtype and fieldtype.has_userdata:
typ = f"{typ}<U>"
# don't box if we're doing Vec<T>, but do box if we're doing Vec<Option<Box<T>>>
if fieldtype and fieldtype.boxed and (not (parent.product or field.seq) or field.opt):
if (
fieldtype
and fieldtype.boxed
and (not (parent.product or field.seq) or field.opt)
):
typ = f"Box<{typ}>"
if field.opt or (
# When a dictionary literal contains dictionary unpacking (e.g., `{**d}`),
# the expression to be unpacked goes in `values` with a `None` at the corresponding
# position in `keys`. To handle this, the type of `keys` needs to be `Option<Vec<T>>`.
constructor == "Dict" and field.name == "keys"
constructor == "Dict"
and field.name == "keys"
):
typ = f"Option<{typ}>"
if field.seq:
Expand Down Expand Up @@ -311,7 +316,7 @@ def visitModule(self, mod, depth):
depth,
)
self.emit(
"Ok(Located { custom: folder.map_user(node.custom)?, location: node.location, end_location: node.end_location, node: f(folder, node.node)? })",
"Ok(Located { custom: folder.map_user(node.custom)?, range: node.range, node: f(folder, node.node)? })",
depth + 1,
)
self.emit("}", depth)
Expand Down Expand Up @@ -649,7 +654,7 @@ def write_ast_def(mod, typeinfo, f):
#![allow(clippy::derive_partial_eq_without_eq)]

pub use crate::constant::*;
pub use crate::Location;
pub use rustpython_compiler_core::text_size::{TextSize, TextRange};

type Ident = String;
\n
Expand All @@ -661,26 +666,54 @@ def write_ast_def(mod, typeinfo, f):
textwrap.dedent(
"""
pub struct Located<T, U = ()> {
pub location: Location,
pub end_location: Option<Location>,
pub range: TextRange,
pub custom: U,
pub node: T,
}

impl<T> Located<T> {
pub fn new(location: Location, end_location: Location, node: T) -> Self {
Self { location, end_location: Some(end_location), custom: (), node }
pub fn new(start: TextSize, end: TextSize, node: T) -> Self {
Self { range: TextRange::new(start, end), custom: (), node }
}

pub const fn start(&self) -> Location {
self.location
/// Creates a new node that spans the position specified by `range`.
pub fn with_range(node: T, range: TextRange) -> Self {
Self {
range,
custom: (),
node,
}
}

/// Returns the absolute start position of the node from the beginning of the document.
#[inline]
pub const fn start(&self) -> TextSize {
self.range.start()
}

/// Returns the node
#[inline]
pub fn node(&self) -> &T {
&self.node
}

/// Consumes self and returns the node.
#[inline]
pub fn into_node(self) -> T {
self.node
}

/// Returns the `range` of the node. The range offsets are absolute to the start of the document.
#[inline]
pub const fn range(&self) -> TextRange {
self.range
}

/// Returns the absolute position at which the node ends in the source document.
#[inline]
pub const fn end(&self) -> TextSize {
self.range.end()
}

/// Returns the node's [`end_location`](Located::end_location) or [`location`](Located::start) if
/// [`end_location`](Located::end_location) is `None`.
pub fn end(&self) -> Location {
self.end_location.unwrap_or(self.location)
}
}

impl<T, U> std::ops::Deref for Located<T, U> {
Expand Down
54 changes: 40 additions & 14 deletions ast/src/ast_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,63 @@
#![allow(clippy::derive_partial_eq_without_eq)]

pub use crate::constant::*;
pub use crate::Location;
pub use rustpython_compiler_core::text_size::{TextRange, TextSize};

type Ident = String;

#[derive(Clone, Debug, PartialEq)]
pub struct Located<T, U = ()> {
pub location: Location,
pub end_location: Option<Location>,
pub range: TextRange,
pub custom: U,
pub node: T,
}

impl<T> Located<T> {
pub fn new(location: Location, end_location: Location, node: T) -> Self {
pub fn new(start: TextSize, end: TextSize, node: T) -> Self {
Self {
location,
end_location: Some(end_location),
range: TextRange::new(start, end),
custom: (),
node,
}
}

pub const fn start(&self) -> Location {
self.location
/// Creates a new node that spans the position specified by `range`.
pub fn with_range(node: T, range: TextRange) -> Self {
Self {
range,
custom: (),
node,
}
}

/// Returns the absolute start position of the node from the beginning of the document.
#[inline]
pub const fn start(&self) -> TextSize {
self.range.start()
}

/// Returns the node
#[inline]
pub fn node(&self) -> &T {
&self.node
}

/// Consumes self and returns the node.
#[inline]
pub fn into_node(self) -> T {
self.node
}

/// Returns the `range` of the node. The range offsets are absolute to the start of the document.
#[inline]
pub const fn range(&self) -> TextRange {
self.range
}

/// Returns the node's [`end_location`](Located::end_location) or [`location`](Located::start) if
/// [`end_location`](Located::end_location) is `None`.
pub fn end(&self) -> Location {
self.end_location.unwrap_or(self.location)
/// Returns the absolute position at which the node ends in the source document.
#[inline]
pub const fn end(&self) -> TextSize {
self.range.end()
}
}

Expand Down Expand Up @@ -554,8 +581,7 @@ pub mod fold {
) -> Result<Located<MT, F::TargetU>, F::Error> {
Ok(Located {
custom: folder.map_user(node.custom)?,
location: node.location,
end_location: node.end_location,
range: node.range,
node: f(folder, node.node)?,
})
}
Expand Down
31 changes: 11 additions & 20 deletions ast/src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,7 @@ impl<U> crate::fold::Fold<U> for ConstantOptimizer {
Ok(crate::Expr {
node: expr,
custom: node.custom,
location: node.location,
end_location: node.end_location,
range: node.range,
})
}
_ => crate::fold::fold_expr(self, node),
Expand All @@ -144,62 +143,55 @@ mod tests {
fn test_constant_opt() {
use crate::{fold::Fold, *};

let start = Default::default();
let end = None;
let range = TextRange::default();
#[allow(clippy::let_unit_value)]
let custom = ();
let ast = Located {
location: start,
end_location: end,
range,
custom,
node: ExprKind::Tuple {
ctx: ExprContext::Load,
elts: vec![
Located {
location: start,
end_location: end,
range,
custom,
node: ExprKind::Constant {
value: BigInt::from(1).into(),
kind: None,
},
},
Located {
location: start,
end_location: end,
range,
custom,
node: ExprKind::Constant {
value: BigInt::from(2).into(),
kind: None,
},
},
Located {
location: start,
end_location: end,
range,
custom,
node: ExprKind::Tuple {
ctx: ExprContext::Load,
elts: vec![
Located {
location: start,
end_location: end,
range,
custom,
node: ExprKind::Constant {
value: BigInt::from(3).into(),
kind: None,
},
},
Located {
location: start,
end_location: end,
range,
custom,
node: ExprKind::Constant {
value: BigInt::from(4).into(),
kind: None,
},
},
Located {
location: start,
end_location: end,
range,
custom,
node: ExprKind::Constant {
value: BigInt::from(5).into(),
Expand All @@ -218,8 +210,7 @@ mod tests {
assert_eq!(
new_ast,
Located {
location: start,
end_location: end,
range,
custom,
node: ExprKind::Constant {
value: Constant::Tuple(vec![
Expand Down
1 change: 0 additions & 1 deletion ast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ mod impls;
mod unparse;

pub use ast_gen::*;
pub use rustpython_compiler_core::Location;

pub type Suite<U = ()> = Vec<Stmt<U>>;
3 changes: 2 additions & 1 deletion core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ license = "MIT"

[dependencies]
bitflags = { workspace = true }
bstr = { workspace = true }
itertools = { workspace = true }
num-bigint = { workspace = true }
num-complex = { workspace = true }
serde = { version = "1.0.133", optional = true, default-features = false, features = ["derive"] }
ruff_text_size = { path = "../ruff_text_size" }

lz4_flex = "0.9.2"

11 changes: 8 additions & 3 deletions core/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::Location;
use ruff_text_size::TextSize;
use std::error::Error as StdError;
use std::fmt::Display;

#[derive(Debug, PartialEq, Eq)]
pub struct BaseError<T> {
pub error: T,
pub location: Location,
pub location: TextSize,
pub source_path: String,
}

Expand All @@ -31,7 +31,12 @@ where
T: std::fmt::Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.location.fmt_with(f, &self.error)
write!(
f,
"{} at byte offset {}",
&self.error,
u32::from(self.location)
)
}
}

Expand Down
2 changes: 2 additions & 0 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ pub use bytecode::*;
pub use error::BaseError;
pub use location::Location;
pub use mode::Mode;

pub use ruff_text_size as text_size; // re-export mandatory and frequently accessed dependency
6 changes: 2 additions & 4 deletions parser/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use crate::{
ast,
lexer::{LexicalError, LexicalErrorType},
text_size::TextSize,
};
use rustc_hash::FxHashSet;

Expand Down Expand Up @@ -83,10 +84,7 @@ pub(crate) fn parse_params(
Ok((pos_only, names, defaults))
}

type FunctionArgument = (
Option<(ast::Location, ast::Location, Option<String>)>,
ast::Expr,
);
type FunctionArgument = (Option<(TextSize, TextSize, Option<String>)>, ast::Expr);

// Parse arguments as supplied during a function/lambda *call*.
pub(crate) fn parse_args(func_args: Vec<FunctionArgument>) -> Result<ArgumentList, LexicalError> {
Expand Down
Loading