rustpython_parser/
parser.rs

1//! Contains the interface to the Python parser.
2//!
3//! Functions in this module can be used to parse Python code into an [Abstract Syntax Tree]
4//! (AST) that is then transformed into bytecode.
5//!
6//! There are three ways to parse Python code corresponding to the different [`Mode`]s
7//! defined in the [`mode`] module.
8//!
9//! All functions return a [`Result`](std::result::Result) containing the parsed AST or
10//! a [`ParseError`] if parsing failed.
11//!
12//! [Abstract Syntax Tree]: https://en.wikipedia.org/wiki/Abstract_syntax_tree
13//! [`Mode`]: crate::mode
14
15use crate::{
16    ast::{self, OptionalRange, Ranged},
17    lexer::{self, LexResult, LexicalError, LexicalErrorType},
18    python,
19    text_size::TextSize,
20    token::Tok,
21    Mode,
22};
23use itertools::Itertools;
24use std::iter;
25
26use crate::{lexer::Lexer, soft_keywords::SoftKeywordTransformer, text_size::TextRange};
27pub(super) use lalrpop_util::ParseError as LalrpopError;
28
29/// Parse Python code string to implementor's type.
30///
31/// # Example
32///
33/// For example, parsing a simple function definition and a call to that function:
34///
35/// ```
36/// use rustpython_parser::{self as parser, ast, Parse};
37/// let source = r#"
38/// def foo():
39///    return 42
40///
41/// print(foo())
42/// "#;
43/// let program = ast::Suite::parse(source, "<embedded>");
44/// assert!(program.is_ok());
45/// ```
46///
47/// Parsing a single expression denoting the addition of two numbers, but this time specifying a different,
48/// somewhat silly, location:
49///
50/// ```
51/// use rustpython_parser::{self as parser, ast, Parse, text_size::TextSize};
52///
53/// let expr = ast::Expr::parse_starts_at("1 + 2", "<embedded>", TextSize::from(400));
54/// assert!(expr.is_ok());
55pub trait Parse
56where
57    Self: Sized,
58{
59    fn parse(source: &str, source_path: &str) -> Result<Self, ParseError> {
60        Self::parse_starts_at(source, source_path, TextSize::default())
61    }
62    fn parse_without_path(source: &str) -> Result<Self, ParseError> {
63        Self::parse(source, "<unknown>")
64    }
65    fn parse_starts_at(
66        source: &str,
67        source_path: &str,
68        offset: TextSize,
69    ) -> Result<Self, ParseError> {
70        let lxr = Self::lex_starts_at(source, offset);
71        #[cfg(feature = "full-lexer")]
72        let lxr =
73            lxr.filter_ok(|(tok, _)| !matches!(tok, Tok::Comment { .. } | Tok::NonLogicalNewline));
74        Self::parse_tokens(lxr, source_path)
75    }