mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-09 05:08:05 +00:00
Start detecting version-related syntax errors in the parser (#16090)
## Summary This PR builds on the changes in #16220 to pass a target Python version to the parser. It also adds the `Parser::unsupported_syntax_errors` field, which collects version-related syntax errors while parsing. These syntax errors are then turned into `Message`s in ruff (in preview mode). This PR only detects one syntax error (`match` statement before Python 3.10), but it has been pretty quick to extend to several other simple errors (see #16308 for example). ## Test Plan The current tests are CLI tests in the linter crate, but these could be supplemented with inline parser tests after #16357. I also tested the display of these syntax errors in VS Code:   --------- Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
This commit is contained in:
parent
b39a4ad01d
commit
78806361fd
14 changed files with 356 additions and 37 deletions
|
@ -67,7 +67,10 @@
|
|||
use std::iter::FusedIterator;
|
||||
use std::ops::Deref;
|
||||
|
||||
pub use crate::error::{FStringErrorType, LexicalErrorType, ParseError, ParseErrorType};
|
||||
pub use crate::error::{
|
||||
FStringErrorType, LexicalErrorType, ParseError, ParseErrorType, UnsupportedSyntaxError,
|
||||
UnsupportedSyntaxErrorKind,
|
||||
};
|
||||
pub use crate::parser::ParseOptions;
|
||||
pub use crate::token::{Token, TokenKind};
|
||||
|
||||
|
@ -305,6 +308,7 @@ pub struct Parsed<T> {
|
|||
syntax: T,
|
||||
tokens: Tokens,
|
||||
errors: Vec<ParseError>,
|
||||
unsupported_syntax_errors: Vec<UnsupportedSyntaxError>,
|
||||
}
|
||||
|
||||
impl<T> Parsed<T> {
|
||||
|
@ -323,6 +327,11 @@ impl<T> Parsed<T> {
|
|||
&self.errors
|
||||
}
|
||||
|
||||
/// Returns a list of version-related syntax errors found during parsing.
|
||||
pub fn unsupported_syntax_errors(&self) -> &[UnsupportedSyntaxError] {
|
||||
&self.unsupported_syntax_errors
|
||||
}
|
||||
|
||||
/// Consumes the [`Parsed`] output and returns the contained syntax node.
|
||||
pub fn into_syntax(self) -> T {
|
||||
self.syntax
|
||||
|
@ -334,12 +343,18 @@ impl<T> Parsed<T> {
|
|||
}
|
||||
|
||||
/// Returns `true` if the parsed source code is valid i.e., it has no syntax errors.
|
||||
///
|
||||
/// Note that this does not include version-related
|
||||
/// [`unsupported_syntax_errors`](Parsed::unsupported_syntax_errors).
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.errors.is_empty()
|
||||
}
|
||||
|
||||
/// Returns the [`Parsed`] output as a [`Result`], returning [`Ok`] if it has no syntax errors,
|
||||
/// or [`Err`] containing the first [`ParseError`] encountered.
|
||||
///
|
||||
/// Note that any [`unsupported_syntax_errors`](Parsed::unsupported_syntax_errors) will not
|
||||
/// cause [`Err`] to be returned.
|
||||
pub fn as_result(&self) -> Result<&Parsed<T>, &[ParseError]> {
|
||||
if self.is_valid() {
|
||||
Ok(self)
|
||||
|
@ -350,6 +365,9 @@ impl<T> Parsed<T> {
|
|||
|
||||
/// Consumes the [`Parsed`] output and returns a [`Result`] which is [`Ok`] if it has no syntax
|
||||
/// errors, or [`Err`] containing the first [`ParseError`] encountered.
|
||||
///
|
||||
/// Note that any [`unsupported_syntax_errors`](Parsed::unsupported_syntax_errors) will not
|
||||
/// cause [`Err`] to be returned.
|
||||
pub(crate) fn into_result(self) -> Result<Parsed<T>, ParseError> {
|
||||
if self.is_valid() {
|
||||
Ok(self)
|
||||
|
@ -373,6 +391,7 @@ impl Parsed<Mod> {
|
|||
syntax: module,
|
||||
tokens: self.tokens,
|
||||
errors: self.errors,
|
||||
unsupported_syntax_errors: self.unsupported_syntax_errors,
|
||||
}),
|
||||
Mod::Expression(_) => None,
|
||||
}
|
||||
|
@ -392,6 +411,7 @@ impl Parsed<Mod> {
|
|||
syntax: expression,
|
||||
tokens: self.tokens,
|
||||
errors: self.errors,
|
||||
unsupported_syntax_errors: self.unsupported_syntax_errors,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue