mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-12 21:36:47 +00:00

## Summary This PR adds a basic README for the `ruff_python_parser` crate and updates the CONTRIBUTING docs with the fuzzer and benchmark section. Additionally, it also updates some inline documentation within the parser crate and splits the `parse_program` function into `parse_single_expression` and `parse_module` which will be called by matching against the `Mode`. This PR doesn't go into too much internal detail around the parser logic due to the following reasons: 1. Where should the docs go? Should it be as a module docs in `lib.rs` or in README? 2. The parser is still evolving and could include a lot of refactors with the future work (feedback loop and improved error recovery and resilience) --------- Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
47 lines
1.9 KiB
Rust
47 lines
1.9 KiB
Rust
//! This module takes care of parsing a type annotation.
|
|
|
|
use anyhow::Result;
|
|
|
|
use ruff_python_ast::relocate::relocate_expr;
|
|
use ruff_python_ast::{str, Expr};
|
|
use ruff_text_size::{TextLen, TextRange};
|
|
|
|
use crate::{parse_expression, parse_expression_starts_at};
|
|
|
|
#[derive(is_macro::Is, Copy, Clone, Debug)]
|
|
pub enum AnnotationKind {
|
|
/// The annotation is defined as part a simple string literal,
|
|
/// e.g. `x: "List[int]" = []`. Annotations within simple literals
|
|
/// can be accurately located. For example, we can underline specific
|
|
/// expressions within the annotation and apply automatic fixes, which is
|
|
/// not possible for complex string literals.
|
|
Simple,
|
|
/// The annotation is defined as part of a complex string literal, such as
|
|
/// a literal containing an implicit concatenation or escaped characters,
|
|
/// e.g. `x: "List" "[int]" = []`. These are comparatively rare, but valid.
|
|
Complex,
|
|
}
|
|
|
|
/// Parse a type annotation from a string.
|
|
pub fn parse_type_annotation(
|
|
value: &str,
|
|
range: TextRange,
|
|
source: &str,
|
|
) -> Result<(Expr, AnnotationKind)> {
|
|
let expression = &source[range];
|
|
|
|
if str::raw_contents(expression).is_some_and(|body| body == value) {
|
|
// The annotation is considered "simple" if and only if the raw representation (e.g.,
|
|
// `List[int]` within "List[int]") exactly matches the parsed representation. This
|
|
// isn't the case, e.g., for implicit concatenations, or for annotations that contain
|
|
// escaped quotes.
|
|
let leading_quote = str::leading_quote(expression).unwrap();
|
|
let expr = parse_expression_starts_at(value, range.start() + leading_quote.text_len())?;
|
|
Ok((expr, AnnotationKind::Simple))
|
|
} else {
|
|
// Otherwise, consider this a "complex" annotation.
|
|
let mut expr = parse_expression(value)?;
|
|
relocate_expr(&mut expr, range);
|
|
Ok((expr, AnnotationKind::Complex))
|
|
}
|
|
}
|