Replace LALRPOP parser with hand-written parser (#10036)

(Supersedes #9152, authored by @LaBatata101)

## Summary

This PR replaces the current parser generated from LALRPOP to a
hand-written recursive descent parser.

It also updates the grammar for [PEP
646](https://peps.python.org/pep-0646/) so that the parser outputs the
correct AST. For example, in `data[*x]`, the index expression is now a
tuple with a single starred expression instead of just a starred
expression.

Beyond the performance improvements, the parser is also error resilient
and can provide better error messages. The behavior as seen by any
downstream tools isn't changed. That is, the linter and formatter can
still assume that the parser will _stop_ at the first syntax error. This
will be updated in the following months.

For more details about the change here, refer to the PR corresponding to
the individual commits and the release blog post.

## Test Plan

Write _lots_ and _lots_ of tests for both valid and invalid syntax and
verify the output.

## Acknowledgements

- @MichaReiser for reviewing 100+ parser PRs and continuously providing
guidance throughout the project
- @LaBatata101 for initiating the transition to a hand-written parser in
#9152
- @addisoncrump for implementing the fuzzer which helped
[catch](https://github.com/astral-sh/ruff/pull/10903)
[a](https://github.com/astral-sh/ruff/pull/10910)
[lot](https://github.com/astral-sh/ruff/pull/10966)
[of](https://github.com/astral-sh/ruff/pull/10896)
[bugs](https://github.com/astral-sh/ruff/pull/10877)

---------

Co-authored-by: Victor Hugo Gomes <labatata101@linuxmail.org>
Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
Dhruv Manilawala 2024-04-18 17:57:39 +05:30 committed by GitHub
parent e09180b1df
commit 13ffb5bc19
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
852 changed files with 112948 additions and 103620 deletions

View file

@ -1,185 +0,0 @@
use ruff_python_ast::{self as ast, Expr, ExprContext};
pub(crate) fn set_context(expr: Expr, ctx: ExprContext) -> Expr {
match expr {
Expr::Name(ast::ExprName { id, range, .. }) => ast::ExprName { range, id, ctx }.into(),
Expr::Tuple(ast::ExprTuple {
elts,
range,
parenthesized: is_parenthesized,
ctx: _,
}) => ast::ExprTuple {
elts: elts.into_iter().map(|elt| set_context(elt, ctx)).collect(),
range,
ctx,
parenthesized: is_parenthesized,
}
.into(),
Expr::List(ast::ExprList { elts, range, .. }) => ast::ExprList {
elts: elts.into_iter().map(|elt| set_context(elt, ctx)).collect(),
range,
ctx,
}
.into(),
Expr::Attribute(ast::ExprAttribute {
value, attr, range, ..
}) => ast::ExprAttribute {
range,
value,
attr,
ctx,
}
.into(),
Expr::Subscript(ast::ExprSubscript {
value,
slice,
range,
..
}) => ast::ExprSubscript {
range,
value,
slice,
ctx,
}
.into(),
Expr::Starred(ast::ExprStarred { value, range, .. }) => ast::ExprStarred {
value: Box::new(set_context(*value, ctx)),
range,
ctx,
}
.into(),
_ => expr,
}
}
#[cfg(test)]
mod tests {
use crate::parser::parse_suite;
#[test]
fn test_assign_name() {
let source = "x = (1, 2, 3)";
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_assign_tuple() {
let source = "(x, y) = (1, 2, 3)";
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_assign_list() {
let source = "[x, y] = (1, 2, 3)";
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_assign_attribute() {
let source = "x.y = (1, 2, 3)";
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_assign_subscript() {
let source = "x[y] = (1, 2, 3)";
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_assign_starred() {
let source = "(x, *y) = (1, 2, 3)";
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_assign_for() {
let source = "for x in (1, 2, 3): pass";
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_assign_list_comp() {
let source = "x = [y for y in (1, 2, 3)]";
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_assign_set_comp() {
let source = "x = {y for y in (1, 2, 3)}";
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_assign_with() {
let source = "with 1 as x: pass";
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_assign_named_expr() {
let source = "if x:= 1: pass";
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_ann_assign_name() {
let source = "x: int = 1";
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_aug_assign_name() {
let source = "x += 1";
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_aug_assign_attribute() {
let source = "x.y += (1, 2, 3)";
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_aug_assign_subscript() {
let source = "x[y] += (1, 2, 3)";
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_del_name() {
let source = "del x";
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_del_attribute() {
let source = "del x.y";
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_del_subscript() {
let source = "del x[y]";
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
}

View file

@ -0,0 +1,297 @@
use std::fmt;
use ruff_text_size::TextRange;
use crate::lexer::{LexicalError, LexicalErrorType};
use crate::TokenKind;
/// Represents represent errors that occur during parsing and are
/// returned by the `parse_*` functions.
#[derive(Debug, PartialEq)]
pub struct ParseError {
pub error: ParseErrorType,
pub location: TextRange,
}
impl std::ops::Deref for ParseError {
type Target = ParseErrorType;
fn deref(&self) -> &Self::Target {
&self.error
}
}
impl std::error::Error for ParseError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.error)
}
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{} at byte range {:?}", &self.error, self.location)
}
}
impl From<LexicalError> for ParseError {
fn from(error: LexicalError) -> Self {
ParseError {
location: error.location(),
error: ParseErrorType::Lexical(error.into_error()),
}
}
}
impl ParseError {
pub fn error(self) -> ParseErrorType {
self.error
}
}
/// Represents the different types of errors that can occur during parsing of an f-string.
#[derive(Debug, Clone, PartialEq)]
pub enum FStringErrorType {
/// Expected a right brace after an opened left brace.
UnclosedLbrace,
/// An invalid conversion flag was encountered.
InvalidConversionFlag,
/// A single right brace was encountered.
SingleRbrace,
/// Unterminated string.
UnterminatedString,
/// Unterminated triple-quoted string.
UnterminatedTripleQuotedString,
/// A lambda expression without parentheses was encountered.
LambdaWithoutParentheses,
}
impl std::fmt::Display for FStringErrorType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use FStringErrorType::{
InvalidConversionFlag, LambdaWithoutParentheses, SingleRbrace, UnclosedLbrace,
UnterminatedString, UnterminatedTripleQuotedString,
};
match self {
UnclosedLbrace => write!(f, "expecting '}}'"),
InvalidConversionFlag => write!(f, "invalid conversion character"),
SingleRbrace => write!(f, "single '}}' is not allowed"),
UnterminatedString => write!(f, "unterminated string"),
UnterminatedTripleQuotedString => write!(f, "unterminated triple-quoted string"),
LambdaWithoutParentheses => {
write!(f, "lambda expressions are not allowed without parentheses")
}
}
}
}
/// Represents the different types of errors that can occur during parsing.
#[derive(Debug, PartialEq)]
pub enum ParseErrorType {
/// An unexpected error occurred.
OtherError(String),
/// An empty slice was found during parsing, e.g `data[]`.
EmptySlice,
/// An empty global names list was found during parsing.
EmptyGlobalNames,
/// An empty nonlocal names list was found during parsing.
EmptyNonlocalNames,
/// An empty delete targets list was found during parsing.
EmptyDeleteTargets,
/// An empty import names list was found during parsing.
EmptyImportNames,
/// An unparenthesized named expression was found where it is not allowed.
UnparenthesizedNamedExpression,
/// An unparenthesized tuple expression was found where it is not allowed.
UnparenthesizedTupleExpression,
/// An invalid usage of a lambda expression was found.
InvalidLambdaExpressionUsage,
/// An invalid usage of a yield expression was found.
InvalidYieldExpressionUsage,
/// An invalid usage of a starred expression was found.
InvalidStarredExpressionUsage,
/// A star pattern was found outside a sequence pattern.
InvalidStarPatternUsage,
/// A parameter was found after a vararg.
ParamAfterVarKeywordParam,
/// A non-default parameter follows a default parameter.
NonDefaultParamAfterDefaultParam,
/// A default value was found for a `*` or `**` parameter.
VarParameterWithDefault,
/// A duplicate parameter was found in a function definition or lambda expression.
DuplicateParameter(String),
/// A keyword argument was repeated.
DuplicateKeywordArgumentError(String),
/// An invalid expression was found in the assignment target.
InvalidAssignmentTarget,
/// An invalid expression was found in the named assignment target.
InvalidNamedAssignmentTarget,
/// An invalid expression was found in the annotated assignment target.
InvalidAnnotatedAssignmentTarget,
/// An invalid expression was found in the augmented assignment target.
InvalidAugmentedAssignmentTarget,
/// An invalid expression was found in the delete target.
InvalidDeleteTarget,
/// A positional argument was found after a keyword argument.
PositionalAfterKeywordArgument,
/// A positional argument was found after a keyword argument unpacking.
PositionalAfterKeywordUnpacking,
/// An iterable argument unpacking was found after keyword argument unpacking.
InvalidArgumentUnpackingOrder,
/// An invalid usage of iterable unpacking in a comprehension was found.
IterableUnpackingInComprehension,
/// Multiple simple statements were found in the same line without a `;` separating them.
SimpleStatementsOnSameLine,
/// A simple statement and a compound statement was found in the same line.
SimpleAndCompoundStatementOnSameLine,
/// Expected one or more keyword parameter after `*` separator.
ExpectedKeywordParam,
/// Expected a real number for a complex literal pattern.
ExpectedRealNumber,
/// Expected an imaginary number for a complex literal pattern.
ExpectedImaginaryNumber,
/// Expected an expression at the current parser location.
ExpectedExpression,
/// The parser expected a specific token that was not found.
ExpectedToken {
expected: TokenKind,
found: TokenKind,
},
/// An unexpected indentation was found during parsing.
UnexpectedIndentation,
/// The statement being parsed cannot be `async`.
UnexpectedTokenAfterAsync(TokenKind),
/// Ipython escape command was found
UnexpectedIpythonEscapeCommand,
/// An unexpected token was found at the end of an expression parsing
UnexpectedExpressionToken,
/// An f-string error containing the [`FStringErrorType`].
FStringError(FStringErrorType),
/// Parser encountered an error during lexing.
Lexical(LexicalErrorType),
}
impl std::error::Error for ParseErrorType {}
impl std::fmt::Display for ParseErrorType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
ParseErrorType::OtherError(msg) => write!(f, "{msg}"),
ParseErrorType::ExpectedToken { found, expected } => {
write!(f, "Expected {expected}, found {found}",)
}
ParseErrorType::Lexical(ref lex_error) => write!(f, "{lex_error}"),
ParseErrorType::SimpleStatementsOnSameLine => {
f.write_str("Simple statements must be separated by newlines or semicolons")
}
ParseErrorType::SimpleAndCompoundStatementOnSameLine => f.write_str(
"Compound statements are not allowed on the same line as simple statements",
),
ParseErrorType::UnexpectedTokenAfterAsync(kind) => {
write!(
f,
"Expected 'def', 'with' or 'for' to follow 'async', found {kind}",
)
}
ParseErrorType::InvalidArgumentUnpackingOrder => {
f.write_str("Iterable argument unpacking cannot follow keyword argument unpacking")
}
ParseErrorType::IterableUnpackingInComprehension => {
f.write_str("Iterable unpacking cannot be used in a comprehension")
}
ParseErrorType::UnparenthesizedNamedExpression => {
f.write_str("Unparenthesized named expression cannot be used here")
}
ParseErrorType::UnparenthesizedTupleExpression => {
f.write_str("Unparenthesized tuple expression cannot be used here")
}
ParseErrorType::InvalidYieldExpressionUsage => {
f.write_str("Yield expression cannot be used here")
}
ParseErrorType::InvalidLambdaExpressionUsage => {
f.write_str("Lambda expression cannot be used here")
}
ParseErrorType::InvalidStarredExpressionUsage => {
f.write_str("Starred expression cannot be used here")
}
ParseErrorType::PositionalAfterKeywordArgument => {
f.write_str("Positional argument cannot follow keyword argument")
}
ParseErrorType::PositionalAfterKeywordUnpacking => {
f.write_str("Positional argument cannot follow keyword argument unpacking")
}
ParseErrorType::EmptySlice => f.write_str("Expected index or slice expression"),
ParseErrorType::EmptyGlobalNames => {
f.write_str("Global statement must have at least one name")
}
ParseErrorType::EmptyNonlocalNames => {
f.write_str("Nonlocal statement must have at least one name")
}
ParseErrorType::EmptyDeleteTargets => {
f.write_str("Delete statement must have at least one target")
}
ParseErrorType::EmptyImportNames => {
f.write_str("Expected one or more symbol names after import")
}
ParseErrorType::ParamAfterVarKeywordParam => {
f.write_str("Parameter cannot follow var-keyword parameter")
}
ParseErrorType::NonDefaultParamAfterDefaultParam => {
f.write_str("Parameter without a default cannot follow a parameter with a default")
}
ParseErrorType::ExpectedKeywordParam => {
f.write_str("Expected one or more keyword parameter after '*' separator")
}
ParseErrorType::VarParameterWithDefault => {
f.write_str("Parameter with '*' or '**' cannot have default value")
}
ParseErrorType::InvalidStarPatternUsage => {
f.write_str("Star pattern cannot be used here")
}
ParseErrorType::ExpectedRealNumber => {
f.write_str("Expected a real number in complex literal pattern")
}
ParseErrorType::ExpectedImaginaryNumber => {
f.write_str("Expected an imaginary number in complex literal pattern")
}
ParseErrorType::ExpectedExpression => f.write_str("Expected an expression"),
ParseErrorType::UnexpectedIndentation => f.write_str("Unexpected indentation"),
ParseErrorType::InvalidAssignmentTarget => f.write_str("Invalid assignment target"),
ParseErrorType::InvalidAnnotatedAssignmentTarget => {
f.write_str("Invalid annotated assignment target")
}
ParseErrorType::InvalidNamedAssignmentTarget => {
f.write_str("Assignment expression target must be an identifier")
}
ParseErrorType::InvalidAugmentedAssignmentTarget => {
f.write_str("Invalid augmented assignment target")
}
ParseErrorType::InvalidDeleteTarget => f.write_str("Invalid delete target"),
ParseErrorType::DuplicateParameter(arg_name) => {
write!(f, "Duplicate parameter {arg_name:?}")
}
ParseErrorType::DuplicateKeywordArgumentError(arg_name) => {
write!(f, "Duplicate keyword argument {arg_name:?}")
}
ParseErrorType::UnexpectedIpythonEscapeCommand => {
f.write_str("IPython escape commands are only allowed in `Mode::Ipython`")
}
ParseErrorType::FStringError(ref fstring_error) => {
write!(f, "f-string: {fstring_error}")
}
ParseErrorType::UnexpectedExpressionToken => {
write!(f, "Unexpected token at the end of an expression")
}
}
}
}

View file

@ -1,246 +0,0 @@
use std::hash::BuildHasherDefault;
// Contains functions that perform validation and parsing of arguments and parameters.
// Checks apply both to functions and to lambdas.
use crate::lexer::{LexicalError, LexicalErrorType};
use ruff_python_ast::{self as ast};
use ruff_text_size::{Ranged, TextRange, TextSize};
use rustc_hash::FxHashSet;
pub(crate) struct ArgumentList {
pub(crate) args: Vec<ast::Expr>,
pub(crate) keywords: Vec<ast::Keyword>,
}
// Perform validation of function/lambda arguments in a function definition.
pub(crate) fn validate_arguments(arguments: &ast::Parameters) -> Result<(), LexicalError> {
let mut all_arg_names = FxHashSet::with_capacity_and_hasher(
arguments.posonlyargs.len()
+ arguments.args.len()
+ usize::from(arguments.vararg.is_some())
+ arguments.kwonlyargs.len()
+ usize::from(arguments.kwarg.is_some()),
BuildHasherDefault::default(),
);
let posonlyargs = arguments.posonlyargs.iter();
let args = arguments.args.iter();
let kwonlyargs = arguments.kwonlyargs.iter();
let vararg: Option<&ast::Parameter> = arguments.vararg.as_deref();
let kwarg: Option<&ast::Parameter> = arguments.kwarg.as_deref();
for arg in posonlyargs
.chain(args)
.chain(kwonlyargs)
.map(|arg| &arg.parameter)
.chain(vararg)
.chain(kwarg)
{
let range = arg.range;
let arg_name = arg.name.as_str();
if !all_arg_names.insert(arg_name) {
return Err(LexicalError::new(
LexicalErrorType::DuplicateArgumentError(arg_name.to_string().into_boxed_str()),
range.start(),
));
}
}
Ok(())
}
pub(crate) fn validate_pos_params(
args: &(
Vec<ast::ParameterWithDefault>,
Vec<ast::ParameterWithDefault>,
),
) -> Result<(), LexicalError> {
let (posonlyargs, args) = args;
#[allow(clippy::skip_while_next)]
let first_invalid = posonlyargs
.iter()
.chain(args.iter()) // for all args
.skip_while(|arg| arg.default.is_none()) // starting with args without default
.skip_while(|arg| arg.default.is_some()) // and then args with default
.next(); // there must not be any more args without default
if let Some(invalid) = first_invalid {
return Err(LexicalError::new(
LexicalErrorType::DefaultArgumentError,
invalid.parameter.start(),
));
}
Ok(())
}
type FunctionArgument = (
Option<(TextSize, TextSize, Option<ast::Identifier>)>,
ast::Expr,
);
// Parse arguments as supplied during a function/lambda *call*.
pub(crate) fn parse_arguments(
function_arguments: Vec<FunctionArgument>,
) -> Result<ArgumentList, LexicalError> {
// First, run through the comments to determine the number of positional and keyword arguments.
let mut keyword_names = FxHashSet::with_capacity_and_hasher(
function_arguments.len(),
BuildHasherDefault::default(),
);
let mut double_starred = false;
let mut num_args = 0;
let mut num_keywords = 0;
for (name, value) in &function_arguments {
if let Some((start, _end, name)) = name {
// Check for duplicate keyword arguments in the call.
if let Some(keyword_name) = &name {
if !keyword_names.insert(keyword_name.to_string()) {
return Err(LexicalError::new(
LexicalErrorType::DuplicateKeywordArgumentError(
keyword_name.to_string().into_boxed_str(),
),
*start,
));
}
} else {
double_starred = true;
}
num_keywords += 1;
} else {
// Positional arguments mustn't follow keyword arguments.
if num_keywords > 0 && !is_starred(value) {
return Err(LexicalError::new(
LexicalErrorType::PositionalArgumentError,
value.start(),
));
// Allow starred arguments after keyword arguments but
// not after double-starred arguments.
} else if double_starred {
return Err(LexicalError::new(
LexicalErrorType::UnpackedArgumentError,
value.start(),
));
}
num_args += 1;
}
}
// Second, push the arguments into vectors of exact capacity. This avoids a vector resize later
// on when these vectors are boxed into slices.
let mut args = Vec::with_capacity(num_args);
let mut keywords = Vec::with_capacity(num_keywords);
for (name, value) in function_arguments {
if let Some((start, end, name)) = name {
keywords.push(ast::Keyword {
arg: name,
value,
range: TextRange::new(start, end),
});
} else {
args.push(value);
}
}
Ok(ArgumentList { args, keywords })
}
// Check if an expression is a starred expression.
const fn is_starred(exp: &ast::Expr) -> bool {
exp.is_starred_expr()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parser::parse_suite;
use crate::ParseErrorType;
macro_rules! function_and_lambda {
($($name:ident: $code:expr,)*) => {
$(
#[test]
fn $name() {
let parse_ast = crate::parser::parse_suite($code, );
insta::assert_debug_snapshot!(parse_ast);
}
)*
}
}
function_and_lambda! {
test_function_no_args_with_ranges: "def f(): pass",
test_function_pos_args_with_ranges: "def f(a, b, c): pass",
}
function_and_lambda! {
test_function_no_args: "def f(): pass",
test_function_pos_args: "def f(a, b, c): pass",
test_function_posonly_and_pos_args: "def f(a, /, b, c): pass",
test_function_pos_args_with_defaults: "def f(a, b=20, /, c=30): pass",
test_function_pos_args_with_defaults_and_varargs_and_kwargs: "def f(a, b=20, /, c=30, *args, **kwargs): pass",
test_function_kw_only_args: "def f(*, a, b, c): pass",
test_function_kw_only_args_with_defaults: "def f(*, a, b=20, c=30): pass",
test_function_kw_only_args_with_defaults_and_varargs: "def f(*args, a, b=20, c=30): pass",
test_function_kw_only_args_with_defaults_and_kwargs: "def f(*, a, b=20, c=30, **kwargs): pass",
test_function_kw_only_args_with_defaults_and_varargs_and_kwargs: "def f(*args, a, b=20, c=30, **kwargs): pass",
test_function_pos_and_kw_only_args: "def f(a, b, /, c, *, d, e, f): pass",
test_function_pos_and_kw_only_args_with_defaults: "def f(a, b, /, c, *, d, e=20, f=30): pass",
test_function_pos_and_kw_only_args_with_defaults_and_varargs: "def f(a, b, /, c, *args, d, e=20, f=30): pass",
test_function_pos_and_kw_only_args_with_defaults_and_kwargs: "def f(a, b, /, c, *, d, e=20, f=30, **kwargs): pass",
test_function_pos_and_kw_only_args_with_defaults_and_varargs_and_kwargs: "def f(a, b, /, c, *args, d, e=20, f=30, **kwargs): pass",
test_lambda_no_args: "lambda: 1",
test_lambda_pos_args: "lambda a, b, c: 1",
test_lambda_posonly_args: "lambda a, b, /, c: 1",
test_lambda_pos_args_with_defaults: "lambda a, b=20, /, c=30: 1",
test_lambda_kw_only_args: "lambda *, a, b, c: 1",
test_lambda_kw_only_args_with_defaults: "lambda *, a, b=20, c=30: 1",
test_lambda_pos_and_kw_only_args: "lambda a, b, /, c, *, d, e: 0",
test_lambda_pos_and_kw_only_args_and_vararg_and_kwarg: "lambda a, b, /, c, *d, e, **f: 0",
}
fn function_parse_error(src: &str) -> LexicalErrorType {
let parse_ast = parse_suite(src);
parse_ast
.map_err(|e| match e.error {
ParseErrorType::Lexical(e) => e,
_ => panic!("Expected LexicalError"),
})
.expect_err("Expected error")
}
macro_rules! function_and_lambda_error {
($($name:ident: $code:expr, $error:expr,)*) => {
$(
#[test]
fn $name() {
let error = function_parse_error($code);
assert_eq!(error, $error);
}
)*
}
}
function_and_lambda_error! {
// Check definitions
test_duplicates_f1: "def f(a, a): pass", LexicalErrorType::DuplicateArgumentError("a".to_string().into_boxed_str()),
test_duplicates_f2: "def f(a, *, a): pass", LexicalErrorType::DuplicateArgumentError("a".to_string().into_boxed_str()),
test_duplicates_f3: "def f(a, a=20): pass", LexicalErrorType::DuplicateArgumentError("a".to_string().into_boxed_str()),
test_duplicates_f4: "def f(a, *a): pass", LexicalErrorType::DuplicateArgumentError("a".to_string().into_boxed_str()),
test_duplicates_f5: "def f(a, *, b, **a): pass", LexicalErrorType::DuplicateArgumentError("a".to_string().into_boxed_str()),
test_duplicates_l1: "lambda a, a: 1", LexicalErrorType::DuplicateArgumentError("a".to_string().into_boxed_str()),
test_duplicates_l2: "lambda a, *, a: 1", LexicalErrorType::DuplicateArgumentError("a".to_string().into_boxed_str()),
test_duplicates_l3: "lambda a, a=20: 1", LexicalErrorType::DuplicateArgumentError("a".to_string().into_boxed_str()),
test_duplicates_l4: "lambda a, *a: 1", LexicalErrorType::DuplicateArgumentError("a".to_string().into_boxed_str()),
test_duplicates_l5: "lambda a, *, b, **a: 1", LexicalErrorType::DuplicateArgumentError("a".to_string().into_boxed_str()),
test_default_arg_error_f: "def f(a, b=20, c): pass", LexicalErrorType::DefaultArgumentError,
test_default_arg_error_l: "lambda a, b=20, c: 1", LexicalErrorType::DefaultArgumentError,
test_named_arguments_follow_bare_star_1: "def f(*): pass", LexicalErrorType::OtherError("named arguments must follow bare *".to_string().into_boxed_str()),
test_named_arguments_follow_bare_star_2: "def f(*, **kwargs): pass", LexicalErrorType::OtherError("named arguments must follow bare *".to_string().into_boxed_str()),
// Check some calls.
test_positional_arg_error_f: "f(b=20, c)", LexicalErrorType::PositionalArgumentError,
test_unpacked_arg_error_f: "f(**b, *c)", LexicalErrorType::UnpackedArgumentError,
test_duplicate_kw_f1: "f(a=20, a=30)", LexicalErrorType::DuplicateKeywordArgumentError("a".to_string().into_boxed_str()),
}
}

View file

@ -1,699 +0,0 @@
/*!
Defines some helper routines for rejecting invalid Python programs.
These routines are named in a way that supports qualified use. For example,
`invalid::assignment_targets`.
*/
use {ruff_python_ast::Expr, ruff_text_size::TextSize};
use crate::lexer::{LexicalError, LexicalErrorType};
/// Returns an error for invalid assignment targets.
///
/// # Errors
///
/// This returns an error when any of the given expressions are themselves
/// or contain an expression that is invalid on the left hand side of an
/// assignment. For example, all literal expressions are invalid assignment
/// targets.
pub(crate) fn assignment_targets(targets: &[Expr]) -> Result<(), LexicalError> {
for t in targets {
assignment_target(t)?;
}
Ok(())
}
/// Returns an error if the given target is invalid for the left hand side of
/// an assignment.
///
/// # Errors
///
/// This returns an error when the given expression is itself or contains an
/// expression that is invalid on the left hand side of an assignment. For
/// example, all literal expressions are invalid assignment targets.
pub(crate) fn assignment_target(target: &Expr) -> Result<(), LexicalError> {
// Allowing a glob import here because of its limited scope.
#[allow(clippy::enum_glob_use)]
use self::Expr::*;
let err = |location: TextSize| -> LexicalError {
let error = LexicalErrorType::AssignmentError;
LexicalError::new(error, location)
};
match *target {
BoolOp(ref e) => Err(err(e.range.start())),
Named(ref e) => Err(err(e.range.start())),
BinOp(ref e) => Err(err(e.range.start())),
UnaryOp(ref e) => Err(err(e.range.start())),
Lambda(ref e) => Err(err(e.range.start())),
If(ref e) => Err(err(e.range.start())),
Dict(ref e) => Err(err(e.range.start())),
Set(ref e) => Err(err(e.range.start())),
ListComp(ref e) => Err(err(e.range.start())),
SetComp(ref e) => Err(err(e.range.start())),
DictComp(ref e) => Err(err(e.range.start())),
Generator(ref e) => Err(err(e.range.start())),
Await(ref e) => Err(err(e.range.start())),
Yield(ref e) => Err(err(e.range.start())),
YieldFrom(ref e) => Err(err(e.range.start())),
Compare(ref e) => Err(err(e.range.start())),
Call(ref e) => Err(err(e.range.start())),
// FString is recursive, but all its forms are invalid as an
// assignment target, so we can reject it without exploring it.
FString(ref e) => Err(err(e.range.start())),
StringLiteral(ref e) => Err(err(e.range.start())),
BytesLiteral(ref e) => Err(err(e.range.start())),
NumberLiteral(ref e) => Err(err(e.range.start())),
BooleanLiteral(ref e) => Err(err(e.range.start())),
NoneLiteral(ref e) => Err(err(e.range.start())),
EllipsisLiteral(ref e) => Err(err(e.range.start())),
// This isn't in the Python grammar but is Jupyter notebook specific.
// It seems like this should be an error. It does also seem like the
// parser prevents this from ever appearing as an assignment target
// anyway. ---AG
IpyEscapeCommand(ref e) => Err(err(e.range.start())),
// The only nested expressions allowed as an assignment target
// are star exprs, lists and tuples.
Starred(ref e) => assignment_target(&e.value),
List(ref e) => assignment_targets(&e.elts),
Tuple(ref e) => assignment_targets(&e.elts),
// Subscript is recursive and can be invalid, but aren't syntax errors.
// For example, `5[1] = 42` is a type error.
Subscript(_) => Ok(()),
// Similar to Subscript, e.g., `5[1:2] = [42]` is a type error.
Slice(_) => Ok(()),
// Similar to Subscript, e.g., `"foo".y = 42` is an attribute error.
Attribute(_) => Ok(()),
// These are always valid as assignment targets.
Name(_) => Ok(()),
}
}
#[cfg(test)]
mod tests {
use crate::parse_suite;
// First we test, broadly, that various kinds of assignments are now
// rejected by the parser. e.g., `5 = 3`, `5 += 3`, `(5): int = 3`.
// Regression test: https://github.com/astral-sh/ruff/issues/6895
#[test]
fn err_literal_assignment() {
let ast = parse_suite(r"5 = 3");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
// This test previously passed before the assignment operator checking
// above, but we include it here for good measure.
#[test]
fn err_assignment_expr() {
let ast = parse_suite(r"(5 := 3)");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: UnrecognizedToken(
ColonEqual,
None,
),
offset: 3,
},
)
"###);
}
#[test]
fn err_literal_augment_assignment() {
let ast = parse_suite(r"5 += 3");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_literal_annotation_assignment() {
let ast = parse_suite(r"(5): int = 3");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 1,
},
)
"###);
}
// Now we exhaustively test all possible cases where assignment can fail.
#[test]
fn err_bool_op() {
let ast = parse_suite(r"x or y = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_named_expr() {
let ast = parse_suite(r"(x := 5) = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 1,
},
)
"###);
}
#[test]
fn err_bin_op() {
let ast = parse_suite(r"x + y = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_unary_op() {
let ast = parse_suite(r"-x = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_lambda() {
let ast = parse_suite(r"(lambda _: 1) = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 1,
},
)
"###);
}
#[test]
fn err_if_exp() {
let ast = parse_suite(r"a if b else c = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_dict() {
let ast = parse_suite(r"{'a':5} = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_set() {
let ast = parse_suite(r"{a} = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_list_comp() {
let ast = parse_suite(r"[x for x in xs] = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_set_comp() {
let ast = parse_suite(r"{x for x in xs} = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_dict_comp() {
let ast = parse_suite(r"{x: x*2 for x in xs} = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_generator_exp() {
let ast = parse_suite(r"(x for x in xs) = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_await() {
let ast = parse_suite(r"await x = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_yield() {
let ast = parse_suite(r"(yield x) = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 1,
},
)
"###);
}
#[test]
fn err_yield_from() {
let ast = parse_suite(r"(yield from xs) = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 1,
},
)
"###);
}
#[test]
fn err_compare() {
let ast = parse_suite(r"a < b < c = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_call() {
let ast = parse_suite(r"foo() = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_formatted_value() {
// N.B. It looks like the parser can't generate a top-level
// FormattedValue, where as the official Python AST permits
// representing a single f-string containing just a variable as a
// FormattedValue directly.
//
// Bottom line is that because of this, this test is (at present)
// duplicative with the `fstring` test. That is, in theory these tests
// could fail independently, but in practice their failure or success
// is coupled.
//
// See: https://docs.python.org/3/library/ast.html#ast.FormattedValue
let ast = parse_suite(r#"f"{quux}" = 42"#);
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_fstring() {
let ast = parse_suite(r#"f"{foo} and {bar}" = 42"#);
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_string_literal() {
let ast = parse_suite(r#""foo" = 42"#);
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_bytes_literal() {
let ast = parse_suite(r#"b"foo" = 42"#);
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_number_literal() {
let ast = parse_suite(r"123 = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_boolean_literal() {
let ast = parse_suite(r"True = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_none_literal() {
let ast = parse_suite(r"None = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_ellipsis_literal() {
let ast = parse_suite(r"... = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 0,
},
)
"###);
}
#[test]
fn err_starred() {
let ast = parse_suite(r"*foo() = 42");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 1,
},
)
"###);
}
#[test]
fn err_list() {
let ast = parse_suite(r"[x, foo(), y] = [42, 42, 42]");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 4,
},
)
"###);
}
#[test]
fn err_list_nested() {
let ast = parse_suite(r"[[a, b], [[42]], d] = [[1, 2], [[3]], 4]");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 11,
},
)
"###);
}
#[test]
fn err_tuple() {
let ast = parse_suite(r"(x, foo(), y) = (42, 42, 42)");
insta::assert_debug_snapshot!(ast, @r###"
Err(
ParseError {
error: Lexical(
AssignmentError,
),
offset: 4,
},
)
"###);
}
// This last group of tests checks that assignments we expect to be parsed
// (including some interesting ones) continue to be parsed successfully.
#[test]
fn ok_starred() {
let ast = parse_suite(r"*foo = 42");
insta::assert_debug_snapshot!(ast);
}
#[test]
fn ok_list() {
let ast = parse_suite(r"[x, y, z] = [1, 2, 3]");
insta::assert_debug_snapshot!(ast);
}
#[test]
fn ok_tuple() {
let ast = parse_suite(r"(x, y, z) = (1, 2, 3)");
insta::assert_debug_snapshot!(ast);
}
#[test]
fn ok_subscript_normal() {
let ast = parse_suite(r"x[0] = 42");
insta::assert_debug_snapshot!(ast);
}
// This is actually a type error, not a syntax error. So check that it
// doesn't fail parsing.
#[test]
fn ok_subscript_weird() {
let ast = parse_suite(r"5[0] = 42");
insta::assert_debug_snapshot!(ast);
}
#[test]
fn ok_slice_normal() {
let ast = parse_suite(r"x[1:2] = [42]");
insta::assert_debug_snapshot!(ast);
}
// This is actually a type error, not a syntax error. So check that it
// doesn't fail parsing.
#[test]
fn ok_slice_weird() {
let ast = parse_suite(r"5[1:2] = [42]");
insta::assert_debug_snapshot!(ast);
}
#[test]
fn ok_attribute_normal() {
let ast = parse_suite(r"foo.bar = 42");
insta::assert_debug_snapshot!(ast);
}
// This is actually an attribute error, not a syntax error. So check that
// it doesn't fail parsing.
#[test]
fn ok_attribute_weird() {
let ast = parse_suite(r#""foo".y = 42"#);
insta::assert_debug_snapshot!(ast);
}
#[test]
fn ok_name() {
let ast = parse_suite(r"foo = 42");
insta::assert_debug_snapshot!(ast);
}
// This is a sanity test for what looks like an ipython directive being
// assigned to. Although this doesn't actually parse as an assignment
// statement, but rather, a directive whose value is `foo = 42`.
#[test]
fn ok_ipy_escape_command() {
use crate::Mode;
let src = r"!foo = 42";
let tokens = crate::lexer::lex(src, Mode::Ipython);
let ast = crate::parse_tokens(tokens.collect(), src, Mode::Ipython);
insta::assert_debug_snapshot!(ast);
}
#[test]
fn ok_assignment_expr() {
let ast = parse_suite(r"(x := 5)");
insta::assert_debug_snapshot!(ast);
}
}

View file

@ -39,10 +39,13 @@ use ruff_python_ast::{
};
use ruff_text_size::{TextLen, TextRange, TextSize};
use crate::error::FStringErrorType;
use crate::lexer::cursor::{Cursor, EOF_CHAR};
use crate::lexer::fstring::{FStringContext, FStrings};
use crate::lexer::indentation::{Indentation, Indentations};
use crate::{soft_keywords::SoftKeywordTransformer, string::FStringErrorType, token::Tok, Mode};
use crate::soft_keywords::SoftKeywordTransformer;
use crate::token::Tok;
use crate::Mode;
mod cursor;
mod fstring;
@ -304,7 +307,7 @@ impl<'source> Lexer<'source> {
Err(err) => {
return Err(LexicalError::new(
LexicalErrorType::OtherError(format!("{err:?}").into_boxed_str()),
self.token_range().start(),
self.token_range(),
));
}
};
@ -329,7 +332,7 @@ impl<'source> Lexer<'source> {
if self.cursor.eat_char('_') {
return Err(LexicalError::new(
LexicalErrorType::OtherError("Invalid Syntax".to_string().into_boxed_str()),
self.offset() - TextSize::new(1),
TextRange::new(self.offset() - TextSize::new(1), self.offset()),
));
}
@ -363,7 +366,7 @@ impl<'source> Lexer<'source> {
LexicalErrorType::OtherError(
"Invalid decimal literal".to_string().into_boxed_str(),
),
self.token_start(),
self.token_range(),
)
})?;
@ -388,9 +391,11 @@ impl<'source> Lexer<'source> {
// Leading zeros in decimal integer literals are not permitted.
return Err(LexicalError::new(
LexicalErrorType::OtherError(
"Invalid Token".to_string().into_boxed_str(),
"Invalid decimal integer literal"
.to_string()
.into_boxed_str(),
),
self.token_range().start(),
self.token_range(),
));
}
value
@ -398,7 +403,7 @@ impl<'source> Lexer<'source> {
Err(err) => {
return Err(LexicalError::new(
LexicalErrorType::OtherError(format!("{err:?}").into_boxed_str()),
self.token_range().start(),
self.token_range(),
))
}
};
@ -614,7 +619,7 @@ impl<'source> Lexer<'source> {
};
return Err(LexicalError::new(
LexicalErrorType::FStringError(error),
self.offset(),
self.token_range(),
));
}
'\n' | '\r' if !fstring.is_triple_quoted() => {
@ -627,7 +632,7 @@ impl<'source> Lexer<'source> {
}
return Err(LexicalError::new(
LexicalErrorType::FStringError(FStringErrorType::UnterminatedString),
self.offset(),
self.token_range(),
));
}
'\\' => {
@ -735,22 +740,9 @@ impl<'source> Lexer<'source> {
let Some(index) = memchr::memchr(quote_byte, self.cursor.rest().as_bytes()) else {
self.cursor.skip_to_end();
if let Some(fstring) = self.fstrings.current() {
// When we are in an f-string, check whether the initial quote
// matches with f-strings quotes and if it is, then this must be a
// missing '}' token so raise the proper error.
if fstring.quote_char() == quote
&& fstring.is_triple_quoted() == kind.is_triple_quoted()
{
return Err(LexicalError::new(
LexicalErrorType::FStringError(FStringErrorType::UnclosedLbrace),
self.cursor.text_len(),
));
}
}
return Err(LexicalError::new(
LexicalErrorType::Eof,
self.cursor.text_len(),
LexicalErrorType::UnclosedStringError,
self.token_range(),
));
};
@ -784,22 +776,9 @@ impl<'source> Lexer<'source> {
else {
self.cursor.skip_to_end();
if let Some(fstring) = self.fstrings.current() {
// When we are in an f-string, check whether the initial quote
// matches with f-strings quotes and if it is, then this must be a
// missing '}' token so raise the proper error.
if fstring.quote_char() == quote
&& fstring.is_triple_quoted() == kind.is_triple_quoted()
{
return Err(LexicalError::new(
LexicalErrorType::FStringError(FStringErrorType::UnclosedLbrace),
self.offset(),
));
}
}
return Err(LexicalError::new(
LexicalErrorType::StringError,
self.offset(),
self.token_range(),
));
};
@ -825,26 +804,9 @@ impl<'source> Lexer<'source> {
match ch {
Some('\r' | '\n') => {
if let Some(fstring) = self.fstrings.current() {
// When we are in an f-string, check whether the initial quote
// matches with f-strings quotes and if it is, then this must be a
// missing '}' token so raise the proper error.
if fstring.quote_char() == quote && !fstring.is_triple_quoted() {
return Err(LexicalError::new(
LexicalErrorType::FStringError(
FStringErrorType::UnclosedLbrace,
),
self.offset() - TextSize::new(1),
));
}
}
return Err(LexicalError::new(
LexicalErrorType::OtherError(
"EOL while scanning string literal"
.to_string()
.into_boxed_str(),
),
self.offset() - TextSize::new(1),
LexicalErrorType::UnclosedStringError,
self.token_range(),
));
}
Some(ch) if ch == quote => {
@ -893,7 +855,7 @@ impl<'source> Lexer<'source> {
self.pending_indentation = Some(indentation);
let offset = self.offset();
self.indentations.dedent_one(indentation).map_err(|_| {
LexicalError::new(LexicalErrorType::IndentationError, offset)
LexicalError::new(LexicalErrorType::IndentationError, self.token_range())
})?;
return Ok((Tok::Dedent, TextRange::empty(offset)));
}
@ -901,7 +863,7 @@ impl<'source> Lexer<'source> {
Err(_) => {
return Err(LexicalError::new(
LexicalErrorType::IndentationError,
self.offset(),
self.token_range(),
));
}
}
@ -927,7 +889,7 @@ impl<'source> Lexer<'source> {
} else {
Err(LexicalError::new(
LexicalErrorType::UnrecognizedToken { tok: c },
self.token_start(),
self.token_range(),
))
}
} else {
@ -951,11 +913,11 @@ impl<'source> Lexer<'source> {
if self.cursor.eat_char('\r') {
self.cursor.eat_char('\n');
} else if self.cursor.is_eof() {
return Err(LexicalError::new(LexicalErrorType::Eof, self.token_start()));
return Err(LexicalError::new(LexicalErrorType::Eof, self.token_range()));
} else if !self.cursor.eat_char('\n') {
return Err(LexicalError::new(
LexicalErrorType::LineContinuationError,
self.token_start(),
self.token_range(),
));
}
}
@ -989,11 +951,11 @@ impl<'source> Lexer<'source> {
if self.cursor.eat_char('\r') {
self.cursor.eat_char('\n');
} else if self.cursor.is_eof() {
return Err(LexicalError::new(LexicalErrorType::Eof, self.token_start()));
return Err(LexicalError::new(LexicalErrorType::Eof, self.token_range()));
} else if !self.cursor.eat_char('\n') {
return Err(LexicalError::new(
LexicalErrorType::LineContinuationError,
self.token_start(),
self.token_range(),
));
}
indentation = Indentation::root();
@ -1031,7 +993,7 @@ impl<'source> Lexer<'source> {
self.pending_indentation = Some(indentation);
self.indentations.dedent_one(indentation).map_err(|_| {
LexicalError::new(LexicalErrorType::IndentationError, self.offset())
LexicalError::new(LexicalErrorType::IndentationError, self.token_range())
})?;
Some((Tok::Dedent, TextRange::empty(self.offset())))
@ -1047,7 +1009,7 @@ impl<'source> Lexer<'source> {
Err(_) => {
return Err(LexicalError::new(
LexicalErrorType::IndentationError,
self.offset(),
self.token_range(),
));
}
};
@ -1061,7 +1023,7 @@ impl<'source> Lexer<'source> {
if self.nesting > 0 {
// Reset the nesting to avoid going into infinite loop.
self.nesting = 0;
return Err(LexicalError::new(LexicalErrorType::Eof, self.offset()));
return Err(LexicalError::new(LexicalErrorType::Eof, self.token_range()));
}
// Next, insert a trailing newline, if required.
@ -1228,7 +1190,7 @@ impl<'source> Lexer<'source> {
if fstring.nesting() == self.nesting {
return Err(LexicalError::new(
LexicalErrorType::FStringError(FStringErrorType::SingleRbrace),
self.token_start(),
self.token_range(),
));
}
fstring.try_end_format_spec(self.nesting);
@ -1322,7 +1284,7 @@ impl<'source> Lexer<'source> {
return Err(LexicalError::new(
LexicalErrorType::UnrecognizedToken { tok: c },
self.token_start(),
self.token_range(),
));
}
};
@ -1386,12 +1348,12 @@ pub struct LexicalError {
/// The type of error that occurred.
error: LexicalErrorType,
/// The location of the error.
location: TextSize,
location: TextRange,
}
impl LexicalError {
/// Creates a new `LexicalError` with the given error type and location.
pub fn new(error: LexicalErrorType, location: TextSize) -> Self {
pub fn new(error: LexicalErrorType, location: TextRange) -> Self {
Self { error, location }
}
@ -1403,7 +1365,7 @@ impl LexicalError {
self.error
}
pub fn location(&self) -> TextSize {
pub fn location(&self) -> TextRange {
self.location
}
}
@ -1428,7 +1390,7 @@ impl std::fmt::Display for LexicalError {
f,
"{} at byte offset {}",
self.error(),
u32::from(self.location())
u32::from(self.location().start())
)
}
}
@ -1443,9 +1405,14 @@ pub enum LexicalErrorType {
// to use the `UnicodeError` variant instead.
#[doc(hidden)]
StringError,
// TODO: Should take a start/end position to report.
/// A string literal without the closing quote.
UnclosedStringError,
/// Decoding of a unicode escape sequence in a string literal failed.
UnicodeError,
/// Missing the `{` for unicode escape sequence.
MissingUnicodeLbrace,
/// Missing the `}` for unicode escape sequence.
MissingUnicodeRbrace,
/// The nesting of brackets/braces/parentheses is not balanced.
NestingError,
/// The indentation is not consistent.
@ -1467,6 +1434,8 @@ pub enum LexicalErrorType {
UnrecognizedToken { tok: char },
/// An f-string error containing the [`FStringErrorType`].
FStringError(FStringErrorType),
/// Invalid character encountered in a byte literal.
InvalidByteLiteral,
/// An unexpected character was encountered after a line continuation.
LineContinuationError,
/// An unexpected end of file was encountered.
@ -1484,6 +1453,9 @@ impl std::fmt::Display for LexicalErrorType {
match self {
LexicalErrorType::StringError => write!(f, "Got unexpected string"),
LexicalErrorType::FStringError(error) => write!(f, "f-string: {error}"),
LexicalErrorType::InvalidByteLiteral => {
write!(f, "bytes can only contain ASCII literal characters")
}
LexicalErrorType::UnicodeError => write!(f, "Got unexpected unicode"),
LexicalErrorType::NestingError => write!(f, "Got unexpected nesting"),
LexicalErrorType::IndentationError => {
@ -1522,6 +1494,15 @@ impl std::fmt::Display for LexicalErrorType {
LexicalErrorType::Eof => write!(f, "unexpected EOF while parsing"),
LexicalErrorType::AssignmentError => write!(f, "invalid assignment target"),
LexicalErrorType::OtherError(msg) => write!(f, "{msg}"),
LexicalErrorType::UnclosedStringError => {
write!(f, "missing closing quote in string literal")
}
LexicalErrorType::MissingUnicodeLbrace => {
write!(f, "Missing `{{` in Unicode escape sequence")
}
LexicalErrorType::MissingUnicodeRbrace => {
write!(f, "Missing `}}` in Unicode escape sequence")
}
}
}
}
@ -2332,9 +2313,7 @@ f"{(lambda x:{x})}"
#[test]
fn test_fstring_error() {
use FStringErrorType::{
SingleRbrace, UnclosedLbrace, UnterminatedString, UnterminatedTripleQuotedString,
};
use FStringErrorType::{SingleRbrace, UnterminatedString, UnterminatedTripleQuotedString};
assert_eq!(lex_fstring_error("f'}'"), SingleRbrace);
assert_eq!(lex_fstring_error("f'{{}'"), SingleRbrace);
@ -2345,18 +2324,6 @@ f"{(lambda x:{x})}"
assert_eq!(lex_fstring_error("f'{3:}}>10}'"), SingleRbrace);
assert_eq!(lex_fstring_error(r"f'\{foo}\}'"), SingleRbrace);
assert_eq!(lex_fstring_error("f'{'"), UnclosedLbrace);
assert_eq!(lex_fstring_error("f'{foo!r'"), UnclosedLbrace);
assert_eq!(lex_fstring_error("f'{foo='"), UnclosedLbrace);
assert_eq!(
lex_fstring_error(
r#"f"{"
"#
),
UnclosedLbrace
);
assert_eq!(lex_fstring_error(r#"f"""{""""#), UnclosedLbrace);
assert_eq!(lex_fstring_error(r#"f""#), UnterminatedString);
assert_eq!(lex_fstring_error(r"f'"), UnterminatedString);
@ -2371,25 +2338,4 @@ f"{(lambda x:{x})}"
UnterminatedTripleQuotedString
);
}
#[test]
fn test_fstring_error_location() {
assert_debug_snapshot!(lex_error("f'{'"), @r###"
LexicalError {
error: FStringError(
UnclosedLbrace,
),
location: 4,
}
"###);
assert_debug_snapshot!(lex_error("f'{'α"), @r###"
LexicalError {
error: FStringError(
UnclosedLbrace,
),
location: 6,
}
"###);
}
}

View file

@ -109,28 +109,210 @@
//! [parsing]: https://en.wikipedia.org/wiki/Parsing
//! [lexer]: crate::lexer
pub use parser::{
parse, parse_expression, parse_expression_starts_at, parse_program, parse_starts_at,
parse_suite, parse_tokens, ParseError, ParseErrorType,
};
use ruff_python_ast::{Mod, PySourceType, Suite};
pub use string::FStringErrorType;
pub use token::{Tok, TokenKind};
use crate::lexer::{lex, lex_starts_at, LexResult};
use crate::lexer::LexResult;
pub use crate::error::{FStringErrorType, ParseError, ParseErrorType};
pub use crate::parser::Program;
pub use crate::token::{Tok, TokenKind};
mod context;
mod function;
mod invalid;
// Skip flattening lexer to distinguish from full ruff_python_parser
use ruff_python_ast::{Expr, Mod, ModModule, PySourceType, Suite};
use ruff_text_size::TextSize;
mod error;
pub mod lexer;
mod parser;
mod soft_keywords;
mod string;
mod token;
mod token_set;
mod token_source;
pub mod typing;
/// Parse a full Python program usually consisting of multiple lines.
///
/// This is a convenience function that can be used to parse a full Python program without having to
/// specify the [`Mode`] or the location. It is probably what you want to use most of the time.
///
/// # Example
///
/// For example, parsing a simple function definition and a call to that function:
///
/// ```
/// use ruff_python_parser as parser;
/// let source = r#"
/// def foo():
/// return 42
///
/// print(foo())
/// "#;
/// let program = parser::parse_program(source);
/// assert!(program.is_ok());
/// ```
pub fn parse_program(source: &str) -> Result<ModModule, ParseError> {
let lexer = lex(source, Mode::Module);
match parse_tokens(lexer.collect(), source, Mode::Module)? {
Mod::Module(m) => Ok(m),
Mod::Expression(_) => unreachable!("Mode::Module doesn't return other variant"),
}
}
pub fn parse_suite(source: &str) -> Result<Suite, ParseError> {
parse_program(source).map(|m| m.body)
}
/// Parses a single Python expression.
///
/// This convenience function can be used to parse a single expression without having to
/// specify the Mode or the location.
///
/// # Example
///
/// For example, parsing a single expression denoting the addition of two numbers:
///
/// ```
/// use ruff_python_parser as parser;
/// let expr = parser::parse_expression("1 + 2");
///
/// assert!(expr.is_ok());
///
/// ```
pub fn parse_expression(source: &str) -> Result<Expr, ParseError> {
let lexer = lex(source, Mode::Expression).collect();
match parse_tokens(lexer, source, Mode::Expression)? {
Mod::Expression(expression) => Ok(*expression.body),
Mod::Module(_m) => unreachable!("Mode::Expression doesn't return other variant"),
}
}
/// Parses a Python expression from a given location.
///
/// This function allows to specify the location of the expression in the source code, other than
/// that, it behaves exactly like [`parse_expression`].
///
/// # Example
///
/// Parsing a single expression denoting the addition of two numbers, but this time specifying a different,
/// somewhat silly, location:
///
/// ```
/// use ruff_python_parser::{parse_expression_starts_at};
/// # use ruff_text_size::TextSize;
///
/// let expr = parse_expression_starts_at("1 + 2", TextSize::from(400));
/// assert!(expr.is_ok());
/// ```
pub fn parse_expression_starts_at(source: &str, offset: TextSize) -> Result<Expr, ParseError> {
let lexer = lex_starts_at(source, Mode::Module, offset).collect();
match parse_tokens(lexer, source, Mode::Expression)? {
Mod::Expression(expression) => Ok(*expression.body),
Mod::Module(_m) => unreachable!("Mode::Expression doesn't return other variant"),
}
}
/// Parse the given Python source code using the specified [`Mode`].
///
/// This function is the most general function to parse Python code. Based on the [`Mode`] supplied,
/// it can be used to parse a single expression, a full Python program, an interactive expression
/// or a Python program containing IPython escape commands.
///
/// # Example
///
/// If we want to parse a simple expression, we can use the [`Mode::Expression`] mode during
/// parsing:
///
/// ```
/// use ruff_python_parser::{Mode, parse};
///
/// let expr = parse("1 + 2", Mode::Expression);
/// assert!(expr.is_ok());
/// ```
///
/// Alternatively, we can parse a full Python program consisting of multiple lines:
///
/// ```
/// use ruff_python_parser::{Mode, parse};
///
/// let source = r#"
/// class Greeter:
///
/// def greet(self):
/// print("Hello, world!")
/// "#;
/// let program = parse(source, Mode::Module);
/// assert!(program.is_ok());
/// ```
///
/// Additionally, we can parse a Python program containing IPython escapes:
///
/// ```
/// use ruff_python_parser::{Mode, parse};
///
/// let source = r#"
/// %timeit 1 + 2
/// ?str.replace
/// !ls
/// "#;
/// let program = parse(source, Mode::Ipython);
/// assert!(program.is_ok());
/// ```
pub fn parse(source: &str, mode: Mode) -> Result<Mod, ParseError> {
let lxr = lexer::lex(source, mode);
parse_tokens(lxr.collect(), source, mode)
}
/// Parse the given Python source code using the specified [`Mode`] and [`TextSize`].
///
/// This function allows to specify the location of the the source code, other than
/// that, it behaves exactly like [`parse`].
///
/// # Example
///
/// ```
/// # use ruff_text_size::TextSize;
/// use ruff_python_parser::{Mode, parse_starts_at};
///
/// let source = r#"
/// def fib(i):
/// a, b = 0, 1
/// for _ in range(i):
/// a, b = b, a + b
/// return a
///
/// print(fib(42))
/// "#;
/// let program = parse_starts_at(source, Mode::Module, TextSize::from(0));
/// assert!(program.is_ok());
/// ```
pub fn parse_starts_at(source: &str, mode: Mode, offset: TextSize) -> Result<Mod, ParseError> {
let lxr = lexer::lex_starts_at(source, mode, offset);
parse_tokens(lxr.collect(), source, mode)
}
/// Parse an iterator of [`LexResult`]s using the specified [`Mode`].
///
/// This could allow you to perform some preprocessing on the tokens before parsing them.
///
/// # Example
///
/// As an example, instead of parsing a string, we can parse a list of tokens after we generate
/// them using the [`lexer::lex`] function:
///
/// ```
/// use ruff_python_parser::{lexer::lex, Mode, parse_tokens};
///
/// let source = "1 + 2";
/// let expr = parse_tokens(lex(source, Mode::Expression).collect(), source, Mode::Expression);
/// assert!(expr.is_ok());
/// ```
pub fn parse_tokens(tokens: Vec<LexResult>, source: &str, mode: Mode) -> Result<Mod, ParseError> {
let program = Program::parse_tokens(source, tokens, mode);
if program.is_valid() {
Ok(program.into_ast())
} else {
Err(program.into_errors().into_iter().next().unwrap())
}
}
/// Collect tokens up to and including the first error.
pub fn tokenize(contents: &str, mode: Mode) -> Vec<LexResult> {
let mut tokens: Vec<LexResult> = allocate_tokens_vec(contents);
@ -248,28 +430,3 @@ impl std::fmt::Display for ModeParseError {
write!(f, r#"mode must be "exec", "eval", "ipython", or "single""#)
}
}
#[rustfmt::skip]
#[allow(unreachable_pub)]
#[allow(clippy::type_complexity)]
#[allow(clippy::extra_unused_lifetimes)]
#[allow(clippy::needless_lifetimes)]
#[allow(clippy::unused_self)]
#[allow(clippy::cast_sign_loss)]
#[allow(clippy::default_trait_access)]
#[allow(clippy::let_unit_value)]
#[allow(clippy::just_underscores_and_digits)]
#[allow(clippy::no_effect_underscore_binding)]
#[allow(clippy::trivially_copy_pass_by_ref)]
#[allow(clippy::option_option)]
#[allow(clippy::unnecessary_wraps)]
#[allow(clippy::uninlined_format_args)]
#[allow(clippy::cloned_instead_of_copied)]
mod python {
#[cfg(feature = "lalrpop")]
include!(concat!(env!("OUT_DIR"), "/src/python.rs"));
#[cfg(not(feature = "lalrpop"))]
include!("python.rs");
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,45 @@
use ruff_python_ast::{self as ast, CmpOp, Expr, ExprContext};
use crate::TokenKind;
/// Set the `ctx` for `Expr::Id`, `Expr::Attribute`, `Expr::Subscript`, `Expr::Starred`,
/// `Expr::Tuple` and `Expr::List`. If `expr` is either `Expr::Tuple` or `Expr::List`,
/// recursively sets the `ctx` for their elements.
pub(super) fn set_expr_ctx(expr: &mut Expr, new_ctx: ExprContext) {
match expr {
Expr::Name(ast::ExprName { ctx, .. })
| Expr::Attribute(ast::ExprAttribute { ctx, .. })
| Expr::Subscript(ast::ExprSubscript { ctx, .. }) => *ctx = new_ctx,
Expr::Starred(ast::ExprStarred { value, ctx, .. }) => {
*ctx = new_ctx;
set_expr_ctx(value, new_ctx);
}
Expr::UnaryOp(ast::ExprUnaryOp { operand, .. }) => {
set_expr_ctx(operand, new_ctx);
}
Expr::List(ast::ExprList { elts, ctx, .. })
| Expr::Tuple(ast::ExprTuple { elts, ctx, .. }) => {
*ctx = new_ctx;
elts.iter_mut()
.for_each(|element| set_expr_ctx(element, new_ctx));
}
_ => {}
}
}
/// Converts a [`TokenKind`] array of size 2 to its correspondent [`CmpOp`].
pub(super) fn token_kind_to_cmp_op(kind: [TokenKind; 2]) -> Result<CmpOp, ()> {
Ok(match kind {
[TokenKind::Is, TokenKind::Not] => CmpOp::IsNot,
[TokenKind::Is, _] => CmpOp::Is,
[TokenKind::Not, TokenKind::In] => CmpOp::NotIn,
[TokenKind::In, _] => CmpOp::In,
[TokenKind::EqEqual, _] => CmpOp::Eq,
[TokenKind::NotEqual, _] => CmpOp::NotEq,
[TokenKind::Less, _] => CmpOp::Lt,
[TokenKind::LessEqual, _] => CmpOp::LtE,
[TokenKind::Greater, _] => CmpOp::Gt,
[TokenKind::GreaterEqual, _] => CmpOp::GtE,
_ => return Err(()),
})
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,752 @@
use ruff_python_ast::{self as ast, Expr, ExprContext, Number, Operator, Pattern, Singleton};
use ruff_text_size::{Ranged, TextSize};
use crate::parser::progress::ParserProgress;
use crate::parser::{recovery, Parser, RecoveryContextKind, SequenceMatchPatternParentheses};
use crate::token_set::TokenSet;
use crate::{ParseErrorType, Tok, TokenKind};
/// The set of tokens that can start a literal pattern.
const LITERAL_PATTERN_START_SET: TokenSet = TokenSet::new([
TokenKind::None,
TokenKind::True,
TokenKind::False,
TokenKind::String,
TokenKind::Int,
TokenKind::Float,
TokenKind::Complex,
TokenKind::Minus, // Unary minus
]);
/// The set of tokens that can start a pattern.
const PATTERN_START_SET: TokenSet = TokenSet::new([
// Star pattern
TokenKind::Star,
// Capture pattern
// Wildcard pattern ('_' is a name token)
// Value pattern (name or attribute)
// Class pattern
TokenKind::Name,
// Group pattern
TokenKind::Lpar,
// Sequence pattern
TokenKind::Lsqb,
// Mapping pattern
TokenKind::Lbrace,
])
.union(LITERAL_PATTERN_START_SET);
/// The set of tokens that can start a mapping pattern.
const MAPPING_PATTERN_START_SET: TokenSet = TokenSet::new([
// Double star pattern
TokenKind::DoubleStar,
// Value pattern
TokenKind::Name,
])
.union(LITERAL_PATTERN_START_SET);
impl<'src> Parser<'src> {
/// Returns `true` if the current token is a valid start of a pattern.
pub(super) fn at_pattern_start(&self) -> bool {
self.at_ts(PATTERN_START_SET)
}
/// Returns `true` if the current token is a valid start of a mapping pattern.
pub(super) fn at_mapping_pattern_start(&self) -> bool {
self.at_ts(MAPPING_PATTERN_START_SET)
}
/// Entry point to start parsing a pattern.
///
/// See: <https://docs.python.org/3/reference/compound_stmts.html#grammar-token-python-grammar-patterns>
pub(super) fn parse_match_patterns(&mut self) -> Pattern {
let start = self.node_start();
// We don't yet know if it's a sequence pattern or a single pattern, so
// we need to allow star pattern here.
let pattern = self.parse_match_pattern(AllowStarPattern::Yes);
if self.at(TokenKind::Comma) {
Pattern::MatchSequence(self.parse_sequence_match_pattern(pattern, start, None))
} else {
// We know it's not a sequence pattern now, so check for star pattern usage.
if pattern.is_match_star() {
self.add_error(ParseErrorType::InvalidStarPatternUsage, &pattern);
}
pattern
}
}
/// Parses an `or_pattern` or an `as_pattern`.
///
/// See: <https://docs.python.org/3/reference/compound_stmts.html#grammar-token-python-grammar-pattern>
fn parse_match_pattern(&mut self, allow_star_pattern: AllowStarPattern) -> Pattern {
let start = self.node_start();
// We don't yet know if it's an or pattern or an as pattern, so use whatever
// was passed in.
let mut lhs = self.parse_match_pattern_lhs(allow_star_pattern);
// Or pattern
if self.at(TokenKind::Vbar) {
// We know it's an `or` pattern now, so check for star pattern usage.
if lhs.is_match_star() {
self.add_error(ParseErrorType::InvalidStarPatternUsage, &lhs);
}
let mut patterns = vec![lhs];
let mut progress = ParserProgress::default();
while self.eat(TokenKind::Vbar) {
progress.assert_progressing(self);
let pattern = self.parse_match_pattern_lhs(AllowStarPattern::No);
patterns.push(pattern);
}
lhs = Pattern::MatchOr(ast::PatternMatchOr {
range: self.node_range(start),
patterns,
});
}
// As pattern
if self.eat(TokenKind::As) {
// We know it's an `as` pattern now, so check for star pattern usage.
if lhs.is_match_star() {
self.add_error(ParseErrorType::InvalidStarPatternUsage, &lhs);
}
let ident = self.parse_identifier();
lhs = Pattern::MatchAs(ast::PatternMatchAs {
range: self.node_range(start),
name: Some(ident),
pattern: Some(Box::new(lhs)),
});
}
lhs
}
/// Parses a pattern.
///
/// See: <https://docs.python.org/3/reference/compound_stmts.html#grammar-token-python-grammar-closed_pattern>
fn parse_match_pattern_lhs(&mut self, allow_star_pattern: AllowStarPattern) -> Pattern {
let start = self.node_start();
let mut lhs = match self.current_token_kind() {
TokenKind::Lbrace => Pattern::MatchMapping(self.parse_match_pattern_mapping()),
TokenKind::Star => {
let star_pattern = self.parse_match_pattern_star();
if allow_star_pattern.is_no() {
self.add_error(ParseErrorType::InvalidStarPatternUsage, &star_pattern);
}
Pattern::MatchStar(star_pattern)
}
TokenKind::Lpar | TokenKind::Lsqb => self.parse_parenthesized_or_sequence_pattern(),
_ => self.parse_match_pattern_literal(),
};
if self.at(TokenKind::Lpar) {
lhs = Pattern::MatchClass(self.parse_match_pattern_class(lhs, start));
}
if matches!(
self.current_token_kind(),
TokenKind::Plus | TokenKind::Minus
) {
lhs = Pattern::MatchValue(self.parse_complex_literal_pattern(lhs, start));
}
lhs
}
/// Parses a mapping pattern.
///
/// # Panics
///
/// If the parser isn't positioned at a `{` token.
///
/// See: <https://docs.python.org/3/reference/compound_stmts.html#mapping-patterns>
fn parse_match_pattern_mapping(&mut self) -> ast::PatternMatchMapping {
let start = self.node_start();
self.bump(TokenKind::Lbrace);
let mut keys = vec![];
let mut patterns = vec![];
let mut rest = None;
self.parse_comma_separated_list(RecoveryContextKind::MatchPatternMapping, |parser| {
let mapping_item_start = parser.node_start();
if parser.eat(TokenKind::DoubleStar) {
let identifier = parser.parse_identifier();
if rest.is_some() {
parser.add_error(
ParseErrorType::OtherError(
"Only one double star pattern is allowed".to_string(),
),
parser.node_range(mapping_item_start),
);
}
// TODO(dhruvmanila): It's not possible to retain multiple double starred
// patterns because of the way the mapping node is represented in the grammar.
// The last value will always win. Update the AST representation.
// See: https://github.com/astral-sh/ruff/pull/10477#discussion_r1535143536
rest = Some(identifier);
} else {
let key = match parser.parse_match_pattern_lhs(AllowStarPattern::No) {
Pattern::MatchValue(ast::PatternMatchValue { value, .. }) => *value,
Pattern::MatchSingleton(ast::PatternMatchSingleton { value, range }) => {
match value {
Singleton::None => Expr::NoneLiteral(ast::ExprNoneLiteral { range }),
Singleton::True => {
Expr::BooleanLiteral(ast::ExprBooleanLiteral { value: true, range })
}
Singleton::False => Expr::BooleanLiteral(ast::ExprBooleanLiteral {
value: false,
range,
}),
}
}
pattern => {
parser.add_error(
ParseErrorType::OtherError("Invalid mapping pattern key".to_string()),
&pattern,
);
recovery::pattern_to_expr(pattern)
}
};
keys.push(key);
parser.expect(TokenKind::Colon);
patterns.push(parser.parse_match_pattern(AllowStarPattern::No));
if rest.is_some() {
parser.add_error(
ParseErrorType::OtherError(
"Pattern cannot follow a double star pattern".to_string(),
),
parser.node_range(mapping_item_start),
);
}
}
});
self.expect(TokenKind::Rbrace);
ast::PatternMatchMapping {
range: self.node_range(start),
keys,
patterns,
rest,
}
}
/// Parses a star pattern.
///
/// # Panics
///
/// If the parser isn't positioned at a `*` token.
///
/// See: <https://docs.python.org/3/reference/compound_stmts.html#grammar-token-python-grammar-star_pattern>
fn parse_match_pattern_star(&mut self) -> ast::PatternMatchStar {
let start = self.node_start();
self.bump(TokenKind::Star);
let ident = self.parse_identifier();
ast::PatternMatchStar {
range: self.node_range(start),
name: if ident.is_valid() && ident.id == "_" {
None
} else {
Some(ident)
},
}
}
/// Parses a parenthesized pattern or a sequence pattern.
///
/// # Panics
///
/// If the parser isn't positioned at a `(` or `[` token.
///
/// See: <https://docs.python.org/3/reference/compound_stmts.html#sequence-patterns>
fn parse_parenthesized_or_sequence_pattern(&mut self) -> Pattern {
let start = self.node_start();
let parentheses = if self.eat(TokenKind::Lpar) {
SequenceMatchPatternParentheses::Tuple
} else {
self.bump(TokenKind::Lsqb);
SequenceMatchPatternParentheses::List
};
if matches!(
self.current_token_kind(),
TokenKind::Newline | TokenKind::Colon
) {
// TODO(dhruvmanila): This recovery isn't possible currently because
// of the soft keyword transformer. If there's a missing closing
// parenthesis, it'll consider `case` a name token instead.
self.add_error(
ParseErrorType::OtherError(format!(
"Missing '{closing}'",
closing = if parentheses.is_list() { "]" } else { ")" }
)),
self.current_token_range(),
);
}
if self.eat(parentheses.closing_kind()) {
return Pattern::MatchSequence(ast::PatternMatchSequence {
patterns: vec![],
range: self.node_range(start),
});
}
let mut pattern = self.parse_match_pattern(AllowStarPattern::Yes);
if parentheses.is_list() || self.at(TokenKind::Comma) {
pattern = Pattern::MatchSequence(self.parse_sequence_match_pattern(
pattern,
start,
Some(parentheses),
));
} else {
self.expect(parentheses.closing_kind());
}
pattern
}
/// Parses the rest of a sequence pattern, given the first element.
///
/// If the `parentheses` is `None`, it is an [open sequence pattern].
///
/// See: <https://docs.python.org/3/reference/compound_stmts.html#sequence-patterns>
///
/// [open sequence pattern]: https://docs.python.org/3/reference/compound_stmts.html#grammar-token-python-grammar-open_sequence_pattern
fn parse_sequence_match_pattern(
&mut self,
first_element: Pattern,
start: TextSize,
parentheses: Option<SequenceMatchPatternParentheses>,
) -> ast::PatternMatchSequence {
if parentheses.is_some_and(|parentheses| {
self.at(parentheses.closing_kind()) || self.peek() == parentheses.closing_kind()
}) {
// The comma is optional if it is a single-element sequence
self.eat(TokenKind::Comma);
} else {
self.expect(TokenKind::Comma);
}
let mut patterns = vec![first_element];
self.parse_comma_separated_list(
RecoveryContextKind::SequenceMatchPattern(parentheses),
|parser| patterns.push(parser.parse_match_pattern(AllowStarPattern::Yes)),
);
if let Some(parentheses) = parentheses {
self.expect(parentheses.closing_kind());
}
ast::PatternMatchSequence {
range: self.node_range(start),
patterns,
}
}
/// Parses a literal pattern.
///
/// See: <https://docs.python.org/3/reference/compound_stmts.html#grammar-token-python-grammar-literal_pattern>
fn parse_match_pattern_literal(&mut self) -> Pattern {
let start = self.node_start();
match self.current_token_kind() {
TokenKind::None => {
self.bump(TokenKind::None);
Pattern::MatchSingleton(ast::PatternMatchSingleton {
value: Singleton::None,
range: self.node_range(start),
})
}
TokenKind::True => {
self.bump(TokenKind::True);
Pattern::MatchSingleton(ast::PatternMatchSingleton {
value: Singleton::True,
range: self.node_range(start),
})
}
TokenKind::False => {
self.bump(TokenKind::False);
Pattern::MatchSingleton(ast::PatternMatchSingleton {
value: Singleton::False,
range: self.node_range(start),
})
}
TokenKind::String | TokenKind::FStringStart => {
let str = self.parse_strings();
Pattern::MatchValue(ast::PatternMatchValue {
value: Box::new(str),
range: self.node_range(start),
})
}
TokenKind::Complex => {
let (Tok::Complex { real, imag }, _) = self.bump(TokenKind::Complex) else {
unreachable!()
};
let range = self.node_range(start);
Pattern::MatchValue(ast::PatternMatchValue {
value: Box::new(Expr::NumberLiteral(ast::ExprNumberLiteral {
value: Number::Complex { real, imag },
range,
})),
range,
})
}
TokenKind::Int => {
let (Tok::Int { value }, _) = self.bump(TokenKind::Int) else {
unreachable!()
};
let range = self.node_range(start);
Pattern::MatchValue(ast::PatternMatchValue {
value: Box::new(Expr::NumberLiteral(ast::ExprNumberLiteral {
value: Number::Int(value),
range,
})),
range,
})
}
TokenKind::Float => {
let (Tok::Float { value }, _) = self.bump(TokenKind::Float) else {
unreachable!()
};
let range = self.node_range(start);
Pattern::MatchValue(ast::PatternMatchValue {
value: Box::new(Expr::NumberLiteral(ast::ExprNumberLiteral {
value: Number::Float(value),
range,
})),
range,
})
}
TokenKind::Name if self.peek() == TokenKind::Dot => {
let (Tok::Name { name }, _) = self.bump(TokenKind::Name) else {
unreachable!()
};
let id = Expr::Name(ast::ExprName {
id: name.to_string(),
ctx: ExprContext::Load,
range: self.node_range(start),
});
let attribute = self.parse_attr_expr_for_match_pattern(id, start);
Pattern::MatchValue(ast::PatternMatchValue {
value: Box::new(attribute),
range: self.node_range(start),
})
}
TokenKind::Name => {
let (Tok::Name { name }, _) = self.bump(TokenKind::Name) else {
unreachable!()
};
let range = self.node_range(start);
// test_ok match_as_pattern
// match foo:
// case foo_bar: ...
// case _: ...
Pattern::MatchAs(ast::PatternMatchAs {
range,
pattern: None,
name: if &*name == "_" {
None
} else {
Some(ast::Identifier {
id: name.to_string(),
range,
})
},
})
}
// The `+` is only for better error recovery.
TokenKind::Minus | TokenKind::Plus
if matches!(
self.peek(),
TokenKind::Int | TokenKind::Float | TokenKind::Complex
) =>
{
let unary_expr = self.parse_unary_expression();
if unary_expr.op.is_u_add() {
self.add_error(
ParseErrorType::OtherError(
"Unary '+' is not allowed as a literal pattern".to_string(),
),
&unary_expr,
);
}
Pattern::MatchValue(ast::PatternMatchValue {
value: Box::new(Expr::UnaryOp(unary_expr)),
range: self.node_range(start),
})
}
kind => {
// Upon encountering an unexpected token, return a `Pattern::MatchValue` containing
// an empty `Expr::Name`.
let invalid_node = if kind.is_keyword() {
Expr::Name(self.parse_name())
} else {
self.add_error(
ParseErrorType::OtherError("Expected a pattern".to_string()),
self.current_token_range(),
);
Expr::Name(ast::ExprName {
range: self.missing_node_range(),
id: String::new(),
ctx: ExprContext::Invalid,
})
};
Pattern::MatchValue(ast::PatternMatchValue {
range: invalid_node.range(),
value: Box::new(invalid_node),
})
}
}
}
/// Parses a complex literal pattern, given the `lhs` pattern and the `start`
/// position of the pattern.
///
/// # Panics
///
/// If the parser isn't positioned at a `+` or `-` token.
///
/// See: <https://docs.python.org/3/reference/compound_stmts.html#literal-patterns>
fn parse_complex_literal_pattern(
&mut self,
lhs: Pattern,
start: TextSize,
) -> ast::PatternMatchValue {
let operator = if self.eat(TokenKind::Plus) {
Operator::Add
} else {
self.bump(TokenKind::Minus);
Operator::Sub
};
let lhs_value = if let Pattern::MatchValue(lhs) = lhs {
if !is_real_number(&lhs.value) {
self.add_error(ParseErrorType::ExpectedRealNumber, &lhs);
}
lhs.value
} else {
self.add_error(ParseErrorType::ExpectedRealNumber, &lhs);
Box::new(recovery::pattern_to_expr(lhs))
};
let rhs_pattern = self.parse_match_pattern_lhs(AllowStarPattern::No);
let rhs_value = if let Pattern::MatchValue(rhs) = rhs_pattern {
if !is_complex_number(&rhs.value) {
self.add_error(ParseErrorType::ExpectedImaginaryNumber, &rhs);
}
rhs.value
} else {
self.add_error(ParseErrorType::ExpectedImaginaryNumber, &rhs_pattern);
Box::new(recovery::pattern_to_expr(rhs_pattern))
};
let range = self.node_range(start);
ast::PatternMatchValue {
value: Box::new(Expr::BinOp(ast::ExprBinOp {
left: lhs_value,
op: operator,
right: rhs_value,
range,
})),
range,
}
}
/// Parses an attribute expression until the current token is not a `.`.
fn parse_attr_expr_for_match_pattern(&mut self, mut lhs: Expr, start: TextSize) -> Expr {
while self.current_token_kind() == TokenKind::Dot {
lhs = Expr::Attribute(self.parse_attribute_expression(lhs, start));
}
lhs
}
/// Parses the [pattern arguments] in a class pattern.
///
/// # Panics
///
/// If the parser isn't positioned at a `(` token.
///
/// See: <https://docs.python.org/3/reference/compound_stmts.html#class-patterns>
///
/// [pattern arguments]: https://docs.python.org/3/reference/compound_stmts.html#grammar-token-python-grammar-pattern_arguments
fn parse_match_pattern_class(
&mut self,
cls: Pattern,
start: TextSize,
) -> ast::PatternMatchClass {
let arguments_start = self.node_start();
let cls = match cls {
Pattern::MatchAs(ast::PatternMatchAs {
pattern: None,
name: Some(ident),
..
}) => {
if ident.is_valid() {
Box::new(Expr::Name(ast::ExprName {
range: ident.range(),
id: ident.id,
ctx: ExprContext::Load,
}))
} else {
Box::new(Expr::Name(ast::ExprName {
range: ident.range(),
id: String::new(),
ctx: ExprContext::Invalid,
}))
}
}
Pattern::MatchValue(ast::PatternMatchValue { value, .. })
if matches!(&*value, Expr::Attribute(_)) =>
{
value
}
pattern => {
self.add_error(
ParseErrorType::OtherError("Invalid value for a class pattern".to_string()),
&pattern,
);
Box::new(recovery::pattern_to_expr(pattern))
}
};
self.bump(TokenKind::Lpar);
let mut patterns = vec![];
let mut keywords = vec![];
let mut has_seen_pattern = false;
let mut has_seen_keyword_pattern = false;
self.parse_comma_separated_list(
RecoveryContextKind::MatchPatternClassArguments,
|parser| {
let pattern_start = parser.node_start();
let pattern = parser.parse_match_pattern(AllowStarPattern::No);
if parser.eat(TokenKind::Equal) {
has_seen_pattern = false;
has_seen_keyword_pattern = true;
let key = if let Pattern::MatchAs(ast::PatternMatchAs {
pattern: None,
name: Some(name),
..
}) = pattern
{
name
} else {
parser.add_error(
ParseErrorType::OtherError(
"Expected an identifier for the keyword pattern".to_string(),
),
&pattern,
);
ast::Identifier {
id: String::new(),
range: parser.missing_node_range(),
}
};
let value_pattern = parser.parse_match_pattern(AllowStarPattern::No);
keywords.push(ast::PatternKeyword {
attr: key,
pattern: value_pattern,
range: parser.node_range(pattern_start),
});
} else {
has_seen_pattern = true;
patterns.push(pattern);
}
if has_seen_keyword_pattern && has_seen_pattern {
parser.add_error(
ParseErrorType::OtherError(
"Positional patterns cannot follow keyword patterns".to_string(),
),
parser.node_range(pattern_start),
);
}
},
);
self.expect(TokenKind::Rpar);
ast::PatternMatchClass {
cls,
arguments: ast::PatternArguments {
patterns,
keywords,
range: self.node_range(arguments_start),
},
range: self.node_range(start),
}
}
}
#[derive(Debug, Clone, Copy)]
enum AllowStarPattern {
Yes,
No,
}
impl AllowStarPattern {
const fn is_no(self) -> bool {
matches!(self, AllowStarPattern::No)
}
}
/// Returns `true` if the given expression is a real number literal or a unary
/// addition or subtraction of a real number literal.
const fn is_real_number(expr: &Expr) -> bool {
match expr {
Expr::NumberLiteral(ast::ExprNumberLiteral {
value: ast::Number::Int(_) | ast::Number::Float(_),
..
}) => true,
Expr::UnaryOp(ast::ExprUnaryOp {
op: ast::UnaryOp::UAdd | ast::UnaryOp::USub,
operand,
..
}) => is_real_number(operand),
_ => false,
}
}
/// Returns `true` if the given expression is a complex number literal.
const fn is_complex_number(expr: &Expr) -> bool {
matches!(
expr,
Expr::NumberLiteral(ast::ExprNumberLiteral {
value: ast::Number::Complex { .. },
..
})
)
}

View file

@ -0,0 +1,46 @@
use crate::parser::Parser;
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub(super) struct TokenId(u32);
impl TokenId {
/// Increments the value of the token ID.
pub(super) fn increment(&mut self) {
// It's fine to just wrap around because the main purpose is to check whether
// the previous token ID is different from the current token ID.
self.0 = self.0.wrapping_add(1);
}
}
/// Captures the progress of the parser and allows to test if the parsing is still making progress
#[derive(Debug, Copy, Clone, Default)]
pub(super) struct ParserProgress(Option<TokenId>);
impl ParserProgress {
/// Returns true if the parser has passed this position
#[inline]
fn has_progressed(self, p: &Parser) -> bool {
match self.0 {
None => true,
Some(prev_token_id) => prev_token_id != p.current_token_id(),
}
}
/// Asserts that the parsing is still making progress.
///
/// # Panics
///
/// Panics if the parser hasn't progressed since the last call.
#[inline]
pub(super) fn assert_progressing(&mut self, p: &Parser) {
assert!(
self.has_progressed(p),
"The parser is no longer progressing. Stuck at '{}' {:?}:{:?}",
p.src_text(p.current_token_range()),
p.current_token_kind(),
p.current_token_range(),
);
self.0 = Some(p.current_token_id());
}
}

View file

@ -0,0 +1,168 @@
use ruff_python_ast::{self as ast, Expr, ExprContext, Pattern};
use ruff_text_size::{Ranged, TextLen, TextRange};
/// Convert the given [`Pattern`] to an [`Expr`].
///
/// This is used to convert an invalid use of pattern to their equivalent expression
/// to preserve the structure of the pattern.
///
/// The conversion is done as follows:
/// - `PatternMatchSingleton`: Boolean and None literals
/// - `PatternMatchValue`: The value itself
/// - `PatternMatchSequence`: List literal
/// - `PatternMatchMapping`: Dictionary literal
/// - `PatternMatchClass`: Call expression
/// - `PatternMatchStar`: Starred expression
/// - `PatternMatchAs`: The pattern itself or the name
/// - `PatternMatchOr`: Binary expression with `|` operator
///
/// Note that the sequence pattern is always converted to a list literal even
/// if it was surrounded by parentheses.
///
/// # Note
///
/// This function returns an invalid [`ast::ExprName`] if the given pattern is a [`Pattern::MatchAs`]
/// with both the pattern and name present. This is because it cannot be converted to an expression
/// without dropping one of them as there's no way to represent `x as y` as a valid expression.
pub(super) fn pattern_to_expr(pattern: Pattern) -> Expr {
match pattern {
Pattern::MatchSingleton(ast::PatternMatchSingleton { range, value }) => match value {
ast::Singleton::True => {
Expr::BooleanLiteral(ast::ExprBooleanLiteral { value: true, range })
}
ast::Singleton::False => Expr::BooleanLiteral(ast::ExprBooleanLiteral {
value: false,
range,
}),
ast::Singleton::None => Expr::NoneLiteral(ast::ExprNoneLiteral { range }),
},
Pattern::MatchValue(ast::PatternMatchValue { value, .. }) => *value,
// We don't know which kind of sequence this is: `case [1, 2]:` or `case (1, 2):`.
Pattern::MatchSequence(ast::PatternMatchSequence { range, patterns }) => {
Expr::List(ast::ExprList {
elts: patterns.into_iter().map(pattern_to_expr).collect(),
ctx: ExprContext::Store,
range,
})
}
Pattern::MatchMapping(ast::PatternMatchMapping {
range,
keys,
patterns,
rest,
}) => {
let mut keys = keys.into_iter().map(Option::Some).collect::<Vec<_>>();
let mut values = patterns
.into_iter()
.map(pattern_to_expr)
.collect::<Vec<_>>();
if let Some(rest) = rest {
keys.push(None);
values.push(Expr::Name(ast::ExprName {
range: rest.range,
id: rest.id,
ctx: ExprContext::Store,
}));
}
Expr::Dict(ast::ExprDict {
range,
keys,
values,
})
}
Pattern::MatchClass(ast::PatternMatchClass {
range,
cls,
arguments,
}) => Expr::Call(ast::ExprCall {
range,
func: cls,
arguments: ast::Arguments {
range: arguments.range,
args: arguments
.patterns
.into_iter()
.map(pattern_to_expr)
.collect(),
keywords: arguments
.keywords
.into_iter()
.map(|keyword_pattern| ast::Keyword {
range: keyword_pattern.range,
arg: Some(keyword_pattern.attr),
value: pattern_to_expr(keyword_pattern.pattern),
})
.collect(),
},
}),
Pattern::MatchStar(ast::PatternMatchStar { range, name }) => {
if let Some(name) = name {
Expr::Starred(ast::ExprStarred {
range,
value: Box::new(Expr::Name(ast::ExprName {
range: name.range,
id: name.id,
ctx: ExprContext::Store,
})),
ctx: ExprContext::Store,
})
} else {
Expr::Starred(ast::ExprStarred {
range,
value: Box::new(Expr::Name(ast::ExprName {
range: TextRange::new(range.end() - "_".text_len(), range.end()),
id: "_".to_string(),
ctx: ExprContext::Store,
})),
ctx: ExprContext::Store,
})
}
}
Pattern::MatchAs(ast::PatternMatchAs {
range,
pattern,
name,
}) => match (pattern, name) {
(Some(_), Some(_)) => Expr::Name(ast::ExprName {
range,
id: String::new(),
ctx: ExprContext::Invalid,
}),
(Some(pattern), None) => pattern_to_expr(*pattern),
(None, Some(name)) => Expr::Name(ast::ExprName {
range: name.range,
id: name.id,
ctx: ExprContext::Store,
}),
(None, None) => Expr::Name(ast::ExprName {
range,
id: "_".to_string(),
ctx: ExprContext::Store,
}),
},
Pattern::MatchOr(ast::PatternMatchOr { patterns, .. }) => {
let to_bin_expr = |left: Pattern, right: Pattern| ast::ExprBinOp {
range: TextRange::new(left.start(), right.end()),
left: Box::new(pattern_to_expr(left)),
op: ast::Operator::BitOr,
right: Box::new(pattern_to_expr(right)),
};
let mut iter = patterns.into_iter();
match (iter.next(), iter.next()) {
(Some(left), Some(right)) => {
Expr::BinOp(iter.fold(to_bin_expr(left, right), |expr_bin_op, pattern| {
ast::ExprBinOp {
range: TextRange::new(expr_bin_op.start(), pattern.end()),
left: Box::new(Expr::BinOp(expr_bin_op)),
op: ast::Operator::BitOr,
right: Box::new(pattern_to_expr(pattern)),
}
}))
}
_ => unreachable!("Or patterns can only be formed with at least two patterns."),
}
}
}
}

View file

@ -0,0 +1,8 @@
---
source: crates/ruff_python_parser/src/parser/tests.rs
expression: error
---
ParseError {
error: UnexpectedExpressionToken,
location: 6..12,
}

View file

@ -0,0 +1,8 @@
---
source: crates/ruff_python_parser/src/parser/tests.rs
expression: error
---
ParseError {
error: UnexpectedExpressionToken,
location: 7..13,
}

View file

@ -0,0 +1,8 @@
---
source: crates/ruff_python_parser/src/parser/tests.rs
expression: error
---
ParseError {
error: UnexpectedExpressionToken,
location: 7..13,
}

View file

@ -0,0 +1,11 @@
---
source: crates/ruff_python_parser/src/parser/tests.rs
expression: expr
---
Name(
ExprName {
range: 0..5,
id: "first",
ctx: Load,
},
)

View file

@ -1,5 +1,5 @@
---
source: crates/ruff_python_parser/src/parser.rs
source: crates/ruff_python_parser/src/parser/tests.rs
expression: parse_ast
---
Module(

View file

@ -1,5 +1,5 @@
---
source: crates/ruff_python_parser/src/parser.rs
source: crates/ruff_python_parser/src/parser/tests.rs
expression: parse_ast
---
[

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,152 @@
use crate::{lex, parse, parse_expression, parse_suite, parse_tokens, Mode};
#[test]
fn test_modes() {
let source = "a[0][1][2][3][4]";
assert!(parse(source, Mode::Expression).is_ok());
assert!(parse(source, Mode::Module).is_ok());
}
#[test]
fn test_expr_mode_invalid_syntax1() {
let source = "first second";
let error = parse_expression(source).unwrap_err();
insta::assert_debug_snapshot!(error);
}
#[test]
fn test_expr_mode_invalid_syntax2() {
let source = r"first
second
";
let error = parse_expression(source).unwrap_err();
insta::assert_debug_snapshot!(error);
}
#[test]
fn test_expr_mode_invalid_syntax3() {
let source = r"first
second
third
";
let error = parse_expression(source).unwrap_err();
insta::assert_debug_snapshot!(error);
}
#[test]
fn test_expr_mode_valid_syntax() {
let source = "first
";
let expr = parse_expression(source).unwrap();
insta::assert_debug_snapshot!(expr);
}
#[test]
fn test_unicode_aliases() {
// https://github.com/RustPython/RustPython/issues/4566
let source = r#"x = "\N{BACKSPACE}another cool trick""#;
let parse_ast = parse_suite(source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_ipython_escape_commands() {
let parse_ast = parse(
r"
# Normal Python code
(
a
%
b
)
# Dynamic object info
??a.foo
?a.foo
?a.foo?
??a.foo()??
# Line magic
%timeit a = b
%timeit foo(b) % 3
%alias showPath pwd && ls -a
%timeit a =\
foo(b); b = 2
%matplotlib --inline
%matplotlib \
--inline
# System shell access
!pwd && ls -a | sed 's/^/\ /'
!pwd \
&& ls -a | sed 's/^/\\ /'
!!cd /Users/foo/Library/Application\ Support/
# Let's add some Python code to make sure that earlier escapes were handled
# correctly and that we didn't consume any of the following code as a result
# of the escapes.
def foo():
return (
a
!=
b
)
# Transforms into `foo(..)`
/foo 1 2
;foo 1 2
,foo 1 2
# Indented escape commands
for a in range(5):
!ls
p1 = !pwd
p2: str = !pwd
foo = %foo \
bar
% foo
foo = %foo # comment
# Help end line magics
foo?
foo.bar??
foo.bar.baz?
foo[0]??
foo[0][1]?
foo.bar[0].baz[1]??
foo.bar[0].baz[2].egg??
"
.trim(),
Mode::Ipython,
)
.unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_ipython_escape_command_parse_error() {
let source = r"
a = 1
%timeit a == 1
"
.trim();
let lxr = lex(source, Mode::Ipython);
let parse_err = parse_tokens(lxr.collect(), source, Mode::Module).unwrap_err();
assert_eq!(
parse_err.to_string(),
"IPython escape commands are only allowed in `Mode::Ipython` at byte range 6..20"
.to_string()
);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,36 +0,0 @@
---
source: crates/ruff_python_parser/src/context.rs
expression: parse_ast
---
[
AnnAssign(
StmtAnnAssign {
range: 0..10,
target: Name(
ExprName {
range: 0..1,
id: "x",
ctx: Store,
},
),
annotation: Name(
ExprName {
range: 3..6,
id: "int",
ctx: Load,
},
),
value: Some(
NumberLiteral(
ExprNumberLiteral {
range: 9..10,
value: Int(
1,
),
},
),
),
simple: true,
},
),
]

View file

@ -1,63 +0,0 @@
---
source: crates/ruff_python_parser/src/context.rs
expression: parse_ast
---
[
Assign(
StmtAssign {
range: 0..15,
targets: [
Attribute(
ExprAttribute {
range: 0..3,
value: Name(
ExprName {
range: 0..1,
id: "x",
ctx: Load,
},
),
attr: Identifier {
id: "y",
range: 2..3,
},
ctx: Store,
},
),
],
value: Tuple(
ExprTuple {
range: 6..15,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 7..8,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 10..11,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 13..14,
value: Int(
3,
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
},
),
]

View file

@ -1,60 +0,0 @@
---
source: crates/ruff_python_parser/src/context.rs
expression: parse_ast
---
[
For(
StmtFor {
range: 0..24,
is_async: false,
target: Name(
ExprName {
range: 4..5,
id: "x",
ctx: Store,
},
),
iter: Tuple(
ExprTuple {
range: 9..18,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 10..11,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 13..14,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 16..17,
value: Int(
3,
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
body: [
Pass(
StmtPass {
range: 20..24,
},
),
],
orelse: [],
},
),
]

View file

@ -1,68 +0,0 @@
---
source: crates/ruff_python_parser/src/context.rs
expression: parse_ast
---
[
Assign(
StmtAssign {
range: 0..18,
targets: [
List(
ExprList {
range: 0..6,
elts: [
Name(
ExprName {
range: 1..2,
id: "x",
ctx: Store,
},
),
Name(
ExprName {
range: 4..5,
id: "y",
ctx: Store,
},
),
],
ctx: Store,
},
),
],
value: Tuple(
ExprTuple {
range: 9..18,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 10..11,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 13..14,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 16..17,
value: Int(
3,
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
},
),
]

View file

@ -1,79 +0,0 @@
---
source: crates/ruff_python_parser/src/context.rs
expression: parse_ast
---
[
Assign(
StmtAssign {
range: 0..26,
targets: [
Name(
ExprName {
range: 0..1,
id: "x",
ctx: Store,
},
),
],
value: ListComp(
ExprListComp {
range: 4..26,
elt: Name(
ExprName {
range: 5..6,
id: "y",
ctx: Load,
},
),
generators: [
Comprehension {
range: 7..25,
target: Name(
ExprName {
range: 11..12,
id: "y",
ctx: Store,
},
),
iter: Tuple(
ExprTuple {
range: 16..25,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 17..18,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 20..21,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 23..24,
value: Int(
3,
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
ifs: [],
is_async: false,
},
],
},
),
},
),
]

View file

@ -1,53 +0,0 @@
---
source: crates/ruff_python_parser/src/context.rs
expression: parse_ast
---
[
Assign(
StmtAssign {
range: 0..13,
targets: [
Name(
ExprName {
range: 0..1,
id: "x",
ctx: Store,
},
),
],
value: Tuple(
ExprTuple {
range: 4..13,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 5..6,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 8..9,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 11..12,
value: Int(
3,
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
},
),
]

View file

@ -1,39 +0,0 @@
---
source: crates/ruff_python_parser/src/context.rs
expression: parse_ast
---
[
If(
StmtIf {
range: 0..14,
test: Named(
ExprNamed {
range: 3..8,
target: Name(
ExprName {
range: 3..4,
id: "x",
ctx: Store,
},
),
value: NumberLiteral(
ExprNumberLiteral {
range: 7..8,
value: Int(
1,
),
},
),
},
),
body: [
Pass(
StmtPass {
range: 10..14,
},
),
],
elif_else_clauses: [],
},
),
]

View file

@ -1,79 +0,0 @@
---
source: crates/ruff_python_parser/src/context.rs
expression: parse_ast
---
[
Assign(
StmtAssign {
range: 0..26,
targets: [
Name(
ExprName {
range: 0..1,
id: "x",
ctx: Store,
},
),
],
value: SetComp(
ExprSetComp {
range: 4..26,
elt: Name(
ExprName {
range: 5..6,
id: "y",
ctx: Load,
},
),
generators: [
Comprehension {
range: 7..25,
target: Name(
ExprName {
range: 11..12,
id: "y",
ctx: Store,
},
),
iter: Tuple(
ExprTuple {
range: 16..25,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 17..18,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 20..21,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 23..24,
value: Int(
3,
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
ifs: [],
is_async: false,
},
],
},
),
},
),
]

View file

@ -1,75 +0,0 @@
---
source: crates/ruff_python_parser/src/context.rs
expression: parse_ast
---
[
Assign(
StmtAssign {
range: 0..19,
targets: [
Tuple(
ExprTuple {
range: 0..7,
elts: [
Name(
ExprName {
range: 1..2,
id: "x",
ctx: Store,
},
),
Starred(
ExprStarred {
range: 4..6,
value: Name(
ExprName {
range: 5..6,
id: "y",
ctx: Store,
},
),
ctx: Store,
},
),
],
ctx: Store,
parenthesized: true,
},
),
],
value: Tuple(
ExprTuple {
range: 10..19,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 11..12,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 14..15,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 17..18,
value: Int(
3,
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
},
),
]

View file

@ -1,66 +0,0 @@
---
source: crates/ruff_python_parser/src/context.rs
expression: parse_ast
---
[
Assign(
StmtAssign {
range: 0..16,
targets: [
Subscript(
ExprSubscript {
range: 0..4,
value: Name(
ExprName {
range: 0..1,
id: "x",
ctx: Load,
},
),
slice: Name(
ExprName {
range: 2..3,
id: "y",
ctx: Load,
},
),
ctx: Store,
},
),
],
value: Tuple(
ExprTuple {
range: 7..16,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 8..9,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 11..12,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 14..15,
value: Int(
3,
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
},
),
]

View file

@ -1,69 +0,0 @@
---
source: crates/ruff_python_parser/src/context.rs
expression: parse_ast
---
[
Assign(
StmtAssign {
range: 0..18,
targets: [
Tuple(
ExprTuple {
range: 0..6,
elts: [
Name(
ExprName {
range: 1..2,
id: "x",
ctx: Store,
},
),
Name(
ExprName {
range: 4..5,
id: "y",
ctx: Store,
},
),
],
ctx: Store,
parenthesized: true,
},
),
],
value: Tuple(
ExprTuple {
range: 9..18,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 10..11,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 13..14,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 16..17,
value: Int(
3,
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
},
),
]

View file

@ -1,41 +0,0 @@
---
source: crates/ruff_python_parser/src/context.rs
expression: parse_ast
---
[
With(
StmtWith {
range: 0..17,
is_async: false,
items: [
WithItem {
range: 5..11,
context_expr: NumberLiteral(
ExprNumberLiteral {
range: 5..6,
value: Int(
1,
),
},
),
optional_vars: Some(
Name(
ExprName {
range: 10..11,
id: "x",
ctx: Store,
},
),
),
},
],
body: [
Pass(
StmtPass {
range: 13..17,
},
),
],
},
),
]

View file

@ -1,62 +0,0 @@
---
source: crates/ruff_python_parser/src/context.rs
expression: parse_ast
---
[
AugAssign(
StmtAugAssign {
range: 0..16,
target: Attribute(
ExprAttribute {
range: 0..3,
value: Name(
ExprName {
range: 0..1,
id: "x",
ctx: Load,
},
),
attr: Identifier {
id: "y",
range: 2..3,
},
ctx: Store,
},
),
op: Add,
value: Tuple(
ExprTuple {
range: 7..16,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 8..9,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 11..12,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 14..15,
value: Int(
3,
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
},
),
]

View file

@ -1,27 +0,0 @@
---
source: crates/ruff_python_parser/src/context.rs
expression: parse_ast
---
[
AugAssign(
StmtAugAssign {
range: 0..6,
target: Name(
ExprName {
range: 0..1,
id: "x",
ctx: Store,
},
),
op: Add,
value: NumberLiteral(
ExprNumberLiteral {
range: 5..6,
value: Int(
1,
),
},
),
},
),
]

View file

@ -1,65 +0,0 @@
---
source: crates/ruff_python_parser/src/context.rs
expression: parse_ast
---
[
AugAssign(
StmtAugAssign {
range: 0..17,
target: Subscript(
ExprSubscript {
range: 0..4,
value: Name(
ExprName {
range: 0..1,
id: "x",
ctx: Load,
},
),
slice: Name(
ExprName {
range: 2..3,
id: "y",
ctx: Load,
},
),
ctx: Store,
},
),
op: Add,
value: Tuple(
ExprTuple {
range: 8..17,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 9..10,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 12..13,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 15..16,
value: Int(
3,
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
},
),
]

View file

@ -1,30 +0,0 @@
---
source: crates/ruff_python_parser/src/context.rs
expression: parse_ast
---
[
Delete(
StmtDelete {
range: 0..7,
targets: [
Attribute(
ExprAttribute {
range: 4..7,
value: Name(
ExprName {
range: 4..5,
id: "x",
ctx: Load,
},
),
attr: Identifier {
id: "y",
range: 6..7,
},
ctx: Del,
},
),
],
},
),
]

View file

@ -1,20 +0,0 @@
---
source: crates/ruff_python_parser/src/context.rs
expression: parse_ast
---
[
Delete(
StmtDelete {
range: 0..5,
targets: [
Name(
ExprName {
range: 4..5,
id: "x",
ctx: Del,
},
),
],
},
),
]

View file

@ -1,33 +0,0 @@
---
source: crates/ruff_python_parser/src/context.rs
expression: parse_ast
---
[
Delete(
StmtDelete {
range: 0..8,
targets: [
Subscript(
ExprSubscript {
range: 4..8,
value: Name(
ExprName {
range: 4..5,
id: "x",
ctx: Load,
},
),
slice: Name(
ExprName {
range: 6..7,
id: "y",
ctx: Load,
},
),
ctx: Del,
},
),
],
},
),
]

View file

@ -1,73 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
FunctionDef(
StmtFunctionDef {
range: 0..23,
is_async: false,
decorator_list: [],
name: Identifier {
id: "f",
range: 4..5,
},
type_params: None,
parameters: Parameters {
range: 5..17,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [
ParameterWithDefault {
range: 9..10,
parameter: Parameter {
range: 9..10,
name: Identifier {
id: "a",
range: 9..10,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 12..13,
parameter: Parameter {
range: 12..13,
name: Identifier {
id: "b",
range: 12..13,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 15..16,
parameter: Parameter {
range: 15..16,
name: Identifier {
id: "c",
range: 15..16,
},
annotation: None,
},
default: None,
},
],
kwarg: None,
},
returns: None,
body: [
Pass(
StmtPass {
range: 19..23,
},
),
],
},
),
],
)

View file

@ -1,91 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
FunctionDef(
StmtFunctionDef {
range: 0..29,
is_async: false,
decorator_list: [],
name: Identifier {
id: "f",
range: 4..5,
},
type_params: None,
parameters: Parameters {
range: 5..23,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [
ParameterWithDefault {
range: 9..10,
parameter: Parameter {
range: 9..10,
name: Identifier {
id: "a",
range: 9..10,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 12..16,
parameter: Parameter {
range: 12..13,
name: Identifier {
id: "b",
range: 12..13,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 14..16,
value: Int(
20,
),
},
),
),
},
ParameterWithDefault {
range: 18..22,
parameter: Parameter {
range: 18..19,
name: Identifier {
id: "c",
range: 18..19,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 20..22,
value: Int(
30,
),
},
),
),
},
],
kwarg: None,
},
returns: None,
body: [
Pass(
StmtPass {
range: 25..29,
},
),
],
},
),
],
)

View file

@ -1,100 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
FunctionDef(
StmtFunctionDef {
range: 0..39,
is_async: false,
decorator_list: [],
name: Identifier {
id: "f",
range: 4..5,
},
type_params: None,
parameters: Parameters {
range: 5..33,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [
ParameterWithDefault {
range: 9..10,
parameter: Parameter {
range: 9..10,
name: Identifier {
id: "a",
range: 9..10,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 12..16,
parameter: Parameter {
range: 12..13,
name: Identifier {
id: "b",
range: 12..13,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 14..16,
value: Int(
20,
),
},
),
),
},
ParameterWithDefault {
range: 18..22,
parameter: Parameter {
range: 18..19,
name: Identifier {
id: "c",
range: 18..19,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 20..22,
value: Int(
30,
),
},
),
),
},
],
kwarg: Some(
Parameter {
range: 24..32,
name: Identifier {
id: "kwargs",
range: 26..32,
},
annotation: None,
},
),
},
returns: None,
body: [
Pass(
StmtPass {
range: 35..39,
},
),
],
},
),
],
)

View file

@ -1,100 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
FunctionDef(
StmtFunctionDef {
range: 0..33,
is_async: false,
decorator_list: [],
name: Identifier {
id: "f",
range: 4..5,
},
type_params: None,
parameters: Parameters {
range: 5..27,
posonlyargs: [],
args: [],
vararg: Some(
Parameter {
range: 6..11,
name: Identifier {
id: "args",
range: 7..11,
},
annotation: None,
},
),
kwonlyargs: [
ParameterWithDefault {
range: 13..14,
parameter: Parameter {
range: 13..14,
name: Identifier {
id: "a",
range: 13..14,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 16..20,
parameter: Parameter {
range: 16..17,
name: Identifier {
id: "b",
range: 16..17,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 18..20,
value: Int(
20,
),
},
),
),
},
ParameterWithDefault {
range: 22..26,
parameter: Parameter {
range: 22..23,
name: Identifier {
id: "c",
range: 22..23,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 24..26,
value: Int(
30,
),
},
),
),
},
],
kwarg: None,
},
returns: None,
body: [
Pass(
StmtPass {
range: 29..33,
},
),
],
},
),
],
)

View file

@ -1,109 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
FunctionDef(
StmtFunctionDef {
range: 0..43,
is_async: false,
decorator_list: [],
name: Identifier {
id: "f",
range: 4..5,
},
type_params: None,
parameters: Parameters {
range: 5..37,
posonlyargs: [],
args: [],
vararg: Some(
Parameter {
range: 6..11,
name: Identifier {
id: "args",
range: 7..11,
},
annotation: None,
},
),
kwonlyargs: [
ParameterWithDefault {
range: 13..14,
parameter: Parameter {
range: 13..14,
name: Identifier {
id: "a",
range: 13..14,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 16..20,
parameter: Parameter {
range: 16..17,
name: Identifier {
id: "b",
range: 16..17,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 18..20,
value: Int(
20,
),
},
),
),
},
ParameterWithDefault {
range: 22..26,
parameter: Parameter {
range: 22..23,
name: Identifier {
id: "c",
range: 22..23,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 24..26,
value: Int(
30,
),
},
),
),
},
],
kwarg: Some(
Parameter {
range: 28..36,
name: Identifier {
id: "kwargs",
range: 30..36,
},
annotation: None,
},
),
},
returns: None,
body: [
Pass(
StmtPass {
range: 39..43,
},
),
],
},
),
],
)

View file

@ -1,36 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
FunctionDef(
StmtFunctionDef {
range: 0..13,
is_async: false,
decorator_list: [],
name: Identifier {
id: "f",
range: 4..5,
},
type_params: None,
parameters: Parameters {
range: 5..7,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Pass(
StmtPass {
range: 9..13,
},
),
],
},
),
],
)

View file

@ -1,36 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
FunctionDef(
StmtFunctionDef {
range: 0..13,
is_async: false,
decorator_list: [],
name: Identifier {
id: "f",
range: 4..5,
},
type_params: None,
parameters: Parameters {
range: 5..7,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Pass(
StmtPass {
range: 9..13,
},
),
],
},
),
],
)

View file

@ -1,111 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
FunctionDef(
StmtFunctionDef {
range: 0..35,
is_async: false,
decorator_list: [],
name: Identifier {
id: "f",
range: 4..5,
},
type_params: None,
parameters: Parameters {
range: 5..29,
posonlyargs: [
ParameterWithDefault {
range: 6..7,
parameter: Parameter {
range: 6..7,
name: Identifier {
id: "a",
range: 6..7,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 9..10,
parameter: Parameter {
range: 9..10,
name: Identifier {
id: "b",
range: 9..10,
},
annotation: None,
},
default: None,
},
],
args: [
ParameterWithDefault {
range: 15..16,
parameter: Parameter {
range: 15..16,
name: Identifier {
id: "c",
range: 15..16,
},
annotation: None,
},
default: None,
},
],
vararg: None,
kwonlyargs: [
ParameterWithDefault {
range: 21..22,
parameter: Parameter {
range: 21..22,
name: Identifier {
id: "d",
range: 21..22,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 24..25,
parameter: Parameter {
range: 24..25,
name: Identifier {
id: "e",
range: 24..25,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 27..28,
parameter: Parameter {
range: 27..28,
name: Identifier {
id: "f",
range: 27..28,
},
annotation: None,
},
default: None,
},
],
kwarg: None,
},
returns: None,
body: [
Pass(
StmtPass {
range: 31..35,
},
),
],
},
),
],
)

View file

@ -1,129 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
FunctionDef(
StmtFunctionDef {
range: 0..41,
is_async: false,
decorator_list: [],
name: Identifier {
id: "f",
range: 4..5,
},
type_params: None,
parameters: Parameters {
range: 5..35,
posonlyargs: [
ParameterWithDefault {
range: 6..7,
parameter: Parameter {
range: 6..7,
name: Identifier {
id: "a",
range: 6..7,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 9..10,
parameter: Parameter {
range: 9..10,
name: Identifier {
id: "b",
range: 9..10,
},
annotation: None,
},
default: None,
},
],
args: [
ParameterWithDefault {
range: 15..16,
parameter: Parameter {
range: 15..16,
name: Identifier {
id: "c",
range: 15..16,
},
annotation: None,
},
default: None,
},
],
vararg: None,
kwonlyargs: [
ParameterWithDefault {
range: 21..22,
parameter: Parameter {
range: 21..22,
name: Identifier {
id: "d",
range: 21..22,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 24..28,
parameter: Parameter {
range: 24..25,
name: Identifier {
id: "e",
range: 24..25,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 26..28,
value: Int(
20,
),
},
),
),
},
ParameterWithDefault {
range: 30..34,
parameter: Parameter {
range: 30..31,
name: Identifier {
id: "f",
range: 30..31,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 32..34,
value: Int(
30,
),
},
),
),
},
],
kwarg: None,
},
returns: None,
body: [
Pass(
StmtPass {
range: 37..41,
},
),
],
},
),
],
)

View file

@ -1,138 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
FunctionDef(
StmtFunctionDef {
range: 0..51,
is_async: false,
decorator_list: [],
name: Identifier {
id: "f",
range: 4..5,
},
type_params: None,
parameters: Parameters {
range: 5..45,
posonlyargs: [
ParameterWithDefault {
range: 6..7,
parameter: Parameter {
range: 6..7,
name: Identifier {
id: "a",
range: 6..7,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 9..10,
parameter: Parameter {
range: 9..10,
name: Identifier {
id: "b",
range: 9..10,
},
annotation: None,
},
default: None,
},
],
args: [
ParameterWithDefault {
range: 15..16,
parameter: Parameter {
range: 15..16,
name: Identifier {
id: "c",
range: 15..16,
},
annotation: None,
},
default: None,
},
],
vararg: None,
kwonlyargs: [
ParameterWithDefault {
range: 21..22,
parameter: Parameter {
range: 21..22,
name: Identifier {
id: "d",
range: 21..22,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 24..28,
parameter: Parameter {
range: 24..25,
name: Identifier {
id: "e",
range: 24..25,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 26..28,
value: Int(
20,
),
},
),
),
},
ParameterWithDefault {
range: 30..34,
parameter: Parameter {
range: 30..31,
name: Identifier {
id: "f",
range: 30..31,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 32..34,
value: Int(
30,
),
},
),
),
},
],
kwarg: Some(
Parameter {
range: 36..44,
name: Identifier {
id: "kwargs",
range: 38..44,
},
annotation: None,
},
),
},
returns: None,
body: [
Pass(
StmtPass {
range: 47..51,
},
),
],
},
),
],
)

View file

@ -1,138 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
FunctionDef(
StmtFunctionDef {
range: 0..45,
is_async: false,
decorator_list: [],
name: Identifier {
id: "f",
range: 4..5,
},
type_params: None,
parameters: Parameters {
range: 5..39,
posonlyargs: [
ParameterWithDefault {
range: 6..7,
parameter: Parameter {
range: 6..7,
name: Identifier {
id: "a",
range: 6..7,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 9..10,
parameter: Parameter {
range: 9..10,
name: Identifier {
id: "b",
range: 9..10,
},
annotation: None,
},
default: None,
},
],
args: [
ParameterWithDefault {
range: 15..16,
parameter: Parameter {
range: 15..16,
name: Identifier {
id: "c",
range: 15..16,
},
annotation: None,
},
default: None,
},
],
vararg: Some(
Parameter {
range: 18..23,
name: Identifier {
id: "args",
range: 19..23,
},
annotation: None,
},
),
kwonlyargs: [
ParameterWithDefault {
range: 25..26,
parameter: Parameter {
range: 25..26,
name: Identifier {
id: "d",
range: 25..26,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 28..32,
parameter: Parameter {
range: 28..29,
name: Identifier {
id: "e",
range: 28..29,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 30..32,
value: Int(
20,
),
},
),
),
},
ParameterWithDefault {
range: 34..38,
parameter: Parameter {
range: 34..35,
name: Identifier {
id: "f",
range: 34..35,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 36..38,
value: Int(
30,
),
},
),
),
},
],
kwarg: None,
},
returns: None,
body: [
Pass(
StmtPass {
range: 41..45,
},
),
],
},
),
],
)

View file

@ -1,147 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
FunctionDef(
StmtFunctionDef {
range: 0..55,
is_async: false,
decorator_list: [],
name: Identifier {
id: "f",
range: 4..5,
},
type_params: None,
parameters: Parameters {
range: 5..49,
posonlyargs: [
ParameterWithDefault {
range: 6..7,
parameter: Parameter {
range: 6..7,
name: Identifier {
id: "a",
range: 6..7,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 9..10,
parameter: Parameter {
range: 9..10,
name: Identifier {
id: "b",
range: 9..10,
},
annotation: None,
},
default: None,
},
],
args: [
ParameterWithDefault {
range: 15..16,
parameter: Parameter {
range: 15..16,
name: Identifier {
id: "c",
range: 15..16,
},
annotation: None,
},
default: None,
},
],
vararg: Some(
Parameter {
range: 18..23,
name: Identifier {
id: "args",
range: 19..23,
},
annotation: None,
},
),
kwonlyargs: [
ParameterWithDefault {
range: 25..26,
parameter: Parameter {
range: 25..26,
name: Identifier {
id: "d",
range: 25..26,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 28..32,
parameter: Parameter {
range: 28..29,
name: Identifier {
id: "e",
range: 28..29,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 30..32,
value: Int(
20,
),
},
),
),
},
ParameterWithDefault {
range: 34..38,
parameter: Parameter {
range: 34..35,
name: Identifier {
id: "f",
range: 34..35,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 36..38,
value: Int(
30,
),
},
),
),
},
],
kwarg: Some(
Parameter {
range: 40..48,
name: Identifier {
id: "kwargs",
range: 42..48,
},
annotation: None,
},
),
},
returns: None,
body: [
Pass(
StmtPass {
range: 51..55,
},
),
],
},
),
],
)

View file

@ -1,73 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
FunctionDef(
StmtFunctionDef {
range: 0..20,
is_async: false,
decorator_list: [],
name: Identifier {
id: "f",
range: 4..5,
},
type_params: None,
parameters: Parameters {
range: 5..14,
posonlyargs: [],
args: [
ParameterWithDefault {
range: 6..7,
parameter: Parameter {
range: 6..7,
name: Identifier {
id: "a",
range: 6..7,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 9..10,
parameter: Parameter {
range: 9..10,
name: Identifier {
id: "b",
range: 9..10,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 12..13,
parameter: Parameter {
range: 12..13,
name: Identifier {
id: "c",
range: 12..13,
},
annotation: None,
},
default: None,
},
],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Pass(
StmtPass {
range: 16..20,
},
),
],
},
),
],
)

View file

@ -1,92 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
FunctionDef(
StmtFunctionDef {
range: 0..29,
is_async: false,
decorator_list: [],
name: Identifier {
id: "f",
range: 4..5,
},
type_params: None,
parameters: Parameters {
range: 5..23,
posonlyargs: [
ParameterWithDefault {
range: 6..7,
parameter: Parameter {
range: 6..7,
name: Identifier {
id: "a",
range: 6..7,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 9..13,
parameter: Parameter {
range: 9..10,
name: Identifier {
id: "b",
range: 9..10,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 11..13,
value: Int(
20,
),
},
),
),
},
],
args: [
ParameterWithDefault {
range: 18..22,
parameter: Parameter {
range: 18..19,
name: Identifier {
id: "c",
range: 18..19,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 20..22,
value: Int(
30,
),
},
),
),
},
],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Pass(
StmtPass {
range: 25..29,
},
),
],
},
),
],
)

View file

@ -1,110 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
FunctionDef(
StmtFunctionDef {
range: 0..46,
is_async: false,
decorator_list: [],
name: Identifier {
id: "f",
range: 4..5,
},
type_params: None,
parameters: Parameters {
range: 5..40,
posonlyargs: [
ParameterWithDefault {
range: 6..7,
parameter: Parameter {
range: 6..7,
name: Identifier {
id: "a",
range: 6..7,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 9..13,
parameter: Parameter {
range: 9..10,
name: Identifier {
id: "b",
range: 9..10,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 11..13,
value: Int(
20,
),
},
),
),
},
],
args: [
ParameterWithDefault {
range: 18..22,
parameter: Parameter {
range: 18..19,
name: Identifier {
id: "c",
range: 18..19,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 20..22,
value: Int(
30,
),
},
),
),
},
],
vararg: Some(
Parameter {
range: 24..29,
name: Identifier {
id: "args",
range: 25..29,
},
annotation: None,
},
),
kwonlyargs: [],
kwarg: Some(
Parameter {
range: 31..39,
name: Identifier {
id: "kwargs",
range: 33..39,
},
annotation: None,
},
),
},
returns: None,
body: [
Pass(
StmtPass {
range: 42..46,
},
),
],
},
),
],
)

View file

@ -1,73 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
FunctionDef(
StmtFunctionDef {
range: 0..20,
is_async: false,
decorator_list: [],
name: Identifier {
id: "f",
range: 4..5,
},
type_params: None,
parameters: Parameters {
range: 5..14,
posonlyargs: [],
args: [
ParameterWithDefault {
range: 6..7,
parameter: Parameter {
range: 6..7,
name: Identifier {
id: "a",
range: 6..7,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 9..10,
parameter: Parameter {
range: 9..10,
name: Identifier {
id: "b",
range: 9..10,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 12..13,
parameter: Parameter {
range: 12..13,
name: Identifier {
id: "c",
range: 12..13,
},
annotation: None,
},
default: None,
},
],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Pass(
StmtPass {
range: 16..20,
},
),
],
},
),
],
)

View file

@ -1,74 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
FunctionDef(
StmtFunctionDef {
range: 0..23,
is_async: false,
decorator_list: [],
name: Identifier {
id: "f",
range: 4..5,
},
type_params: None,
parameters: Parameters {
range: 5..17,
posonlyargs: [
ParameterWithDefault {
range: 6..7,
parameter: Parameter {
range: 6..7,
name: Identifier {
id: "a",
range: 6..7,
},
annotation: None,
},
default: None,
},
],
args: [
ParameterWithDefault {
range: 12..13,
parameter: Parameter {
range: 12..13,
name: Identifier {
id: "b",
range: 12..13,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 15..16,
parameter: Parameter {
range: 15..16,
name: Identifier {
id: "c",
range: 15..16,
},
annotation: None,
},
default: None,
},
],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Pass(
StmtPass {
range: 19..23,
},
),
],
},
),
],
)

View file

@ -1,73 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
Expr(
StmtExpr {
range: 0..20,
value: Lambda(
ExprLambda {
range: 0..20,
parameters: Some(
Parameters {
range: 7..17,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [
ParameterWithDefault {
range: 10..11,
parameter: Parameter {
range: 10..11,
name: Identifier {
id: "a",
range: 10..11,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 13..14,
parameter: Parameter {
range: 13..14,
name: Identifier {
id: "b",
range: 13..14,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 16..17,
parameter: Parameter {
range: 16..17,
name: Identifier {
id: "c",
range: 16..17,
},
annotation: None,
},
default: None,
},
],
kwarg: None,
},
),
body: NumberLiteral(
ExprNumberLiteral {
range: 19..20,
value: Int(
1,
),
},
),
},
),
},
),
],
)

View file

@ -1,91 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
Expr(
StmtExpr {
range: 0..26,
value: Lambda(
ExprLambda {
range: 0..26,
parameters: Some(
Parameters {
range: 7..23,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [
ParameterWithDefault {
range: 10..11,
parameter: Parameter {
range: 10..11,
name: Identifier {
id: "a",
range: 10..11,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 13..17,
parameter: Parameter {
range: 13..14,
name: Identifier {
id: "b",
range: 13..14,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 15..17,
value: Int(
20,
),
},
),
),
},
ParameterWithDefault {
range: 19..23,
parameter: Parameter {
range: 19..20,
name: Identifier {
id: "c",
range: 19..20,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 21..23,
value: Int(
30,
),
},
),
),
},
],
kwarg: None,
},
),
body: NumberLiteral(
ExprNumberLiteral {
range: 25..26,
value: Int(
1,
),
},
),
},
),
},
),
],
)

View file

@ -1,27 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
Expr(
StmtExpr {
range: 0..9,
value: Lambda(
ExprLambda {
range: 0..9,
parameters: None,
body: NumberLiteral(
ExprNumberLiteral {
range: 8..9,
value: Int(
1,
),
},
),
},
),
},
),
],
)

View file

@ -1,99 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
Expr(
StmtExpr {
range: 0..29,
value: Lambda(
ExprLambda {
range: 0..29,
parameters: Some(
Parameters {
range: 7..26,
posonlyargs: [
ParameterWithDefault {
range: 7..8,
parameter: Parameter {
range: 7..8,
name: Identifier {
id: "a",
range: 7..8,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 10..11,
parameter: Parameter {
range: 10..11,
name: Identifier {
id: "b",
range: 10..11,
},
annotation: None,
},
default: None,
},
],
args: [
ParameterWithDefault {
range: 16..17,
parameter: Parameter {
range: 16..17,
name: Identifier {
id: "c",
range: 16..17,
},
annotation: None,
},
default: None,
},
],
vararg: None,
kwonlyargs: [
ParameterWithDefault {
range: 22..23,
parameter: Parameter {
range: 22..23,
name: Identifier {
id: "d",
range: 22..23,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 25..26,
parameter: Parameter {
range: 25..26,
name: Identifier {
id: "e",
range: 25..26,
},
annotation: None,
},
default: None,
},
],
kwarg: None,
},
),
body: NumberLiteral(
ExprNumberLiteral {
range: 28..29,
value: Int(
0,
),
},
),
},
),
},
),
],
)

View file

@ -1,105 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
Expr(
StmtExpr {
range: 0..32,
value: Lambda(
ExprLambda {
range: 0..32,
parameters: Some(
Parameters {
range: 7..29,
posonlyargs: [
ParameterWithDefault {
range: 7..8,
parameter: Parameter {
range: 7..8,
name: Identifier {
id: "a",
range: 7..8,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 10..11,
parameter: Parameter {
range: 10..11,
name: Identifier {
id: "b",
range: 10..11,
},
annotation: None,
},
default: None,
},
],
args: [
ParameterWithDefault {
range: 16..17,
parameter: Parameter {
range: 16..17,
name: Identifier {
id: "c",
range: 16..17,
},
annotation: None,
},
default: None,
},
],
vararg: Some(
Parameter {
range: 19..21,
name: Identifier {
id: "d",
range: 20..21,
},
annotation: None,
},
),
kwonlyargs: [
ParameterWithDefault {
range: 23..24,
parameter: Parameter {
range: 23..24,
name: Identifier {
id: "e",
range: 23..24,
},
annotation: None,
},
default: None,
},
],
kwarg: Some(
Parameter {
range: 26..29,
name: Identifier {
id: "f",
range: 28..29,
},
annotation: None,
},
),
},
),
body: NumberLiteral(
ExprNumberLiteral {
range: 31..32,
value: Int(
0,
),
},
),
},
),
},
),
],
)

View file

@ -1,73 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
Expr(
StmtExpr {
range: 0..17,
value: Lambda(
ExprLambda {
range: 0..17,
parameters: Some(
Parameters {
range: 7..14,
posonlyargs: [],
args: [
ParameterWithDefault {
range: 7..8,
parameter: Parameter {
range: 7..8,
name: Identifier {
id: "a",
range: 7..8,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 10..11,
parameter: Parameter {
range: 10..11,
name: Identifier {
id: "b",
range: 10..11,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 13..14,
parameter: Parameter {
range: 13..14,
name: Identifier {
id: "c",
range: 13..14,
},
annotation: None,
},
default: None,
},
],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
),
body: NumberLiteral(
ExprNumberLiteral {
range: 16..17,
value: Int(
1,
),
},
),
},
),
},
),
],
)

View file

@ -1,92 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
Expr(
StmtExpr {
range: 0..26,
value: Lambda(
ExprLambda {
range: 0..26,
parameters: Some(
Parameters {
range: 7..23,
posonlyargs: [
ParameterWithDefault {
range: 7..8,
parameter: Parameter {
range: 7..8,
name: Identifier {
id: "a",
range: 7..8,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 10..14,
parameter: Parameter {
range: 10..11,
name: Identifier {
id: "b",
range: 10..11,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 12..14,
value: Int(
20,
),
},
),
),
},
],
args: [
ParameterWithDefault {
range: 19..23,
parameter: Parameter {
range: 19..20,
name: Identifier {
id: "c",
range: 19..20,
},
annotation: None,
},
default: Some(
NumberLiteral(
ExprNumberLiteral {
range: 21..23,
value: Int(
30,
),
},
),
),
},
],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
),
body: NumberLiteral(
ExprNumberLiteral {
range: 25..26,
value: Int(
1,
),
},
),
},
),
},
),
],
)

View file

@ -1,74 +0,0 @@
---
source: crates/ruff_python_parser/src/function.rs
expression: parse_ast
---
Ok(
[
Expr(
StmtExpr {
range: 0..20,
value: Lambda(
ExprLambda {
range: 0..20,
parameters: Some(
Parameters {
range: 7..17,
posonlyargs: [
ParameterWithDefault {
range: 7..8,
parameter: Parameter {
range: 7..8,
name: Identifier {
id: "a",
range: 7..8,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 10..11,
parameter: Parameter {
range: 10..11,
name: Identifier {
id: "b",
range: 10..11,
},
annotation: None,
},
default: None,
},
],
args: [
ParameterWithDefault {
range: 16..17,
parameter: Parameter {
range: 16..17,
name: Identifier {
id: "c",
range: 16..17,
},
annotation: None,
},
default: None,
},
],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
),
body: NumberLiteral(
ExprNumberLiteral {
range: 19..20,
value: Int(
1,
),
},
),
},
),
},
),
],
)

View file

@ -1,33 +0,0 @@
---
source: crates/ruff_python_parser/src/invalid.rs
expression: ast
---
Ok(
[
Expr(
StmtExpr {
range: 0..8,
value: Named(
ExprNamed {
range: 1..7,
target: Name(
ExprName {
range: 1..2,
id: "x",
ctx: Store,
},
),
value: NumberLiteral(
ExprNumberLiteral {
range: 6..7,
value: Int(
5,
),
},
),
},
),
},
),
],
)

View file

@ -1,40 +0,0 @@
---
source: crates/ruff_python_parser/src/invalid.rs
expression: ast
---
Ok(
[
Assign(
StmtAssign {
range: 0..12,
targets: [
Attribute(
ExprAttribute {
range: 0..7,
value: Name(
ExprName {
range: 0..3,
id: "foo",
ctx: Load,
},
),
attr: Identifier {
id: "bar",
range: 4..7,
},
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 10..12,
value: Int(
42,
),
},
),
},
),
],
)

View file

@ -1,51 +0,0 @@
---
source: crates/ruff_python_parser/src/invalid.rs
expression: ast
---
Ok(
[
Assign(
StmtAssign {
range: 0..12,
targets: [
Attribute(
ExprAttribute {
range: 0..7,
value: StringLiteral(
ExprStringLiteral {
range: 0..5,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 0..5,
value: "foo",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
},
},
),
attr: Identifier {
id: "y",
range: 6..7,
},
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 10..12,
value: Int(
42,
),
},
),
},
),
],
)

View file

@ -1,20 +0,0 @@
---
source: crates/ruff_python_parser/src/invalid.rs
expression: ast
---
Ok(
Module(
ModModule {
range: 0..9,
body: [
IpyEscapeCommand(
StmtIpyEscapeCommand {
range: 0..9,
kind: Shell,
value: "foo = 42",
},
),
],
},
),
)

View file

@ -1,76 +0,0 @@
---
source: crates/ruff_python_parser/src/invalid.rs
expression: ast
---
Ok(
[
Assign(
StmtAssign {
range: 0..21,
targets: [
List(
ExprList {
range: 0..9,
elts: [
Name(
ExprName {
range: 1..2,
id: "x",
ctx: Store,
},
),
Name(
ExprName {
range: 4..5,
id: "y",
ctx: Store,
},
),
Name(
ExprName {
range: 7..8,
id: "z",
ctx: Store,
},
),
],
ctx: Store,
},
),
],
value: List(
ExprList {
range: 12..21,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 13..14,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 16..17,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 19..20,
value: Int(
3,
),
},
),
],
ctx: Load,
},
),
},
),
],
)

View file

@ -1,30 +0,0 @@
---
source: crates/ruff_python_parser/src/invalid.rs
expression: ast
---
Ok(
[
Assign(
StmtAssign {
range: 0..8,
targets: [
Name(
ExprName {
range: 0..3,
id: "foo",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 6..8,
value: Int(
42,
),
},
),
},
),
],
)

View file

@ -1,70 +0,0 @@
---
source: crates/ruff_python_parser/src/invalid.rs
expression: ast
---
Ok(
[
Assign(
StmtAssign {
range: 0..13,
targets: [
Subscript(
ExprSubscript {
range: 0..6,
value: Name(
ExprName {
range: 0..1,
id: "x",
ctx: Load,
},
),
slice: Slice(
ExprSlice {
range: 2..5,
lower: Some(
NumberLiteral(
ExprNumberLiteral {
range: 2..3,
value: Int(
1,
),
},
),
),
upper: Some(
NumberLiteral(
ExprNumberLiteral {
range: 4..5,
value: Int(
2,
),
},
),
),
step: None,
},
),
ctx: Store,
},
),
],
value: List(
ExprList {
range: 9..13,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 10..12,
value: Int(
42,
),
},
),
],
ctx: Load,
},
),
},
),
],
)

View file

@ -1,71 +0,0 @@
---
source: crates/ruff_python_parser/src/invalid.rs
expression: ast
---
Ok(
[
Assign(
StmtAssign {
range: 0..13,
targets: [
Subscript(
ExprSubscript {
range: 0..6,
value: NumberLiteral(
ExprNumberLiteral {
range: 0..1,
value: Int(
5,
),
},
),
slice: Slice(
ExprSlice {
range: 2..5,
lower: Some(
NumberLiteral(
ExprNumberLiteral {
range: 2..3,
value: Int(
1,
),
},
),
),
upper: Some(
NumberLiteral(
ExprNumberLiteral {
range: 4..5,
value: Int(
2,
),
},
),
),
step: None,
},
),
ctx: Store,
},
),
],
value: List(
ExprList {
range: 9..13,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 10..12,
value: Int(
42,
),
},
),
],
ctx: Load,
},
),
},
),
],
)

View file

@ -1,36 +0,0 @@
---
source: crates/ruff_python_parser/src/invalid.rs
expression: ast
---
Ok(
[
Assign(
StmtAssign {
range: 0..9,
targets: [
Starred(
ExprStarred {
range: 0..4,
value: Name(
ExprName {
range: 1..4,
id: "foo",
ctx: Store,
},
),
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 7..9,
value: Int(
42,
),
},
),
},
),
],
)

View file

@ -1,44 +0,0 @@
---
source: crates/ruff_python_parser/src/invalid.rs
expression: ast
---
Ok(
[
Assign(
StmtAssign {
range: 0..9,
targets: [
Subscript(
ExprSubscript {
range: 0..4,
value: Name(
ExprName {
range: 0..1,
id: "x",
ctx: Load,
},
),
slice: NumberLiteral(
ExprNumberLiteral {
range: 2..3,
value: Int(
0,
),
},
),
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 7..9,
value: Int(
42,
),
},
),
},
),
],
)

View file

@ -1,45 +0,0 @@
---
source: crates/ruff_python_parser/src/invalid.rs
expression: ast
---
Ok(
[
Assign(
StmtAssign {
range: 0..9,
targets: [
Subscript(
ExprSubscript {
range: 0..4,
value: NumberLiteral(
ExprNumberLiteral {
range: 0..1,
value: Int(
5,
),
},
),
slice: NumberLiteral(
ExprNumberLiteral {
range: 2..3,
value: Int(
0,
),
},
),
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 7..9,
value: Int(
42,
),
},
),
},
),
],
)

View file

@ -1,78 +0,0 @@
---
source: crates/ruff_python_parser/src/invalid.rs
expression: ast
---
Ok(
[
Assign(
StmtAssign {
range: 0..21,
targets: [
Tuple(
ExprTuple {
range: 0..9,
elts: [
Name(
ExprName {
range: 1..2,
id: "x",
ctx: Store,
},
),
Name(
ExprName {
range: 4..5,
id: "y",
ctx: Store,
},
),
Name(
ExprName {
range: 7..8,
id: "z",
ctx: Store,
},
),
],
ctx: Store,
parenthesized: true,
},
),
],
value: Tuple(
ExprTuple {
range: 12..21,
elts: [
NumberLiteral(
ExprNumberLiteral {
range: 13..14,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 16..17,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 19..20,
value: Int(
3,
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
},
),
],
)

View file

@ -5,8 +5,8 @@ expression: tokens
Err(
LexicalError {
error: OtherError(
"Invalid Token",
"Invalid decimal integer literal",
),
location: 0,
location: 0..85,
},
)

View file

@ -5,8 +5,8 @@ expression: tokens
Err(
LexicalError {
error: OtherError(
"Invalid Token",
"Invalid decimal integer literal",
),
location: 0,
location: 0..3,
},
)

View file

@ -48,7 +48,7 @@ expression: tokens
Err(
LexicalError {
error: IndentationError,
location: 20,
location: 18..20,
},
),
Ok(

View file

@ -1,75 +0,0 @@
---
source: crates/ruff_python_parser/src/parser.rs
expression: parse_ast
---
[
FunctionDef(
StmtFunctionDef {
range: 0..34,
is_async: false,
decorator_list: [
Decorator {
range: 0..13,
expression: Name(
ExprName {
range: 1..13,
id: "my_decorator",
ctx: Load,
},
),
},
],
name: Identifier {
id: "test",
range: 18..22,
},
type_params: None,
parameters: Parameters {
range: 22..24,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Pass(
StmtPass {
range: 30..34,
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 36..73,
decorator_list: [
Decorator {
range: 36..52,
expression: Name(
ExprName {
range: 37..52,
id: "class_decorator",
ctx: Load,
},
),
},
],
name: Identifier {
id: "Abcd",
range: 59..63,
},
type_params: None,
arguments: None,
body: [
Pass(
StmtPass {
range: 69..73,
},
),
],
},
),
]

View file

@ -1,97 +0,0 @@
---
source: crates/ruff_python_parser/src/parser.rs
expression: parse_ast
---
Dict(
ExprDict {
range: 0..25,
keys: [
Some(
StringLiteral(
ExprStringLiteral {
range: 1..4,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 1..4,
value: "a",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
},
},
),
),
None,
Some(
StringLiteral(
ExprStringLiteral {
range: 16..19,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 16..19,
value: "d",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
},
},
),
),
],
values: [
StringLiteral(
ExprStringLiteral {
range: 6..9,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 6..9,
value: "b",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
},
},
),
Name(
ExprName {
range: 13..14,
id: "c",
ctx: Load,
},
),
StringLiteral(
ExprStringLiteral {
range: 21..24,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 21..24,
value: "e",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
},
},
),
],
},
)

View file

@ -1,322 +0,0 @@
---
source: crates/ruff_python_parser/src/parser.rs
expression: parse_ast
---
[
Expr(
StmtExpr {
range: 0..29,
value: FString(
ExprFString {
range: 0..29,
value: FStringValue {
inner: Concatenated(
[
Literal(
StringLiteral {
range: 0..6,
value: "foo",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Unicode,
triple_quoted: false,
},
},
),
FString(
FString {
range: 7..15,
elements: [
Expression(
FStringExpressionElement {
range: 9..14,
expression: Name(
ExprName {
range: 10..13,
id: "bar",
ctx: Load,
},
),
debug_text: None,
conversion: None,
format_spec: None,
},
),
],
flags: FStringFlags {
quote_style: Double,
prefix: Regular,
triple_quoted: false,
},
},
),
Literal(
StringLiteral {
range: 16..21,
value: "baz",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
Literal(
StringLiteral {
range: 22..29,
value: " some",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
],
),
},
},
),
},
),
Expr(
StmtExpr {
range: 30..59,
value: FString(
ExprFString {
range: 30..59,
value: FStringValue {
inner: Concatenated(
[
Literal(
StringLiteral {
range: 30..35,
value: "foo",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
FString(
FString {
range: 36..44,
elements: [
Expression(
FStringExpressionElement {
range: 38..43,
expression: Name(
ExprName {
range: 39..42,
id: "bar",
ctx: Load,
},
),
debug_text: None,
conversion: None,
format_spec: None,
},
),
],
flags: FStringFlags {
quote_style: Double,
prefix: Regular,
triple_quoted: false,
},
},
),
Literal(
StringLiteral {
range: 45..51,
value: "baz",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Unicode,
triple_quoted: false,
},
},
),
Literal(
StringLiteral {
range: 52..59,
value: " some",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
],
),
},
},
),
},
),
Expr(
StmtExpr {
range: 60..89,
value: FString(
ExprFString {
range: 60..89,
value: FStringValue {
inner: Concatenated(
[
Literal(
StringLiteral {
range: 60..65,
value: "foo",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
FString(
FString {
range: 66..74,
elements: [
Expression(
FStringExpressionElement {
range: 68..73,
expression: Name(
ExprName {
range: 69..72,
id: "bar",
ctx: Load,
},
),
debug_text: None,
conversion: None,
format_spec: None,
},
),
],
flags: FStringFlags {
quote_style: Double,
prefix: Regular,
triple_quoted: false,
},
},
),
Literal(
StringLiteral {
range: 75..80,
value: "baz",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
Literal(
StringLiteral {
range: 81..89,
value: " some",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Unicode,
triple_quoted: false,
},
},
),
],
),
},
},
),
},
),
Expr(
StmtExpr {
range: 90..128,
value: FString(
ExprFString {
range: 90..128,
value: FStringValue {
inner: Concatenated(
[
Literal(
StringLiteral {
range: 90..96,
value: "foo",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Unicode,
triple_quoted: false,
},
},
),
FString(
FString {
range: 97..116,
elements: [
Literal(
FStringLiteralElement {
range: 99..103,
value: "bar ",
},
),
Expression(
FStringExpressionElement {
range: 103..108,
expression: Name(
ExprName {
range: 104..107,
id: "baz",
ctx: Load,
},
),
debug_text: None,
conversion: None,
format_spec: None,
},
),
Literal(
FStringLiteralElement {
range: 108..115,
value: " really",
},
),
],
flags: FStringFlags {
quote_style: Double,
prefix: Regular,
triple_quoted: false,
},
},
),
Literal(
StringLiteral {
range: 117..123,
value: "bar",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Unicode,
triple_quoted: false,
},
},
),
Literal(
StringLiteral {
range: 124..128,
value: "no",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
],
),
},
},
),
},
),
]

View file

@ -1,175 +0,0 @@
---
source: crates/ruff_python_parser/src/parser.rs
expression: parse_ast
---
Call(
ExprCall {
range: 0..141,
func: Attribute(
ExprAttribute {
range: 0..8,
value: StringLiteral(
ExprStringLiteral {
range: 0..3,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 0..3,
value: " ",
flags: StringLiteralFlags {
quote_style: Single,
prefix: Empty,
triple_quoted: false,
},
},
),
},
},
),
attr: Identifier {
id: "join",
range: 4..8,
},
ctx: Load,
},
),
arguments: Arguments {
range: 8..141,
args: [
Generator(
ExprGenerator {
range: 14..139,
elt: Name(
ExprName {
range: 14..17,
id: "sql",
ctx: Load,
},
),
generators: [
Comprehension {
range: 22..139,
target: Name(
ExprName {
range: 26..29,
id: "sql",
ctx: Store,
},
),
iter: Tuple(
ExprTuple {
range: 33..139,
elts: [
If(
ExprIf {
range: 43..80,
test: Name(
ExprName {
range: 65..70,
id: "limit",
ctx: Load,
},
),
body: BinOp(
ExprBinOp {
range: 43..61,
left: StringLiteral(
ExprStringLiteral {
range: 43..53,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 43..53,
value: "LIMIT %d",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
},
},
),
op: Mod,
right: Name(
ExprName {
range: 56..61,
id: "limit",
ctx: Load,
},
),
},
),
orelse: NoneLiteral(
ExprNoneLiteral {
range: 76..80,
},
),
},
),
If(
ExprIf {
range: 90..132,
test: Name(
ExprName {
range: 116..122,
id: "offset",
ctx: Load,
},
),
body: BinOp(
ExprBinOp {
range: 91..111,
left: StringLiteral(
ExprStringLiteral {
range: 91..102,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 91..102,
value: "OFFSET %d",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
},
},
),
op: Mod,
right: Name(
ExprName {
range: 105..111,
id: "offset",
ctx: Load,
},
),
},
),
orelse: NoneLiteral(
ExprNoneLiteral {
range: 128..132,
},
),
},
),
],
ctx: Load,
parenthesized: true,
},
),
ifs: [],
is_async: false,
},
],
parenthesized: false,
},
),
],
keywords: [],
},
},
)

View file

@ -1,624 +0,0 @@
---
source: crates/ruff_python_parser/src/parser.rs
expression: parse_ast
---
[
Match(
StmtMatch {
range: 1..73,
subject: Dict(
ExprDict {
range: 7..18,
keys: [
Some(
StringLiteral(
ExprStringLiteral {
range: 8..14,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 8..14,
value: "test",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
},
},
),
),
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 16..17,
value: Int(
1,
),
},
),
],
},
),
cases: [
MatchCase {
range: 24..73,
pattern: MatchMapping(
PatternMatchMapping {
range: 29..52,
keys: [],
patterns: [],
rest: Some(
Identifier {
id: "rest",
range: 41..45,
},
),
},
),
guard: None,
body: [
Expr(
StmtExpr {
range: 62..73,
value: Call(
ExprCall {
range: 62..73,
func: Name(
ExprName {
range: 62..67,
id: "print",
ctx: Load,
},
),
arguments: Arguments {
range: 67..73,
args: [
Name(
ExprName {
range: 68..72,
id: "rest",
ctx: Load,
},
),
],
keywords: [],
},
},
),
},
),
],
},
],
},
),
Match(
StmtMatch {
range: 74..177,
subject: Dict(
ExprDict {
range: 80..97,
keys: [
Some(
StringLiteral(
ExprStringLiteral {
range: 81..88,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 81..88,
value: "label",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
},
},
),
),
],
values: [
StringLiteral(
ExprStringLiteral {
range: 90..96,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 90..96,
value: "test",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
},
},
),
],
},
),
cases: [
MatchCase {
range: 103..177,
pattern: MatchMapping(
PatternMatchMapping {
range: 108..155,
keys: [
StringLiteral(
ExprStringLiteral {
range: 118..125,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 118..125,
value: "label",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
},
},
),
],
patterns: [
MatchAs(
PatternMatchAs {
range: 127..148,
pattern: Some(
MatchOr(
PatternMatchOr {
range: 127..139,
patterns: [
MatchClass(
PatternMatchClass {
range: 127..132,
cls: Name(
ExprName {
range: 127..130,
id: "str",
ctx: Load,
},
),
arguments: PatternArguments {
range: 130..132,
patterns: [],
keywords: [],
},
},
),
MatchSingleton(
PatternMatchSingleton {
range: 135..139,
value: None,
},
),
],
},
),
),
name: Some(
Identifier {
id: "label",
range: 143..148,
},
),
},
),
],
rest: None,
},
),
guard: None,
body: [
Expr(
StmtExpr {
range: 165..177,
value: Call(
ExprCall {
range: 165..177,
func: Name(
ExprName {
range: 165..170,
id: "print",
ctx: Load,
},
),
arguments: Arguments {
range: 170..177,
args: [
Name(
ExprName {
range: 171..176,
id: "label",
ctx: Load,
},
),
],
keywords: [],
},
},
),
},
),
],
},
],
},
),
Match(
StmtMatch {
range: 178..218,
subject: Name(
ExprName {
range: 184..185,
id: "x",
ctx: Load,
},
),
cases: [
MatchCase {
range: 191..218,
pattern: MatchSequence(
PatternMatchSequence {
range: 196..203,
patterns: [
MatchValue(
PatternMatchValue {
range: 197..198,
value: NumberLiteral(
ExprNumberLiteral {
range: 197..198,
value: Int(
0,
),
},
),
},
),
MatchValue(
PatternMatchValue {
range: 200..201,
value: NumberLiteral(
ExprNumberLiteral {
range: 200..201,
value: Int(
1,
),
},
),
},
),
],
},
),
guard: None,
body: [
Assign(
StmtAssign {
range: 213..218,
targets: [
Name(
ExprName {
range: 213..214,
id: "y",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 217..218,
value: Int(
0,
),
},
),
},
),
],
},
],
},
),
Match(
StmtMatch {
range: 219..259,
subject: Name(
ExprName {
range: 225..226,
id: "x",
ctx: Load,
},
),
cases: [
MatchCase {
range: 232..259,
pattern: MatchSequence(
PatternMatchSequence {
range: 237..244,
patterns: [
MatchValue(
PatternMatchValue {
range: 238..239,
value: NumberLiteral(
ExprNumberLiteral {
range: 238..239,
value: Int(
0,
),
},
),
},
),
MatchValue(
PatternMatchValue {
range: 241..242,
value: NumberLiteral(
ExprNumberLiteral {
range: 241..242,
value: Int(
1,
),
},
),
},
),
],
},
),
guard: None,
body: [
Assign(
StmtAssign {
range: 254..259,
targets: [
Name(
ExprName {
range: 254..255,
id: "y",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 258..259,
value: Int(
0,
),
},
),
},
),
],
},
],
},
),
Match(
StmtMatch {
range: 260..297,
subject: Name(
ExprName {
range: 266..267,
id: "x",
ctx: Load,
},
),
cases: [
MatchCase {
range: 273..297,
pattern: MatchSequence(
PatternMatchSequence {
range: 278..282,
patterns: [
MatchValue(
PatternMatchValue {
range: 279..280,
value: NumberLiteral(
ExprNumberLiteral {
range: 279..280,
value: Int(
0,
),
},
),
},
),
],
},
),
guard: None,
body: [
Assign(
StmtAssign {
range: 292..297,
targets: [
Name(
ExprName {
range: 292..293,
id: "y",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 296..297,
value: Int(
0,
),
},
),
},
),
],
},
],
},
),
Match(
StmtMatch {
range: 298..332,
subject: Tuple(
ExprTuple {
range: 304..306,
elts: [
Name(
ExprName {
range: 304..305,
id: "x",
ctx: Load,
},
),
],
ctx: Load,
parenthesized: false,
},
),
cases: [
MatchCase {
range: 312..332,
pattern: MatchAs(
PatternMatchAs {
range: 317..318,
pattern: None,
name: Some(
Identifier {
id: "z",
range: 317..318,
},
),
},
),
guard: None,
body: [
Pass(
StmtPass {
range: 328..332,
},
),
],
},
],
},
),
Match(
StmtMatch {
range: 333..369,
subject: Tuple(
ExprTuple {
range: 339..343,
elts: [
Name(
ExprName {
range: 339..340,
id: "x",
ctx: Load,
},
),
Name(
ExprName {
range: 342..343,
id: "y",
ctx: Load,
},
),
],
ctx: Load,
parenthesized: false,
},
),
cases: [
MatchCase {
range: 349..369,
pattern: MatchAs(
PatternMatchAs {
range: 354..355,
pattern: None,
name: Some(
Identifier {
id: "z",
range: 354..355,
},
),
},
),
guard: None,
body: [
Pass(
StmtPass {
range: 365..369,
},
),
],
},
],
},
),
Match(
StmtMatch {
range: 370..407,
subject: Tuple(
ExprTuple {
range: 376..381,
elts: [
Name(
ExprName {
range: 376..377,
id: "x",
ctx: Load,
},
),
Name(
ExprName {
range: 379..380,
id: "y",
ctx: Load,
},
),
],
ctx: Load,
parenthesized: false,
},
),
cases: [
MatchCase {
range: 387..407,
pattern: MatchAs(
PatternMatchAs {
range: 392..393,
pattern: None,
name: Some(
Identifier {
id: "z",
range: 392..393,
},
),
},
),
guard: None,
body: [
Pass(
StmtPass {
range: 403..407,
},
),
],
},
],
},
),
]

View file

@ -1,833 +0,0 @@
---
source: crates/ruff_python_parser/src/parser.rs
expression: parse_suite(source).unwrap()
---
[
Expr(
StmtExpr {
range: 2..17,
value: Tuple(
ExprTuple {
range: 2..17,
elts: [
BinOp(
ExprBinOp {
range: 2..14,
left: BinOp(
ExprBinOp {
range: 2..10,
left: Name(
ExprName {
range: 2..7,
id: "match",
ctx: Load,
},
),
op: Mult,
right: Name(
ExprName {
range: 9..10,
id: "a",
ctx: Load,
},
),
},
),
op: Add,
right: Name(
ExprName {
range: 13..14,
id: "b",
ctx: Load,
},
),
},
),
Name(
ExprName {
range: 16..17,
id: "c",
ctx: Load,
},
),
],
ctx: Load,
parenthesized: false,
},
),
},
),
Expr(
StmtExpr {
range: 43..60,
value: Tuple(
ExprTuple {
range: 43..60,
elts: [
BinOp(
ExprBinOp {
range: 43..57,
left: Name(
ExprName {
range: 43..48,
id: "match",
ctx: Load,
},
),
op: Mult,
right: BinOp(
ExprBinOp {
range: 51..56,
left: Name(
ExprName {
range: 51..52,
id: "a",
ctx: Load,
},
),
op: Add,
right: Name(
ExprName {
range: 55..56,
id: "b",
ctx: Load,
},
),
},
),
},
),
Name(
ExprName {
range: 59..60,
id: "c",
ctx: Load,
},
),
],
ctx: Load,
parenthesized: false,
},
),
},
),
Expr(
StmtExpr {
range: 86..103,
value: Call(
ExprCall {
range: 86..103,
func: Name(
ExprName {
range: 86..91,
id: "match",
ctx: Load,
},
),
arguments: Arguments {
range: 92..103,
args: [
Starred(
ExprStarred {
range: 93..99,
value: BinOp(
ExprBinOp {
range: 94..99,
left: Name(
ExprName {
range: 94..95,
id: "a",
ctx: Load,
},
),
op: Add,
right: Name(
ExprName {
range: 98..99,
id: "b",
ctx: Load,
},
),
},
),
ctx: Load,
},
),
Name(
ExprName {
range: 101..102,
id: "c",
ctx: Load,
},
),
],
keywords: [],
},
},
),
},
),
Expr(
StmtExpr {
range: 130..146,
value: BinOp(
ExprBinOp {
range: 130..146,
left: BinOp(
ExprBinOp {
range: 130..142,
left: Name(
ExprName {
range: 130..135,
id: "match",
ctx: Load,
},
),
op: Sub,
right: BinOp(
ExprBinOp {
range: 137..142,
left: Name(
ExprName {
range: 137..138,
id: "a",
ctx: Load,
},
),
op: Mult,
right: Name(
ExprName {
range: 141..142,
id: "b",
ctx: Load,
},
),
},
),
},
),
op: Add,
right: Name(
ExprName {
range: 145..146,
id: "c",
ctx: Load,
},
),
},
),
},
),
Expr(
StmtExpr {
range: 173..191,
value: BinOp(
ExprBinOp {
range: 173..191,
left: BinOp(
ExprBinOp {
range: 173..187,
left: Name(
ExprName {
range: 173..178,
id: "match",
ctx: Load,
},
),
op: Sub,
right: BinOp(
ExprBinOp {
range: 181..186,
left: Name(
ExprName {
range: 181..182,
id: "a",
ctx: Load,
},
),
op: Mult,
right: Name(
ExprName {
range: 185..186,
id: "b",
ctx: Load,
},
),
},
),
},
),
op: Add,
right: Name(
ExprName {
range: 190..191,
id: "c",
ctx: Load,
},
),
},
),
},
),
Expr(
StmtExpr {
range: 218..236,
value: BinOp(
ExprBinOp {
range: 218..236,
left: BinOp(
ExprBinOp {
range: 218..232,
left: Call(
ExprCall {
range: 218..228,
func: Name(
ExprName {
range: 218..223,
id: "match",
ctx: Load,
},
),
arguments: Arguments {
range: 224..228,
args: [
UnaryOp(
ExprUnaryOp {
range: 225..227,
op: USub,
operand: Name(
ExprName {
range: 226..227,
id: "a",
ctx: Load,
},
),
},
),
],
keywords: [],
},
},
),
op: Mult,
right: Name(
ExprName {
range: 231..232,
id: "b",
ctx: Load,
},
),
},
),
op: Add,
right: Name(
ExprName {
range: 235..236,
id: "c",
ctx: Load,
},
),
},
),
},
),
Expr(
StmtExpr {
range: 264..274,
value: Attribute(
ExprAttribute {
range: 264..274,
value: Call(
ExprCall {
range: 264..272,
func: Name(
ExprName {
range: 264..269,
id: "match",
ctx: Load,
},
),
arguments: Arguments {
range: 270..272,
args: [],
keywords: [],
},
},
),
attr: Identifier {
id: "a",
range: 273..274,
},
ctx: Load,
},
),
},
),
Expr(
StmtExpr {
range: 291..303,
value: Attribute(
ExprAttribute {
range: 291..303,
value: Call(
ExprCall {
range: 291..301,
func: Name(
ExprName {
range: 291..296,
id: "match",
ctx: Load,
},
),
arguments: Arguments {
range: 297..301,
args: [
Tuple(
ExprTuple {
range: 298..300,
elts: [],
ctx: Load,
parenthesized: true,
},
),
],
keywords: [],
},
},
),
attr: Identifier {
id: "a",
range: 302..303,
},
ctx: Load,
},
),
},
),
Expr(
StmtExpr {
range: 322..335,
value: Attribute(
ExprAttribute {
range: 322..335,
value: Call(
ExprCall {
range: 322..333,
func: Name(
ExprName {
range: 322..327,
id: "match",
ctx: Load,
},
),
arguments: Arguments {
range: 328..333,
args: [
Tuple(
ExprTuple {
range: 329..331,
elts: [],
ctx: Load,
parenthesized: true,
},
),
],
keywords: [],
},
},
),
attr: Identifier {
id: "a",
range: 334..335,
},
ctx: Load,
},
),
},
),
Expr(
StmtExpr {
range: 354..365,
value: Attribute(
ExprAttribute {
range: 354..365,
value: Subscript(
ExprSubscript {
range: 354..363,
value: Name(
ExprName {
range: 354..359,
id: "match",
ctx: Load,
},
),
slice: Name(
ExprName {
range: 361..362,
id: "a",
ctx: Load,
},
),
ctx: Load,
},
),
attr: Identifier {
id: "b",
range: 364..365,
},
ctx: Load,
},
),
},
),
Expr(
StmtExpr {
range: 383..395,
value: Attribute(
ExprAttribute {
range: 383..395,
value: Subscript(
ExprSubscript {
range: 383..393,
value: Name(
ExprName {
range: 383..388,
id: "match",
ctx: Load,
},
),
slice: Tuple(
ExprTuple {
range: 390..392,
elts: [
Name(
ExprName {
range: 390..391,
id: "a",
ctx: Load,
},
),
],
ctx: Load,
parenthesized: false,
},
),
ctx: Load,
},
),
attr: Identifier {
id: "b",
range: 394..395,
},
ctx: Load,
},
),
},
),
Expr(
StmtExpr {
range: 436..450,
value: Attribute(
ExprAttribute {
range: 436..450,
value: Subscript(
ExprSubscript {
range: 436..448,
value: Name(
ExprName {
range: 436..441,
id: "match",
ctx: Load,
},
),
slice: Tuple(
ExprTuple {
range: 443..447,
elts: [
Name(
ExprName {
range: 444..445,
id: "a",
ctx: Load,
},
),
],
ctx: Load,
parenthesized: true,
},
),
ctx: Load,
},
),
attr: Identifier {
id: "b",
range: 449..450,
},
ctx: Load,
},
),
},
),
Expr(
StmtExpr {
range: 471..488,
value: Subscript(
ExprSubscript {
range: 471..488,
value: Call(
ExprCall {
range: 471..478,
func: Name(
ExprName {
range: 471..476,
id: "match",
ctx: Load,
},
),
arguments: Arguments {
range: 476..478,
args: [],
keywords: [],
},
},
),
slice: Slice(
ExprSlice {
range: 479..487,
lower: Some(
Name(
ExprName {
range: 479..480,
id: "a",
ctx: Load,
},
),
),
upper: Some(
Name(
ExprName {
range: 486..487,
id: "b",
ctx: Load,
},
),
),
step: None,
},
),
ctx: Load,
},
),
},
),
If(
StmtIf {
range: 508..527,
test: Named(
ExprNamed {
range: 511..521,
target: Name(
ExprName {
range: 511..516,
id: "match",
ctx: Store,
},
),
value: NumberLiteral(
ExprNumberLiteral {
range: 520..521,
value: Int(
1,
),
},
),
},
),
body: [
Pass(
StmtPass {
range: 523..527,
},
),
],
elif_else_clauses: [],
},
),
Match(
StmtMatch {
range: 528..582,
subject: Name(
ExprName {
range: 534..539,
id: "match",
ctx: Load,
},
),
cases: [
MatchCase {
range: 545..557,
pattern: MatchValue(
PatternMatchValue {
range: 550..551,
value: NumberLiteral(
ExprNumberLiteral {
range: 550..551,
value: Int(
1,
),
},
),
},
),
guard: None,
body: [
Pass(
StmtPass {
range: 553..557,
},
),
],
},
MatchCase {
range: 562..582,
pattern: MatchValue(
PatternMatchValue {
range: 567..568,
value: NumberLiteral(
ExprNumberLiteral {
range: 567..568,
value: Int(
2,
),
},
),
},
),
guard: None,
body: [
Pass(
StmtPass {
range: 578..582,
},
),
],
},
],
},
),
Assign(
StmtAssign {
range: 583..619,
targets: [
Name(
ExprName {
range: 583..588,
id: "match",
ctx: Store,
},
),
],
value: Lambda(
ExprLambda {
range: 591..619,
parameters: Some(
Parameters {
range: 598..603,
posonlyargs: [],
args: [
ParameterWithDefault {
range: 598..603,
parameter: Parameter {
range: 598..603,
name: Identifier {
id: "query",
range: 598..603,
},
annotation: None,
},
default: None,
},
],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
),
body: Compare(
ExprCompare {
range: 605..619,
left: Name(
ExprName {
range: 605..610,
id: "query",
ctx: Load,
},
),
ops: [
Eq,
],
comparators: [
Name(
ExprName {
range: 614..619,
id: "event",
ctx: Load,
},
),
],
},
),
},
),
},
),
Expr(
StmtExpr {
range: 620..636,
value: Call(
ExprCall {
range: 620..636,
func: Name(
ExprName {
range: 620..625,
id: "print",
ctx: Load,
},
),
arguments: Arguments {
range: 625..636,
args: [
Call(
ExprCall {
range: 626..635,
func: Name(
ExprName {
range: 626..631,
id: "match",
ctx: Load,
},
),
arguments: Arguments {
range: 631..635,
args: [
NumberLiteral(
ExprNumberLiteral {
range: 632..634,
value: Int(
12,
),
},
),
],
keywords: [],
},
},
),
],
keywords: [],
},
},
),
},
),
]

View file

@ -1,36 +0,0 @@
---
source: crates/ruff_python_parser/src/parser.rs
expression: parse_ast
---
Named(
ExprNamed {
range: 1..15,
target: Name(
ExprName {
range: 1..2,
id: "x",
ctx: Store,
},
),
value: BinOp(
ExprBinOp {
range: 8..13,
left: Name(
ExprName {
range: 8..9,
id: "y",
ctx: Load,
},
),
op: Mult,
right: Name(
ExprName {
range: 12..13,
id: "z",
ctx: Load,
},
),
},
),
},
)

View file

@ -1,404 +0,0 @@
---
source: crates/ruff_python_parser/src/parser.rs
expression: "parse_suite(source, \"<test>\").unwrap()"
---
[
Assign(
StmtAssign {
range: 0..13,
targets: [
Name(
ExprName {
range: 0..1,
id: "x",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 4..13,
value: Int(
123456789,
),
},
),
},
),
Assign(
StmtAssign {
range: 14..24,
targets: [
Name(
ExprName {
range: 14..15,
id: "x",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 18..24,
value: Int(
123456,
),
},
),
},
),
Assign(
StmtAssign {
range: 25..31,
targets: [
Name(
ExprName {
range: 25..26,
id: "x",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 29..31,
value: Float(
0.1,
),
},
),
},
),
Assign(
StmtAssign {
range: 32..38,
targets: [
Name(
ExprName {
range: 32..33,
id: "x",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 36..38,
value: Float(
1.0,
),
},
),
},
),
Assign(
StmtAssign {
range: 39..47,
targets: [
Name(
ExprName {
range: 39..40,
id: "x",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 43..47,
value: Float(
10.0,
),
},
),
},
),
Assign(
StmtAssign {
range: 48..56,
targets: [
Name(
ExprName {
range: 48..49,
id: "x",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 52..56,
value: Float(
0.1,
),
},
),
},
),
Assign(
StmtAssign {
range: 57..73,
targets: [
Name(
ExprName {
range: 57..58,
id: "x",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 61..73,
value: Float(
1.00000001,
),
},
),
},
),
Assign(
StmtAssign {
range: 74..97,
targets: [
Name(
ExprName {
range: 74..75,
id: "x",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 78..97,
value: Float(
123456789.12345679,
),
},
),
},
),
Assign(
StmtAssign {
range: 98..131,
targets: [
Name(
ExprName {
range: 98..99,
id: "x",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 102..131,
value: Float(
inf,
),
},
),
},
),
Assign(
StmtAssign {
range: 132..155,
targets: [
Name(
ExprName {
range: 132..133,
id: "x",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 136..155,
value: Float(
inf,
),
},
),
},
),
Assign(
StmtAssign {
range: 156..170,
targets: [
Name(
ExprName {
range: 156..157,
id: "x",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 160..170,
value: Complex {
real: 0.0,
imag: 123456789.0,
},
},
),
},
),
Assign(
StmtAssign {
range: 171..195,
targets: [
Name(
ExprName {
range: 171..172,
id: "x",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 175..195,
value: Complex {
real: 0.0,
imag: 123456789.12345679,
},
},
),
},
),
Assign(
StmtAssign {
range: 196..207,
targets: [
Name(
ExprName {
range: 196..197,
id: "x",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 200..207,
value: Int(
727756,
),
},
),
},
),
Assign(
StmtAssign {
range: 208..218,
targets: [
Name(
ExprName {
range: 208..209,
id: "x",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 212..218,
value: Int(
11,
),
},
),
},
),
Assign(
StmtAssign {
range: 219..228,
targets: [
Name(
ExprName {
range: 219..220,
id: "x",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 223..228,
value: Int(
511,
),
},
),
},
),
Assign(
StmtAssign {
range: 229..244,
targets: [
Name(
ExprName {
range: 229..230,
id: "x",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 233..244,
value: Float(
6e-9,
),
},
),
},
),
Assign(
StmtAssign {
range: 245..254,
targets: [
Name(
ExprName {
range: 245..246,
id: "x",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 249..254,
value: Int(
10000,
),
},
),
},
),
Assign(
StmtAssign {
range: 255..265,
targets: [
Name(
ExprName {
range: 255..256,
id: "x",
ctx: Store,
},
),
],
value: NumberLiteral(
ExprNumberLiteral {
range: 259..265,
value: Int(
133333,
),
},
),
},
),
]

View file

@ -1,663 +0,0 @@
---
source: crates/ruff_python_parser/src/parser.rs
expression: "parse_suite(source, \"<test>\").unwrap()"
---
[
Assign(
StmtAssign {
range: 0..19,
targets: [
Name(
ExprName {
range: 0..1,
id: "x",
ctx: Store,
},
),
],
value: Call(
ExprCall {
range: 4..19,
func: Attribute(
ExprAttribute {
range: 4..17,
value: NumberLiteral(
ExprNumberLiteral {
range: 4..6,
value: Float(
0.1,
),
},
),
attr: Identifier {
id: "is_integer",
range: 7..17,
},
ctx: Load,
},
),
arguments: Arguments {
range: 17..19,
args: [],
keywords: [],
},
},
),
},
),
Assign(
StmtAssign {
range: 20..32,
targets: [
Name(
ExprName {
range: 20..21,
id: "x",
ctx: Store,
},
),
],
value: Attribute(
ExprAttribute {
range: 24..32,
value: NumberLiteral(
ExprNumberLiteral {
range: 24..26,
value: Float(
1.0,
),
},
),
attr: Identifier {
id: "imag",
range: 28..32,
},
ctx: Load,
},
),
},
),
Assign(
StmtAssign {
range: 33..46,
targets: [
Name(
ExprName {
range: 33..34,
id: "x",
ctx: Store,
},
),
],
value: Attribute(
ExprAttribute {
range: 37..46,
value: NumberLiteral(
ExprNumberLiteral {
range: 37..41,
value: Float(
10.0,
),
},
),
attr: Identifier {
id: "imag",
range: 42..46,
},
ctx: Load,
},
),
},
),
Assign(
StmtAssign {
range: 47..60,
targets: [
Name(
ExprName {
range: 47..48,
id: "x",
ctx: Store,
},
),
],
value: Attribute(
ExprAttribute {
range: 51..60,
value: NumberLiteral(
ExprNumberLiteral {
range: 51..55,
value: Float(
0.1,
),
},
),
attr: Identifier {
id: "real",
range: 56..60,
},
ctx: Load,
},
),
},
),
Assign(
StmtAssign {
range: 61..90,
targets: [
Name(
ExprName {
range: 61..62,
id: "x",
ctx: Store,
},
),
],
value: Call(
ExprCall {
range: 65..90,
func: Attribute(
ExprAttribute {
range: 65..88,
value: NumberLiteral(
ExprNumberLiteral {
range: 65..84,
value: Float(
123456789.12345679,
),
},
),
attr: Identifier {
id: "hex",
range: 85..88,
},
ctx: Load,
},
),
arguments: Arguments {
range: 88..90,
args: [],
keywords: [],
},
},
),
},
),
Assign(
StmtAssign {
range: 91..130,
targets: [
Name(
ExprName {
range: 91..92,
id: "x",
ctx: Store,
},
),
],
value: Attribute(
ExprAttribute {
range: 95..130,
value: NumberLiteral(
ExprNumberLiteral {
range: 95..124,
value: Float(
inf,
),
},
),
attr: Identifier {
id: "real",
range: 126..130,
},
ctx: Load,
},
),
},
),
Assign(
StmtAssign {
range: 131..167,
targets: [
Name(
ExprName {
range: 131..132,
id: "x",
ctx: Store,
},
),
],
value: Call(
ExprCall {
range: 135..167,
func: Attribute(
ExprAttribute {
range: 135..165,
value: NumberLiteral(
ExprNumberLiteral {
range: 135..154,
value: Float(
inf,
),
},
),
attr: Identifier {
id: "conjugate",
range: 156..165,
},
ctx: Load,
},
),
arguments: Arguments {
range: 165..167,
args: [],
keywords: [],
},
},
),
},
),
Assign(
StmtAssign {
range: 168..187,
targets: [
Name(
ExprName {
range: 168..169,
id: "x",
ctx: Store,
},
),
],
value: Attribute(
ExprAttribute {
range: 172..187,
value: NumberLiteral(
ExprNumberLiteral {
range: 172..182,
value: Complex {
real: 0.0,
imag: 123456789.0,
},
},
),
attr: Identifier {
id: "real",
range: 183..187,
},
ctx: Load,
},
),
},
),
Assign(
StmtAssign {
range: 188..241,
targets: [
Name(
ExprName {
range: 188..189,
id: "x",
ctx: Store,
},
),
],
value: Call(
ExprCall {
range: 192..241,
func: Attribute(
ExprAttribute {
range: 192..220,
value: NumberLiteral(
ExprNumberLiteral {
range: 192..212,
value: Complex {
real: 0.0,
imag: 123456789.12345679,
},
},
),
attr: Identifier {
id: "__add__",
range: 213..220,
},
ctx: Load,
},
),
arguments: Arguments {
range: 220..241,
args: [
Call(
ExprCall {
range: 221..240,
func: Attribute(
ExprAttribute {
range: 221..238,
value: NumberLiteral(
ExprNumberLiteral {
range: 221..227,
value: Int(
11,
),
},
),
attr: Identifier {
id: "bit_length",
range: 228..238,
},
ctx: Load,
},
),
arguments: Arguments {
range: 238..240,
args: [],
keywords: [],
},
},
),
],
keywords: [],
},
},
),
},
),
Assign(
StmtAssign {
range: 242..265,
targets: [
Name(
ExprName {
range: 242..243,
id: "x",
ctx: Store,
},
),
],
value: Call(
ExprCall {
range: 246..265,
func: Attribute(
ExprAttribute {
range: 246..263,
value: NumberLiteral(
ExprNumberLiteral {
range: 246..253,
value: Int(
727756,
),
},
),
attr: Identifier {
id: "conjugate",
range: 254..263,
},
ctx: Load,
},
),
arguments: Arguments {
range: 263..265,
args: [],
keywords: [],
},
},
),
},
),
Assign(
StmtAssign {
range: 266..289,
targets: [
Name(
ExprName {
range: 266..267,
id: "x",
ctx: Store,
},
),
],
value: Call(
ExprCall {
range: 270..289,
func: Attribute(
ExprAttribute {
range: 270..287,
value: NumberLiteral(
ExprNumberLiteral {
range: 270..276,
value: Int(
11,
),
},
),
attr: Identifier {
id: "conjugate",
range: 278..287,
},
ctx: Load,
},
),
arguments: Arguments {
range: 287..289,
args: [],
keywords: [],
},
},
),
},
),
Assign(
StmtAssign {
range: 290..305,
targets: [
Name(
ExprName {
range: 290..291,
id: "x",
ctx: Store,
},
),
],
value: Attribute(
ExprAttribute {
range: 294..305,
value: NumberLiteral(
ExprNumberLiteral {
range: 294..299,
value: Int(
511,
),
},
),
attr: Identifier {
id: "real",
range: 301..305,
},
ctx: Load,
},
),
},
),
Assign(
StmtAssign {
range: 306..329,
targets: [
Name(
ExprName {
range: 306..307,
id: "x",
ctx: Store,
},
),
],
value: Call(
ExprCall {
range: 310..329,
func: Attribute(
ExprAttribute {
range: 310..327,
value: NumberLiteral(
ExprNumberLiteral {
range: 310..321,
value: Float(
6e-9,
),
},
),
attr: Identifier {
id: "hex",
range: 324..327,
},
ctx: Load,
},
),
arguments: Arguments {
range: 327..329,
args: [],
keywords: [],
},
},
),
},
),
Assign(
StmtAssign {
range: 330..344,
targets: [
Name(
ExprName {
range: 330..331,
id: "x",
ctx: Store,
},
),
],
value: UnaryOp(
ExprUnaryOp {
range: 334..344,
op: USub,
operand: NumberLiteral(
ExprNumberLiteral {
range: 335..344,
value: Complex {
real: 0.0,
imag: 100.0,
},
},
),
},
),
},
),
If(
StmtIf {
range: 346..366,
test: Attribute(
ExprAttribute {
range: 349..357,
value: NumberLiteral(
ExprNumberLiteral {
range: 349..351,
value: Int(
10,
),
},
),
attr: Identifier {
id: "real",
range: 353..357,
},
ctx: Load,
},
),
body: [
Expr(
StmtExpr {
range: 363..366,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 363..366,
},
),
},
),
],
elif_else_clauses: [],
},
),
Assign(
StmtAssign {
range: 368..379,
targets: [
Name(
ExprName {
range: 368..369,
id: "y",
ctx: Store,
},
),
],
value: Subscript(
ExprSubscript {
range: 372..379,
value: NumberLiteral(
ExprNumberLiteral {
range: 372..375,
value: Int(
100,
),
},
),
slice: Name(
ExprName {
range: 376..378,
id: "no",
ctx: Load,
},
),
ctx: Load,
},
),
},
),
Assign(
StmtAssign {
range: 380..391,
targets: [
Name(
ExprName {
range: 380..381,
id: "y",
ctx: Store,
},
),
],
value: Call(
ExprCall {
range: 384..391,
func: NumberLiteral(
ExprNumberLiteral {
range: 384..387,
value: Int(
100,
),
},
),
arguments: Arguments {
range: 387..391,
args: [
Name(
ExprName {
range: 388..390,
id: "no",
ctx: Load,
},
),
],
keywords: [],
},
},
),
},
),
]

View file

@ -1,678 +0,0 @@
---
source: crates/ruff_python_parser/src/parser.rs
expression: parse_suite(source).unwrap()
---
[
With(
StmtWith {
range: 0..21,
is_async: false,
items: [
WithItem {
range: 6..9,
context_expr: Name(
ExprName {
range: 7..8,
id: "a",
ctx: Load,
},
),
optional_vars: None,
},
WithItem {
range: 11..14,
context_expr: Name(
ExprName {
range: 12..13,
id: "b",
ctx: Load,
},
),
optional_vars: None,
},
],
body: [
Pass(
StmtPass {
range: 17..21,
},
),
],
},
),
With(
StmtWith {
range: 22..56,
is_async: false,
items: [
WithItem {
range: 28..31,
context_expr: Name(
ExprName {
range: 29..30,
id: "a",
ctx: Load,
},
),
optional_vars: None,
},
WithItem {
range: 33..36,
context_expr: Name(
ExprName {
range: 34..35,
id: "b",
ctx: Load,
},
),
optional_vars: None,
},
WithItem {
range: 38..44,
context_expr: Name(
ExprName {
range: 38..39,
id: "c",
ctx: Load,
},
),
optional_vars: Some(
Name(
ExprName {
range: 43..44,
id: "d",
ctx: Store,
},
),
),
},
WithItem {
range: 46..49,
context_expr: Name(
ExprName {
range: 47..48,
id: "e",
ctx: Load,
},
),
optional_vars: None,
},
],
body: [
Pass(
StmtPass {
range: 52..56,
},
),
],
},
),
With(
StmtWith {
range: 57..74,
is_async: false,
items: [
WithItem {
range: 63..64,
context_expr: Name(
ExprName {
range: 63..64,
id: "a",
ctx: Load,
},
),
optional_vars: None,
},
WithItem {
range: 66..67,
context_expr: Name(
ExprName {
range: 66..67,
id: "b",
ctx: Load,
},
),
optional_vars: None,
},
],
body: [
Pass(
StmtPass {
range: 70..74,
},
),
],
},
),
With(
StmtWith {
range: 75..97,
is_async: false,
items: [
WithItem {
range: 80..91,
context_expr: Tuple(
ExprTuple {
range: 80..86,
elts: [
Name(
ExprName {
range: 81..82,
id: "a",
ctx: Load,
},
),
Name(
ExprName {
range: 84..85,
id: "b",
ctx: Load,
},
),
],
ctx: Load,
parenthesized: true,
},
),
optional_vars: Some(
Name(
ExprName {
range: 90..91,
id: "c",
ctx: Store,
},
),
),
},
],
body: [
Pass(
StmtPass {
range: 93..97,
},
),
],
},
),
With(
StmtWith {
range: 98..122,
is_async: false,
items: [
WithItem {
range: 104..115,
context_expr: Tuple(
ExprTuple {
range: 104..110,
elts: [
Name(
ExprName {
range: 105..106,
id: "a",
ctx: Load,
},
),
Name(
ExprName {
range: 108..109,
id: "b",
ctx: Load,
},
),
],
ctx: Load,
parenthesized: true,
},
),
optional_vars: Some(
Name(
ExprName {
range: 114..115,
id: "c",
ctx: Store,
},
),
),
},
],
body: [
Pass(
StmtPass {
range: 118..122,
},
),
],
},
),
With(
StmtWith {
range: 123..142,
is_async: false,
items: [
WithItem {
range: 129..135,
context_expr: Name(
ExprName {
range: 129..130,
id: "a",
ctx: Load,
},
),
optional_vars: Some(
Name(
ExprName {
range: 134..135,
id: "b",
ctx: Store,
},
),
),
},
],
body: [
Pass(
StmtPass {
range: 138..142,
},
),
],
},
),
With(
StmtWith {
range: 143..157,
is_async: false,
items: [
WithItem {
range: 149..150,
context_expr: Name(
ExprName {
range: 149..150,
id: "a",
ctx: Load,
},
),
optional_vars: None,
},
],
body: [
Pass(
StmtPass {
range: 153..157,
},
),
],
},
),
With(
StmtWith {
range: 158..177,
is_async: false,
items: [
WithItem {
range: 164..170,
context_expr: Named(
ExprNamed {
range: 164..170,
target: Name(
ExprName {
range: 164..165,
id: "a",
ctx: Store,
},
),
value: NumberLiteral(
ExprNumberLiteral {
range: 169..170,
value: Int(
0,
),
},
),
},
),
optional_vars: None,
},
],
body: [
Pass(
StmtPass {
range: 173..177,
},
),
],
},
),
With(
StmtWith {
range: 178..202,
is_async: false,
items: [
WithItem {
range: 183..196,
context_expr: Named(
ExprNamed {
range: 184..190,
target: Name(
ExprName {
range: 184..185,
id: "a",
ctx: Store,
},
),
value: NumberLiteral(
ExprNumberLiteral {
range: 189..190,
value: Int(
0,
),
},
),
},
),
optional_vars: Some(
Name(
ExprName {
range: 195..196,
id: "x",
ctx: Store,
},
),
),
},
],
body: [
Pass(
StmtPass {
range: 198..202,
},
),
],
},
),
With(
StmtWith {
range: 203..219,
is_async: false,
items: [
WithItem {
range: 209..212,
context_expr: Name(
ExprName {
range: 210..211,
id: "a",
ctx: Load,
},
),
optional_vars: None,
},
],
body: [
Pass(
StmtPass {
range: 215..219,
},
),
],
},
),
With(
StmtWith {
range: 220..241,
is_async: false,
items: [
WithItem {
range: 226..234,
context_expr: Named(
ExprNamed {
range: 227..233,
target: Name(
ExprName {
range: 227..228,
id: "a",
ctx: Store,
},
),
value: NumberLiteral(
ExprNumberLiteral {
range: 232..233,
value: Int(
0,
),
},
),
},
),
optional_vars: None,
},
],
body: [
Pass(
StmtPass {
range: 237..241,
},
),
],
},
),
With(
StmtWith {
range: 242..271,
is_async: false,
items: [
WithItem {
range: 248..254,
context_expr: Name(
ExprName {
range: 248..249,
id: "a",
ctx: Load,
},
),
optional_vars: Some(
Name(
ExprName {
range: 253..254,
id: "b",
ctx: Store,
},
),
),
},
WithItem {
range: 256..264,
context_expr: Named(
ExprNamed {
range: 257..263,
target: Name(
ExprName {
range: 257..258,
id: "a",
ctx: Store,
},
),
value: NumberLiteral(
ExprNumberLiteral {
range: 262..263,
value: Int(
0,
),
},
),
},
),
optional_vars: None,
},
],
body: [
Pass(
StmtPass {
range: 267..271,
},
),
],
},
),
With(
StmtWith {
range: 272..296,
is_async: false,
items: [
WithItem {
range: 278..279,
context_expr: Name(
ExprName {
range: 278..279,
id: "a",
ctx: Load,
},
),
optional_vars: None,
},
WithItem {
range: 281..289,
context_expr: Named(
ExprNamed {
range: 282..288,
target: Name(
ExprName {
range: 282..283,
id: "a",
ctx: Store,
},
),
value: NumberLiteral(
ExprNumberLiteral {
range: 287..288,
value: Int(
0,
),
},
),
},
),
optional_vars: None,
},
],
body: [
Pass(
StmtPass {
range: 292..296,
},
),
],
},
),
With(
StmtWith {
range: 297..315,
is_async: false,
items: [
WithItem {
range: 303..308,
context_expr: Yield(
ExprYield {
range: 303..308,
value: None,
},
),
optional_vars: None,
},
],
body: [
Pass(
StmtPass {
range: 311..315,
},
),
],
},
),
With(
StmtWith {
range: 316..341,
is_async: false,
items: [
WithItem {
range: 322..334,
context_expr: YieldFrom(
ExprYieldFrom {
range: 322..334,
value: Name(
ExprName {
range: 333..334,
id: "a",
ctx: Load,
},
),
},
),
optional_vars: None,
},
],
body: [
Pass(
StmtPass {
range: 337..341,
},
),
],
},
),
With(
StmtWith {
range: 342..362,
is_async: false,
items: [
WithItem {
range: 348..355,
context_expr: Yield(
ExprYield {
range: 349..354,
value: None,
},
),
optional_vars: None,
},
],
body: [
Pass(
StmtPass {
range: 358..362,
},
),
],
},
),
With(
StmtWith {
range: 363..390,
is_async: false,
items: [
WithItem {
range: 369..383,
context_expr: YieldFrom(
ExprYieldFrom {
range: 370..382,
value: Name(
ExprName {
range: 381..382,
id: "a",
ctx: Load,
},
),
},
),
optional_vars: None,
},
],
body: [
Pass(
StmtPass {
range: 386..390,
},
),
],
},
),
]

View file

@ -1,26 +0,0 @@
---
source: crates/ruff_python_parser/src/parser.rs
expression: parse_ast
---
BoolOp(
ExprBoolOp {
range: 0..7,
op: And,
values: [
Name(
ExprName {
range: 0..1,
id: "x",
ctx: Load,
},
),
Name(
ExprName {
range: 6..7,
id: "y",
ctx: Load,
},
),
],
},
)

View file

@ -1,26 +0,0 @@
---
source: crates/ruff_python_parser/src/parser.rs
expression: parse_ast
---
BoolOp(
ExprBoolOp {
range: 0..6,
op: Or,
values: [
Name(
ExprName {
range: 0..1,
id: "x",
ctx: Load,
},
),
Name(
ExprName {
range: 5..6,
id: "y",
ctx: Load,
},
),
],
},
)

View file

@ -1,154 +0,0 @@
---
source: crates/ruff_python_parser/src/parser.rs
expression: parse_suite(source).unwrap()
---
[
ClassDef(
StmtClassDef {
range: 0..98,
decorator_list: [],
name: Identifier {
id: "Foo",
range: 6..9,
},
type_params: None,
arguments: Some(
Arguments {
range: 9..15,
args: [
Name(
ExprName {
range: 10..11,
id: "A",
ctx: Load,
},
),
Name(
ExprName {
range: 13..14,
id: "B",
ctx: Load,
},
),
],
keywords: [],
},
),
body: [
FunctionDef(
StmtFunctionDef {
range: 18..44,
is_async: false,
decorator_list: [],
name: Identifier {
id: "__init__",
range: 22..30,
},
type_params: None,
parameters: Parameters {
range: 30..36,
posonlyargs: [],
args: [
ParameterWithDefault {
range: 31..35,
parameter: Parameter {
range: 31..35,
name: Identifier {
id: "self",
range: 31..35,
},
annotation: None,
},
default: None,
},
],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Pass(
StmtPass {
range: 40..44,
},
),
],
},
),
FunctionDef(
StmtFunctionDef {
range: 46..98,
is_async: false,
decorator_list: [],
name: Identifier {
id: "method_with_default",
range: 50..69,
},
type_params: None,
parameters: Parameters {
range: 69..90,
posonlyargs: [],
args: [
ParameterWithDefault {
range: 70..74,
parameter: Parameter {
range: 70..74,
name: Identifier {
id: "self",
range: 70..74,
},
annotation: None,
},
default: None,
},
ParameterWithDefault {
range: 76..89,
parameter: Parameter {
range: 76..79,
name: Identifier {
id: "arg",
range: 76..79,
},
annotation: None,
},
default: Some(
StringLiteral(
ExprStringLiteral {
range: 80..89,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 80..89,
value: "default",
flags: StringLiteralFlags {
quote_style: Single,
prefix: Empty,
triple_quoted: false,
},
},
),
},
},
),
),
},
],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
returns: None,
body: [
Pass(
StmtPass {
range: 94..98,
},
),
],
},
),
],
},
),
]

View file

@ -1,455 +0,0 @@
---
source: crates/ruff_python_parser/src/parser.rs
expression: parse_suite(source).unwrap()
---
[
ClassDef(
StmtClassDef {
range: 10..29,
decorator_list: [],
name: Identifier {
id: "Foo",
range: 16..19,
},
type_params: Some(
TypeParams {
range: 19..22,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 20..21,
name: Identifier {
id: "T",
range: 20..21,
},
bound: None,
},
),
],
},
),
arguments: Some(
Arguments {
range: 22..24,
args: [],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 26..29,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 26..29,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 52..76,
decorator_list: [],
name: Identifier {
id: "Foo",
range: 58..61,
},
type_params: Some(
TypeParams {
range: 61..69,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 62..68,
name: Identifier {
id: "T",
range: 62..63,
},
bound: Some(
Name(
ExprName {
range: 65..68,
id: "str",
ctx: Load,
},
),
),
},
),
],
},
),
arguments: Some(
Arguments {
range: 69..71,
args: [],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 73..76,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 73..76,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 105..138,
decorator_list: [],
name: Identifier {
id: "Foo",
range: 111..114,
},
type_params: Some(
TypeParams {
range: 114..131,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 115..130,
name: Identifier {
id: "T",
range: 115..116,
},
bound: Some(
Tuple(
ExprTuple {
range: 118..130,
elts: [
Name(
ExprName {
range: 119..122,
id: "str",
ctx: Load,
},
),
Name(
ExprName {
range: 124..129,
id: "bytes",
ctx: Load,
},
),
],
ctx: Load,
parenthesized: true,
},
),
),
},
),
],
},
),
arguments: Some(
Arguments {
range: 131..133,
args: [],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 135..138,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 135..138,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 159..181,
decorator_list: [],
name: Identifier {
id: "Foo",
range: 165..168,
},
type_params: Some(
TypeParams {
range: 168..174,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 169..170,
name: Identifier {
id: "T",
range: 169..170,
},
bound: None,
},
),
TypeVar(
TypeParamTypeVar {
range: 172..173,
name: Identifier {
id: "U",
range: 172..173,
},
bound: None,
},
),
],
},
),
arguments: Some(
Arguments {
range: 174..176,
args: [],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 178..181,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 178..181,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 200..223,
decorator_list: [],
name: Identifier {
id: "Foo",
range: 206..209,
},
type_params: Some(
TypeParams {
range: 209..216,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 210..211,
name: Identifier {
id: "T",
range: 210..211,
},
bound: None,
},
),
TypeVar(
TypeParamTypeVar {
range: 213..214,
name: Identifier {
id: "U",
range: 213..214,
},
bound: None,
},
),
],
},
),
arguments: Some(
Arguments {
range: 216..218,
args: [],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 220..223,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 220..223,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 240..261,
decorator_list: [],
name: Identifier {
id: "Foo",
range: 246..249,
},
type_params: Some(
TypeParams {
range: 249..254,
type_params: [
TypeVarTuple(
TypeParamTypeVarTuple {
range: 250..253,
name: Identifier {
id: "Ts",
range: 251..253,
},
},
),
],
},
),
arguments: Some(
Arguments {
range: 254..256,
args: [],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 258..261,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 258..261,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 275..296,
decorator_list: [],
name: Identifier {
id: "Foo",
range: 281..284,
},
type_params: Some(
TypeParams {
range: 284..289,
type_params: [
ParamSpec(
TypeParamParamSpec {
range: 285..288,
name: Identifier {
id: "P",
range: 287..288,
},
},
),
],
},
),
arguments: Some(
Arguments {
range: 289..291,
args: [],
keywords: [],
},
),
body: [
Expr(
StmtExpr {
range: 293..296,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 293..296,
},
),
},
),
],
},
),
ClassDef(
StmtClassDef {
range: 312..351,
decorator_list: [],
name: Identifier {
id: "Foo",
range: 318..321,
},
type_params: Some(
TypeParams {
range: 321..341,
type_params: [
TypeVar(
TypeParamTypeVar {
range: 322..323,
name: Identifier {
id: "X",
range: 322..323,
},
bound: None,
},
),
TypeVar(
TypeParamTypeVar {
range: 325..331,
name: Identifier {
id: "Y",
range: 325..326,
},
bound: Some(
Name(
ExprName {
range: 328..331,
id: "str",
ctx: Load,
},
),
),
},
),
TypeVarTuple(
TypeParamTypeVarTuple {
range: 333..335,
name: Identifier {
id: "U",
range: 334..335,
},
},
),
ParamSpec(
TypeParamParamSpec {
range: 337..340,
name: Identifier {
id: "P",
range: 339..340,
},
},
),
],
},
),
arguments: Some(
Arguments {
range: 341..343,
args: [],
keywords: [],
},
),
body: [
Pass(
StmtPass {
range: 347..351,
},
),
],
},
),
]

View file

@ -1,44 +0,0 @@
---
source: crates/ruff_python_parser/src/parser.rs
expression: parse_ast
---
DictComp(
ExprDictComp {
range: 0..19,
key: Name(
ExprName {
range: 1..3,
id: "x1",
ctx: Load,
},
),
value: Name(
ExprName {
range: 5..7,
id: "x2",
ctx: Load,
},
),
generators: [
Comprehension {
range: 8..18,
target: Name(
ExprName {
range: 12..13,
id: "y",
ctx: Store,
},
),
iter: Name(
ExprName {
range: 17..18,
id: "z",
ctx: Load,
},
),
ifs: [],
is_async: false,
},
],
},
)

View file

@ -1,123 +0,0 @@
---
source: crates/ruff_python_parser/src/parser.rs
expression: parse_ast
---
ListComp(
ExprListComp {
range: 0..48,
elt: Name(
ExprName {
range: 1..2,
id: "x",
ctx: Load,
},
),
generators: [
Comprehension {
range: 3..17,
target: Tuple(
ExprTuple {
range: 7..12,
elts: [
Name(
ExprName {
range: 7..8,
id: "y",
ctx: Store,
},
),
Name(
ExprName {
range: 10..12,
id: "y2",
ctx: Store,
},
),
],
ctx: Store,
parenthesized: false,
},
),
iter: Name(
ExprName {
range: 16..17,
id: "z",
ctx: Load,
},
),
ifs: [],
is_async: false,
},
Comprehension {
range: 18..47,
target: Name(
ExprName {
range: 22..23,
id: "a",
ctx: Store,
},
),
iter: Name(
ExprName {
range: 27..28,
id: "b",
ctx: Load,
},
),
ifs: [
Compare(
ExprCompare {
range: 32..37,
left: Name(
ExprName {
range: 32..33,
id: "a",
ctx: Load,
},
),
ops: [
Lt,
],
comparators: [
NumberLiteral(
ExprNumberLiteral {
range: 36..37,
value: Int(
5,
),
},
),
],
},
),
Compare(
ExprCompare {
range: 41..47,
left: Name(
ExprName {
range: 41..42,
id: "a",
ctx: Load,
},
),
ops: [
Gt,
],
comparators: [
NumberLiteral(
ExprNumberLiteral {
range: 45..47,
value: Int(
10,
),
},
),
],
},
),
],
is_async: false,
},
],
},
)

View file

@ -1,5 +0,0 @@
---
source: crates/ruff_python_parser/src/parser.rs
expression: parse_ast
---
[]

View file

@ -1,38 +0,0 @@
---
source: crates/ruff_python_parser/src/parser.rs
expression: parse_ast
---
[
Expr(
StmtExpr {
range: 0..14,
value: FString(
ExprFString {
range: 0..14,
value: FStringValue {
inner: Single(
FString(
FString {
range: 0..14,
elements: [
Literal(
FStringLiteralElement {
range: 2..13,
value: "Hello world",
},
),
],
flags: FStringFlags {
quote_style: Single,
prefix: Regular,
triple_quoted: false,
},
},
),
),
},
},
),
},
),
]

Some files were not shown because too many files have changed in this diff Show more