mirror of
https://github.com/RustPython/Parser.git
synced 2025-07-21 12:05:27 +00:00
Add source_path to ParseError
This commit is contained in:
parent
a66902406f
commit
3742f9117b
5 changed files with 45 additions and 35 deletions
|
@ -124,6 +124,7 @@ impl From<FStringError> for LalrpopError<Location, Tok, LexicalError> {
|
||||||
pub struct ParseError {
|
pub struct ParseError {
|
||||||
pub error: ParseErrorType,
|
pub error: ParseErrorType,
|
||||||
pub location: Location,
|
pub location: Location,
|
||||||
|
pub source_path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
|
@ -141,21 +142,28 @@ pub enum ParseErrorType {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert `lalrpop_util::ParseError` to our internal type
|
/// Convert `lalrpop_util::ParseError` to our internal type
|
||||||
impl From<LalrpopError<Location, Tok, LexicalError>> for ParseError {
|
impl ParseError {
|
||||||
fn from(err: LalrpopError<Location, Tok, LexicalError>) -> Self {
|
pub(crate) fn from_lalrpop(
|
||||||
|
err: LalrpopError<Location, Tok, LexicalError>,
|
||||||
|
source_path: &str,
|
||||||
|
) -> Self {
|
||||||
|
let source_path = source_path.to_owned();
|
||||||
match err {
|
match err {
|
||||||
// TODO: Are there cases where this isn't an EOF?
|
// TODO: Are there cases where this isn't an EOF?
|
||||||
LalrpopError::InvalidToken { location } => ParseError {
|
LalrpopError::InvalidToken { location } => ParseError {
|
||||||
error: ParseErrorType::Eof,
|
error: ParseErrorType::Eof,
|
||||||
location,
|
location,
|
||||||
|
source_path,
|
||||||
},
|
},
|
||||||
LalrpopError::ExtraToken { token } => ParseError {
|
LalrpopError::ExtraToken { token } => ParseError {
|
||||||
error: ParseErrorType::ExtraToken(token.1),
|
error: ParseErrorType::ExtraToken(token.1),
|
||||||
location: token.0,
|
location: token.0,
|
||||||
|
source_path,
|
||||||
},
|
},
|
||||||
LalrpopError::User { error } => ParseError {
|
LalrpopError::User { error } => ParseError {
|
||||||
error: ParseErrorType::Lexical(error.error),
|
error: ParseErrorType::Lexical(error.error),
|
||||||
location: error.location,
|
location: error.location,
|
||||||
|
source_path,
|
||||||
},
|
},
|
||||||
LalrpopError::UnrecognizedToken { token, expected } => {
|
LalrpopError::UnrecognizedToken { token, expected } => {
|
||||||
// Hacky, but it's how CPython does it. See PyParser_AddToken,
|
// Hacky, but it's how CPython does it. See PyParser_AddToken,
|
||||||
|
@ -164,11 +172,13 @@ impl From<LalrpopError<Location, Tok, LexicalError>> for ParseError {
|
||||||
ParseError {
|
ParseError {
|
||||||
error: ParseErrorType::UnrecognizedToken(token.1, expected),
|
error: ParseErrorType::UnrecognizedToken(token.1, expected),
|
||||||
location: token.0,
|
location: token.0,
|
||||||
|
source_path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LalrpopError::UnrecognizedEOF { location, .. } => ParseError {
|
LalrpopError::UnrecognizedEOF { location, .. } => ParseError {
|
||||||
error: ParseErrorType::Eof,
|
error: ParseErrorType::Eof,
|
||||||
location,
|
location,
|
||||||
|
source_path,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -293,7 +293,7 @@ impl<'a> FStringParser<'a> {
|
||||||
|
|
||||||
fn parse_fstring_expr(source: &str) -> Result<Expr, ParseError> {
|
fn parse_fstring_expr(source: &str) -> Result<Expr, ParseError> {
|
||||||
let fstring_body = format!("({})", source);
|
let fstring_body = format!("({})", source);
|
||||||
parse_expression(&fstring_body)
|
parse_expression(&fstring_body, "<fstring>")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse an fstring from a string, located at a certain position in the sourcecode.
|
/// Parse an fstring from a string, located at a certain position in the sourcecode.
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
//! use rustpython_parser::{parser, ast};
|
//! use rustpython_parser::{parser, ast};
|
||||||
//!
|
//!
|
||||||
//! let python_source = "print('Hello world')";
|
//! let python_source = "print('Hello world')";
|
||||||
//! let python_ast = parser::parse_expression(python_source).unwrap();
|
//! let python_ast = parser::parse_expression(python_source, "<embedded>").unwrap();
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,8 @@ use crate::python;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// Parse a full python program, containing usually multiple lines.
|
/// Parse a full python program, containing usually multiple lines.
|
||||||
pub fn parse_program(source: &str) -> Result<ast::Suite, ParseError> {
|
pub fn parse_program(source: &str, source_path: &str) -> Result<ast::Suite, ParseError> {
|
||||||
parse(source, Mode::Module).map(|top| match top {
|
parse(source, Mode::Module, source_path).map(|top| match top {
|
||||||
ast::Mod::Module { body, .. } => body,
|
ast::Mod::Module { body, .. } => body,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
})
|
||||||
|
@ -33,7 +33,7 @@ pub fn parse_program(source: &str) -> Result<ast::Suite, ParseError> {
|
||||||
/// ```
|
/// ```
|
||||||
/// extern crate num_bigint;
|
/// extern crate num_bigint;
|
||||||
/// use rustpython_parser::{parser, ast};
|
/// use rustpython_parser::{parser, ast};
|
||||||
/// let expr = parser::parse_expression("1 + 2").unwrap();
|
/// let expr = parser::parse_expression("1 + 2", "<embedded>").unwrap();
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// expr,
|
/// expr,
|
||||||
|
@ -63,22 +63,22 @@ pub fn parse_program(source: &str) -> Result<ast::Suite, ParseError> {
|
||||||
/// );
|
/// );
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
pub fn parse_expression(source: &str) -> Result<ast::Expr, ParseError> {
|
pub fn parse_expression(source: &str, path: &str) -> Result<ast::Expr, ParseError> {
|
||||||
parse(source, Mode::Expression).map(|top| match top {
|
parse(source, Mode::Expression, path).map(|top| match top {
|
||||||
ast::Mod::Expression { body } => *body,
|
ast::Mod::Expression { body } => *body,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse a given source code
|
// Parse a given source code
|
||||||
pub fn parse(source: &str, mode: Mode) -> Result<ast::Mod, ParseError> {
|
pub fn parse(source: &str, mode: Mode, source_path: &str) -> Result<ast::Mod, ParseError> {
|
||||||
let lxr = lexer::make_tokenizer(source);
|
let lxr = lexer::make_tokenizer(source);
|
||||||
let marker_token = (Default::default(), mode.to_marker(), Default::default());
|
let marker_token = (Default::default(), mode.to_marker(), Default::default());
|
||||||
let tokenizer = iter::once(Ok(marker_token)).chain(lxr);
|
let tokenizer = iter::once(Ok(marker_token)).chain(lxr);
|
||||||
|
|
||||||
python::TopParser::new()
|
python::TopParser::new()
|
||||||
.parse(tokenizer)
|
.parse(tokenizer)
|
||||||
.map_err(ParseError::from)
|
.map_err(|e| ParseError::from_lalrpop(e, source_path))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -87,56 +87,56 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_empty() {
|
fn test_parse_empty() {
|
||||||
let parse_ast = parse_program("").unwrap();
|
let parse_ast = parse_program("", "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_string() {
|
fn test_parse_string() {
|
||||||
let source = String::from("'Hello world'");
|
let source = String::from("'Hello world'");
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_f_string() {
|
fn test_parse_f_string() {
|
||||||
let source = String::from("f'Hello world'");
|
let source = String::from("f'Hello world'");
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_print_hello() {
|
fn test_parse_print_hello() {
|
||||||
let source = String::from("print('Hello world')");
|
let source = String::from("print('Hello world')");
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_print_2() {
|
fn test_parse_print_2() {
|
||||||
let source = String::from("print('Hello world', 2)");
|
let source = String::from("print('Hello world', 2)");
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_kwargs() {
|
fn test_parse_kwargs() {
|
||||||
let source = String::from("my_func('positional', keyword=2)");
|
let source = String::from("my_func('positional', keyword=2)");
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_if_elif_else() {
|
fn test_parse_if_elif_else() {
|
||||||
let source = String::from("if 1: 10\nelif 2: 20\nelse: 30");
|
let source = String::from("if 1: 10\nelif 2: 20\nelse: 30");
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_lambda() {
|
fn test_parse_lambda() {
|
||||||
let source = "lambda x, y: x * y"; // lambda(x, y): x * y";
|
let source = "lambda x, y: x * y"; // lambda(x, y): x * y";
|
||||||
let parse_ast = parse_program(source).unwrap();
|
let parse_ast = parse_program(source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ mod tests {
|
||||||
fn test_parse_tuples() {
|
fn test_parse_tuples() {
|
||||||
let source = "a, b = 4, 5";
|
let source = "a, b = 4, 5";
|
||||||
|
|
||||||
insta::assert_debug_snapshot!(parse_program(source).unwrap());
|
insta::assert_debug_snapshot!(parse_program(source, "<test>").unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -155,48 +155,48 @@ class Foo(A, B):
|
||||||
pass
|
pass
|
||||||
def method_with_default(self, arg='default'):
|
def method_with_default(self, arg='default'):
|
||||||
pass";
|
pass";
|
||||||
insta::assert_debug_snapshot!(parse_program(source).unwrap());
|
insta::assert_debug_snapshot!(parse_program(source, "<test>").unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_dict_comprehension() {
|
fn test_parse_dict_comprehension() {
|
||||||
let source = String::from("{x1: x2 for y in z}");
|
let source = String::from("{x1: x2 for y in z}");
|
||||||
let parse_ast = parse_expression(&source).unwrap();
|
let parse_ast = parse_expression(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_list_comprehension() {
|
fn test_parse_list_comprehension() {
|
||||||
let source = String::from("[x for y in z]");
|
let source = String::from("[x for y in z]");
|
||||||
let parse_ast = parse_expression(&source).unwrap();
|
let parse_ast = parse_expression(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_double_list_comprehension() {
|
fn test_parse_double_list_comprehension() {
|
||||||
let source = String::from("[x for y, y2 in z for a in b if a < 5 if a > 10]");
|
let source = String::from("[x for y, y2 in z for a in b if a < 5 if a > 10]");
|
||||||
let parse_ast = parse_expression(&source).unwrap();
|
let parse_ast = parse_expression(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_generator_comprehension() {
|
fn test_parse_generator_comprehension() {
|
||||||
let source = String::from("(x for y in z)");
|
let source = String::from("(x for y in z)");
|
||||||
let parse_ast = parse_expression(&source).unwrap();
|
let parse_ast = parse_expression(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_named_expression_generator_comprehension() {
|
fn test_parse_named_expression_generator_comprehension() {
|
||||||
let source = String::from("(x := y + 1 for y in z)");
|
let source = String::from("(x := y + 1 for y in z)");
|
||||||
let parse_ast = parse_expression(&source).unwrap();
|
let parse_ast = parse_expression(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_if_else_generator_comprehension() {
|
fn test_parse_if_else_generator_comprehension() {
|
||||||
let source = String::from("(x if y else y for y in z)");
|
let source = String::from("(x if y else y for y in z)");
|
||||||
let parse_ast = parse_expression(&source).unwrap();
|
let parse_ast = parse_expression(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,56 +88,56 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_string_concat() {
|
fn test_parse_string_concat() {
|
||||||
let source = String::from("'Hello ' 'world'");
|
let source = String::from("'Hello ' 'world'");
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_u_string_concat_1() {
|
fn test_parse_u_string_concat_1() {
|
||||||
let source = String::from("'Hello ' u'world'");
|
let source = String::from("'Hello ' u'world'");
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_u_string_concat_2() {
|
fn test_parse_u_string_concat_2() {
|
||||||
let source = String::from("u'Hello ' 'world'");
|
let source = String::from("u'Hello ' 'world'");
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_f_string_concat_1() {
|
fn test_parse_f_string_concat_1() {
|
||||||
let source = String::from("'Hello ' f'world'");
|
let source = String::from("'Hello ' f'world'");
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_f_string_concat_2() {
|
fn test_parse_f_string_concat_2() {
|
||||||
let source = String::from("'Hello ' f'world'");
|
let source = String::from("'Hello ' f'world'");
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_f_string_concat_3() {
|
fn test_parse_f_string_concat_3() {
|
||||||
let source = String::from("'Hello ' f'world{\"!\"}'");
|
let source = String::from("'Hello ' f'world{\"!\"}'");
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_u_f_string_concat_1() {
|
fn test_parse_u_f_string_concat_1() {
|
||||||
let source = String::from("u'Hello ' f'world'");
|
let source = String::from("u'Hello ' f'world'");
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_u_f_string_concat_2() {
|
fn test_parse_u_f_string_concat_2() {
|
||||||
let source = String::from("u'Hello ' f'world' '!'");
|
let source = String::from("u'Hello ' f'world' '!'");
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue