Compare commits
1 Commits
dcreager/f
...
dhruv/iden
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91c712cdb1 |
@@ -7,7 +7,7 @@ use rustc_hash::{FxBuildHasher, FxHashSet};
|
||||
use ruff_python_ast::name::Name;
|
||||
use ruff_python_ast::{
|
||||
self as ast, BoolOp, CmpOp, ConversionFlag, Expr, ExprContext, FStringElement, FStringElements,
|
||||
IpyEscapeKind, Number, Operator, UnaryOp,
|
||||
Identifier, IpyEscapeKind, Number, Operator, UnaryOp,
|
||||
};
|
||||
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
||||
|
||||
@@ -446,18 +446,13 @@ impl<'src> Parser<'src> {
|
||||
|
||||
/// Parses a name.
|
||||
///
|
||||
/// For an invalid name, the `id` field will be an empty string and the `ctx`
|
||||
/// field will be [`ExprContext::Invalid`].
|
||||
/// For an invalid name, the `id` field will be an empty string and if a keyword is used,
|
||||
/// the `id` field will be the keyword name. In both cases, the `ctx` field will be
|
||||
/// [`ExprContext::Invalid`].
|
||||
///
|
||||
/// See: <https://docs.python.org/3/reference/expressions.html#atom-identifiers>
|
||||
pub(super) fn parse_name(&mut self) -> ast::ExprName {
|
||||
let identifier = self.parse_identifier();
|
||||
|
||||
let ctx = if identifier.is_valid() {
|
||||
ExprContext::Load
|
||||
} else {
|
||||
ExprContext::Invalid
|
||||
};
|
||||
let (identifier, ctx) = self.parse_identifier().unwrap_with_context();
|
||||
|
||||
ast::ExprName {
|
||||
range: identifier.range,
|
||||
@@ -471,20 +466,20 @@ impl<'src> Parser<'src> {
|
||||
/// For an invalid identifier, the `id` field will be an empty string.
|
||||
///
|
||||
/// See: <https://docs.python.org/3/reference/expressions.html#atom-identifiers>
|
||||
pub(super) fn parse_identifier(&mut self) -> ast::Identifier {
|
||||
pub(super) fn parse_identifier(&mut self) -> IdentifierParseResult {
|
||||
let range = self.current_token_range();
|
||||
|
||||
if self.at(TokenKind::Name) {
|
||||
let TokenValue::Name(name) = self.bump_value(TokenKind::Name) else {
|
||||
unreachable!();
|
||||
};
|
||||
return ast::Identifier { id: name, range };
|
||||
return IdentifierParseResult::ok(name, range);
|
||||
}
|
||||
|
||||
if self.current_token_kind().is_soft_keyword() {
|
||||
let id = Name::new(self.src_text(range));
|
||||
let name = Name::new(self.src_text(range));
|
||||
self.bump_soft_keyword_as_name();
|
||||
return ast::Identifier { id, range };
|
||||
return IdentifierParseResult::ok(name, range);
|
||||
}
|
||||
|
||||
if self.current_token_kind().is_keyword() {
|
||||
@@ -497,19 +492,16 @@ impl<'src> Parser<'src> {
|
||||
range,
|
||||
);
|
||||
|
||||
let id = Name::new(self.src_text(range));
|
||||
let name = Name::new(self.src_text(range));
|
||||
self.bump_any();
|
||||
ast::Identifier { id, range }
|
||||
IdentifierParseResult::err(name, range)
|
||||
} else {
|
||||
self.add_error(
|
||||
ParseErrorType::OtherError("Expected an identifier".into()),
|
||||
range,
|
||||
);
|
||||
|
||||
ast::Identifier {
|
||||
id: Name::empty(),
|
||||
range: self.missing_node_range(),
|
||||
}
|
||||
IdentifierParseResult::err(Name::empty(), self.missing_node_range())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -942,12 +934,12 @@ impl<'src> Parser<'src> {
|
||||
) -> ast::ExprAttribute {
|
||||
self.bump(TokenKind::Dot);
|
||||
|
||||
let attr = self.parse_identifier();
|
||||
let (attr, ctx) = self.parse_identifier().unwrap_with_context();
|
||||
|
||||
ast::ExprAttribute {
|
||||
value: Box::new(value),
|
||||
attr,
|
||||
ctx: ExprContext::Load,
|
||||
ctx,
|
||||
range: self.node_range(start),
|
||||
}
|
||||
}
|
||||
@@ -2587,3 +2579,36 @@ impl ExpressionContext {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A result-like type that represents the result of parsing an identifier.
|
||||
pub(super) struct IdentifierParseResult(Result<Identifier, Identifier>);
|
||||
|
||||
impl IdentifierParseResult {
|
||||
fn ok(name: Name, range: TextRange) -> Self {
|
||||
IdentifierParseResult(Ok(Identifier { id: name, range }))
|
||||
}
|
||||
|
||||
fn err(name: Name, range: TextRange) -> Self {
|
||||
IdentifierParseResult(Err(Identifier { id: name, range }))
|
||||
}
|
||||
|
||||
/// Unwraps the result and returns the inner [`Identifier`].
|
||||
pub(super) fn into_inner(self) -> Identifier {
|
||||
match self.0 {
|
||||
Ok(identifier) | Err(identifier) => identifier,
|
||||
}
|
||||
}
|
||||
|
||||
/// Unwraps the result and returns the inner [`Identifier`] along with the [`ExprContext`].
|
||||
///
|
||||
/// If the result is [`Ok`], the context is [`Load`], otherwise it's [`Invalid`].
|
||||
///
|
||||
/// [`Load`]: ExprContext::Load
|
||||
/// [`Invalid`]: ExprContext::Invalid
|
||||
fn unwrap_with_context(self) -> (Identifier, ExprContext) {
|
||||
match self.0 {
|
||||
Ok(identifier) => (identifier, ExprContext::Load),
|
||||
Err(identifier) => (identifier, ExprContext::Invalid),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ impl Parser<'_> {
|
||||
self.add_error(ParseErrorType::InvalidStarPatternUsage, &lhs);
|
||||
}
|
||||
|
||||
let ident = self.parse_identifier();
|
||||
let ident = self.parse_identifier().into_inner();
|
||||
lhs = Pattern::MatchAs(ast::PatternMatchAs {
|
||||
range: self.node_range(start),
|
||||
name: Some(ident),
|
||||
@@ -183,7 +183,7 @@ impl Parser<'_> {
|
||||
let mapping_item_start = parser.node_start();
|
||||
|
||||
if parser.eat(TokenKind::DoubleStar) {
|
||||
let identifier = parser.parse_identifier();
|
||||
let identifier = parser.parse_identifier().into_inner();
|
||||
if rest.is_some() {
|
||||
parser.add_error(
|
||||
ParseErrorType::OtherError(
|
||||
@@ -258,7 +258,7 @@ impl Parser<'_> {
|
||||
let start = self.node_start();
|
||||
self.bump(TokenKind::Star);
|
||||
|
||||
let ident = self.parse_identifier();
|
||||
let ident = self.parse_identifier().into_inner();
|
||||
|
||||
ast::PatternMatchStar {
|
||||
range: self.node_range(start),
|
||||
@@ -490,7 +490,7 @@ impl Parser<'_> {
|
||||
// case case: ...
|
||||
// case match: ...
|
||||
// case type: ...
|
||||
let ident = self.parse_identifier();
|
||||
let ident = self.parse_identifier().into_inner();
|
||||
|
||||
// test_ok match_as_pattern
|
||||
// match foo:
|
||||
|
||||
@@ -635,7 +635,7 @@ impl<'src> Parser<'src> {
|
||||
|
||||
let name = match style {
|
||||
ImportStyle::Import => self.parse_dotted_name(),
|
||||
ImportStyle::ImportFrom => self.parse_identifier(),
|
||||
ImportStyle::ImportFrom => self.parse_identifier().into_inner(),
|
||||
};
|
||||
|
||||
let asname = if self.eat(TokenKind::As) {
|
||||
@@ -644,7 +644,7 @@ impl<'src> Parser<'src> {
|
||||
// import foo as match
|
||||
// import bar as case
|
||||
// import baz as type
|
||||
Some(self.parse_identifier())
|
||||
Some(self.parse_identifier().into_inner())
|
||||
} else {
|
||||
// test_err import_alias_missing_asname
|
||||
// import x as
|
||||
@@ -671,7 +671,7 @@ impl<'src> Parser<'src> {
|
||||
fn parse_dotted_name(&mut self) -> ast::Identifier {
|
||||
let start = self.node_start();
|
||||
|
||||
let mut dotted_name: CompactString = self.parse_identifier().id.into();
|
||||
let mut dotted_name: CompactString = self.parse_identifier().into_inner().id.into();
|
||||
let mut progress = ParserProgress::default();
|
||||
|
||||
while self.eat(TokenKind::Dot) {
|
||||
@@ -681,7 +681,7 @@ impl<'src> Parser<'src> {
|
||||
// import a..b
|
||||
// import a...b
|
||||
dotted_name.push('.');
|
||||
dotted_name.push_str(&self.parse_identifier());
|
||||
dotted_name.push_str(&self.parse_identifier().into_inner());
|
||||
}
|
||||
|
||||
// test_ok dotted_name_normalized_spaces
|
||||
@@ -805,10 +805,10 @@ impl<'src> Parser<'src> {
|
||||
|
||||
// test_err global_stmt_expression
|
||||
// global x + 1
|
||||
let names = self.parse_comma_separated_list_into_vec(
|
||||
RecoveryContextKind::Identifiers,
|
||||
Parser::parse_identifier,
|
||||
);
|
||||
let names = self
|
||||
.parse_comma_separated_list_into_vec(RecoveryContextKind::Identifiers, |p| {
|
||||
p.parse_identifier().into_inner()
|
||||
});
|
||||
|
||||
if names.is_empty() {
|
||||
// test_err global_stmt_empty
|
||||
@@ -843,10 +843,10 @@ impl<'src> Parser<'src> {
|
||||
|
||||
// test_err nonlocal_stmt_expression
|
||||
// nonlocal x + 1
|
||||
let names = self.parse_comma_separated_list_into_vec(
|
||||
RecoveryContextKind::Identifiers,
|
||||
Parser::parse_identifier,
|
||||
);
|
||||
let names = self
|
||||
.parse_comma_separated_list_into_vec(RecoveryContextKind::Identifiers, |p| {
|
||||
p.parse_identifier().into_inner()
|
||||
});
|
||||
|
||||
if names.is_empty() {
|
||||
// test_err nonlocal_stmt_empty
|
||||
@@ -1516,7 +1516,7 @@ impl<'src> Parser<'src> {
|
||||
// except Exception as match: ...
|
||||
// except Exception as case: ...
|
||||
// except Exception as type: ...
|
||||
Some(self.parse_identifier())
|
||||
Some(self.parse_identifier().into_inner())
|
||||
} else {
|
||||
// test_err except_stmt_missing_as_name
|
||||
// try:
|
||||
@@ -1712,7 +1712,7 @@ impl<'src> Parser<'src> {
|
||||
// test_err function_def_missing_identifier
|
||||
// def (): ...
|
||||
// def () -> int: ...
|
||||
let name = self.parse_identifier();
|
||||
let name = self.parse_identifier().into_inner();
|
||||
|
||||
// test_err function_def_unclosed_type_param_list
|
||||
// def foo[T1, *T2(a, b):
|
||||
@@ -1826,7 +1826,7 @@ impl<'src> Parser<'src> {
|
||||
// class : ...
|
||||
// class (): ...
|
||||
// class (metaclass=ABC): ...
|
||||
let name = self.parse_identifier();
|
||||
let name = self.parse_identifier().into_inner();
|
||||
|
||||
// test_err class_def_unclosed_type_param_list
|
||||
// class Foo[T1, *T2(a, b):
|
||||
@@ -2631,7 +2631,7 @@ impl<'src> Parser<'src> {
|
||||
function_kind: FunctionKind,
|
||||
allow_star_annotation: AllowStarAnnotation,
|
||||
) -> ast::Parameter {
|
||||
let name = self.parse_identifier();
|
||||
let name = self.parse_identifier().into_inner();
|
||||
|
||||
// Annotations are only allowed for function definition. For lambda expression,
|
||||
// the `:` token would indicate its body.
|
||||
@@ -3068,7 +3068,7 @@ impl<'src> Parser<'src> {
|
||||
// type X[T, *Ts] = int
|
||||
// type X[T, *Ts = int] = int
|
||||
if self.eat(TokenKind::Star) {
|
||||
let name = self.parse_identifier();
|
||||
let name = self.parse_identifier().into_inner();
|
||||
|
||||
let default = if self.eat(TokenKind::Equal) {
|
||||
if self.at_expr() {
|
||||
@@ -3112,7 +3112,7 @@ impl<'src> Parser<'src> {
|
||||
// type X[T, **P] = int
|
||||
// type X[T, **P = int] = int
|
||||
} else if self.eat(TokenKind::DoubleStar) {
|
||||
let name = self.parse_identifier();
|
||||
let name = self.parse_identifier().into_inner();
|
||||
|
||||
let default = if self.eat(TokenKind::Equal) {
|
||||
if self.at_expr() {
|
||||
@@ -3151,7 +3151,7 @@ impl<'src> Parser<'src> {
|
||||
// type X[T: (int, int) = int] = int
|
||||
// type X[T: int = int, U: (int, int) = int] = int
|
||||
} else {
|
||||
let name = self.parse_identifier();
|
||||
let name = self.parse_identifier().into_inner();
|
||||
|
||||
let bound = if self.eat(TokenKind::Colon) {
|
||||
if self.at_expr() {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
source: crates/ruff_python_parser/tests/fixtures.rs
|
||||
input_file: crates/ruff_python_parser/resources/inline/err/assert_invalid_test_expr.py
|
||||
snapshot_kind: text
|
||||
---
|
||||
## AST
|
||||
|
||||
@@ -36,7 +35,7 @@ Module(
|
||||
ExprName {
|
||||
range: 17..23,
|
||||
id: Name("assert"),
|
||||
ctx: Load,
|
||||
ctx: Invalid,
|
||||
},
|
||||
),
|
||||
msg: None,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
source: crates/ruff_python_parser/tests/fixtures.rs
|
||||
input_file: crates/ruff_python_parser/resources/inline/err/aug_assign_stmt_invalid_target.py
|
||||
snapshot_kind: text
|
||||
---
|
||||
## AST
|
||||
|
||||
@@ -134,7 +133,7 @@ Module(
|
||||
ExprName {
|
||||
range: 41..45,
|
||||
id: Name("pass"),
|
||||
ctx: Load,
|
||||
ctx: Invalid,
|
||||
},
|
||||
),
|
||||
},
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
source: crates/ruff_python_parser/tests/fixtures.rs
|
||||
input_file: crates/ruff_python_parser/resources/inline/err/comprehension_missing_for_after_async.py
|
||||
snapshot_kind: text
|
||||
---
|
||||
## AST
|
||||
|
||||
@@ -17,7 +16,7 @@ Module(
|
||||
ExprName {
|
||||
range: 1..6,
|
||||
id: Name("async"),
|
||||
ctx: Load,
|
||||
ctx: Invalid,
|
||||
},
|
||||
),
|
||||
},
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
source: crates/ruff_python_parser/tests/fixtures.rs
|
||||
input_file: crates/ruff_python_parser/resources/invalid/expressions/attribute/multiple_dots.py
|
||||
snapshot_kind: text
|
||||
---
|
||||
## AST
|
||||
|
||||
@@ -30,7 +29,7 @@ Module(
|
||||
id: Name(""),
|
||||
range: 6..6,
|
||||
},
|
||||
ctx: Load,
|
||||
ctx: Invalid,
|
||||
},
|
||||
),
|
||||
attr: Identifier {
|
||||
@@ -104,7 +103,7 @@ Module(
|
||||
id: Name(""),
|
||||
range: 40..40,
|
||||
},
|
||||
ctx: Load,
|
||||
ctx: Invalid,
|
||||
},
|
||||
),
|
||||
attr: Identifier {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
source: crates/ruff_python_parser/tests/fixtures.rs
|
||||
input_file: crates/ruff_python_parser/resources/invalid/expressions/attribute/no_member.py
|
||||
snapshot_kind: text
|
||||
---
|
||||
## AST
|
||||
|
||||
@@ -27,7 +26,7 @@ Module(
|
||||
id: Name(""),
|
||||
range: 93..93,
|
||||
},
|
||||
ctx: Load,
|
||||
ctx: Invalid,
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -61,7 +60,7 @@ Module(
|
||||
id: Name(""),
|
||||
range: 141..141,
|
||||
},
|
||||
ctx: Load,
|
||||
ctx: Invalid,
|
||||
},
|
||||
),
|
||||
},
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
source: crates/ruff_python_parser/tests/fixtures.rs
|
||||
input_file: crates/ruff_python_parser/resources/invalid/expressions/compare/invalid_order.py
|
||||
snapshot_kind: text
|
||||
---
|
||||
## AST
|
||||
|
||||
@@ -106,7 +105,7 @@ Module(
|
||||
ExprName {
|
||||
range: 126..128,
|
||||
id: Name("is"),
|
||||
ctx: Load,
|
||||
ctx: Invalid,
|
||||
},
|
||||
),
|
||||
},
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
source: crates/ruff_python_parser/tests/fixtures.rs
|
||||
input_file: crates/ruff_python_parser/resources/invalid/expressions/dict/double_star_comprehension.py
|
||||
snapshot_kind: text
|
||||
---
|
||||
## AST
|
||||
|
||||
@@ -41,7 +40,7 @@ Module(
|
||||
ExprName {
|
||||
range: 130..133,
|
||||
id: Name("for"),
|
||||
ctx: Load,
|
||||
ctx: Invalid,
|
||||
},
|
||||
),
|
||||
},
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
source: crates/ruff_python_parser/tests/fixtures.rs
|
||||
input_file: crates/ruff_python_parser/resources/invalid/expressions/dict/missing_closing_brace_0.py
|
||||
snapshot_kind: text
|
||||
---
|
||||
## AST
|
||||
|
||||
@@ -31,7 +30,7 @@ Module(
|
||||
ExprName {
|
||||
range: 5..8,
|
||||
id: Name("def"),
|
||||
ctx: Load,
|
||||
ctx: Invalid,
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -59,7 +58,7 @@ Module(
|
||||
ExprName {
|
||||
range: 20..24,
|
||||
id: Name("pass"),
|
||||
ctx: Load,
|
||||
ctx: Invalid,
|
||||
},
|
||||
),
|
||||
},
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
source: crates/ruff_python_parser/tests/fixtures.rs
|
||||
input_file: crates/ruff_python_parser/resources/invalid/expressions/named/missing_expression_2.py
|
||||
snapshot_kind: text
|
||||
---
|
||||
## AST
|
||||
|
||||
@@ -27,7 +26,7 @@ Module(
|
||||
ExprName {
|
||||
range: 68..71,
|
||||
id: Name("def"),
|
||||
ctx: Load,
|
||||
ctx: Invalid,
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -58,7 +57,7 @@ Module(
|
||||
ExprName {
|
||||
range: 83..87,
|
||||
id: Name("pass"),
|
||||
ctx: Load,
|
||||
ctx: Invalid,
|
||||
},
|
||||
),
|
||||
value: None,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
source: crates/ruff_python_parser/tests/fixtures.rs
|
||||
input_file: crates/ruff_python_parser/resources/invalid/expressions/subscript/unclosed_slice_1.py
|
||||
snapshot_kind: text
|
||||
---
|
||||
## AST
|
||||
|
||||
@@ -33,7 +32,7 @@ Module(
|
||||
ExprName {
|
||||
range: 6..9,
|
||||
id: Name("def"),
|
||||
ctx: Load,
|
||||
ctx: Invalid,
|
||||
},
|
||||
),
|
||||
),
|
||||
@@ -68,7 +67,7 @@ Module(
|
||||
ExprName {
|
||||
range: 21..25,
|
||||
id: Name("pass"),
|
||||
ctx: Load,
|
||||
ctx: Invalid,
|
||||
},
|
||||
),
|
||||
value: None,
|
||||
|
||||
Reference in New Issue
Block a user