Implement asdl in the ast and parser

This commit is contained in:
Noah committed 2021-01-14 12:37:37 -06:00
1 parent 0063c766b7
commit b8aabb7bb7
41 files changed
+3135 -1855

No files matched your search

+3
View File
@@ -22,3 +22,6 @@ unic-ucd-ident = "0.9"
unicode_names2 = "0.4"
phf = { version = "0.8", features = ["macros"] }
ahash = "0.6"
[dev-dependencies]
insta = "1.5"
+106 -150
View File
@@ -2,25 +2,31 @@ use std::iter;
use std::mem;
use std::str;
use crate::ast::{ConversionFlag, Expression, Location, StringGroup};
use crate::ast::{Constant, ConversionFlag, Expr, ExprKind, Location};
use crate::error::{FStringError, FStringErrorType, ParseError};
use crate::parser::parse_expression;
use self::FStringErrorType::*;
use self::StringGroup::*;
struct FStringParser<'a> {
chars: iter::Peekable<str::Chars<'a>>,
str_location: Location,
}
impl<'a> FStringParser<'a> {
fn new(source: &'a str) -> Self {
fn new(source: &'a str, str_location: Location) -> Self {
Self {
chars: source.chars().peekable(),
str_location,
}
}
fn parse_formatted_value(&mut self) -> Result<StringGroup, FStringErrorType> {
#[inline]
fn expr(&self, node: ExprKind) -> Expr {
Expr::new(self.str_location, node)
}
fn parse_formatted_value(&mut self) -> Result<Vec<Expr>, FStringErrorType> {
let mut expression = String::new();
let mut spec = None;
let mut delims = Vec::new();
@@ -114,20 +120,23 @@ impl<'a> FStringParser<'a> {
if in_nested {
return Err(UnclosedLbrace);
}
if nested {
spec = Some(Box::new(FormattedValue {
value: Box::new(
parse_fstring_expr(&spec_expression)
.map_err(|e| InvalidExpression(Box::new(e.error)))?,
),
conversion: None,
spec: None,
}))
spec = Some(if nested {
Box::new(
self.expr(ExprKind::FormattedValue {
value: Box::new(
parse_fstring_expr(&spec_expression)
.map_err(|e| InvalidExpression(Box::new(e.error)))?,
),
conversion: None,
format_spec: None,
}),
)
} else {
spec = Some(Box::new(Constant {
value: spec_expression.to_owned(),
Box::new(self.expr(ExprKind::Constant {
value: spec_expression.to_owned().into(),
kind: None,
}))
}
})
}
'(' | '{' | '[' => {
expression.push(ch);
@@ -155,35 +164,36 @@ impl<'a> FStringParser<'a> {
if expression.is_empty() {
return Err(EmptyExpression);
}
if pred_expression_text.is_empty() {
return Ok(FormattedValue {
let ret = if pred_expression_text.is_empty() {
vec![self.expr(ExprKind::FormattedValue {
value: Box::new(
parse_fstring_expr(&expression)
.map_err(|e| InvalidExpression(Box::new(e.error)))?,
),
conversion,
spec,
});
format_spec: spec,
})]
} else {
return Ok(Joined {
values: vec![
Constant {
value: pred_expression_text + "=",
},
Constant {
value: trailing_seq,
},
FormattedValue {
value: Box::new(
parse_fstring_expr(&expression)
.map_err(|e| InvalidExpression(Box::new(e.error)))?,
),
conversion,
spec,
},
],
});
}
vec![
self.expr(ExprKind::Constant {
value: Constant::Str(pred_expression_text + "="),
kind: None,
}),
self.expr(ExprKind::Constant {
value: trailing_seq.into(),
kind: None,
}),
self.expr(ExprKind::FormattedValue {
value: Box::new(
parse_fstring_expr(&expression)
.map_err(|e| InvalidExpression(Box::new(e.error)))?,
),
conversion,
format_spec: spec,
}),
]
};
return Ok(ret);
}
'"' | '\'' => {
expression.push(ch);
@@ -205,7 +215,7 @@ impl<'a> FStringParser<'a> {
Err(UnclosedLbrace)
}
fn parse(mut self) -> Result<StringGroup, FStringErrorType> {
fn parse(mut self) -> Result<Expr, FStringErrorType> {
let mut content = String::new();
let mut values = vec![];
@@ -217,12 +227,13 @@ impl<'a> FStringParser<'a> {
content.push('{');
} else {
if !content.is_empty() {
values.push(Constant {
value: mem::replace(&mut content, String::new()),
});
values.push(self.expr(ExprKind::Constant {
value: mem::take(&mut content).into(),
kind: None,
}));
}
values.push(self.parse_formatted_value()?);
values.extend(self.parse_formatted_value()?);
}
}
'}' => {
@@ -240,151 +251,96 @@ impl<'a> FStringParser<'a> {
}
if !content.is_empty() {
values.push(Constant { value: content })
values.push(self.expr(ExprKind::Constant {
value: content.into(),
kind: None,
}))
}
Ok(match values.len() {
0 => Constant {
value: String::new(),
},
let s = match values.len() {
0 => self.expr(ExprKind::Constant {
value: String::new().into(),
kind: None,
}),
1 => values.into_iter().next().unwrap(),
_ => Joined { values },
})
_ => self.expr(ExprKind::JoinedStr { values }),
};
Ok(s)
}
}
fn parse_fstring_expr(source: &str) -> Result<Expression, ParseError> {
fn parse_fstring_expr(source: &str) -> Result<Expr, ParseError> {
let fstring_body = format!("({})", source);
let mut expression = parse_expression(&fstring_body)?;
expression.location.go_left();
Ok(expression)
}
/// Parse an f-string into a string group.
fn parse_fstring(source: &str) -> Result<StringGroup, FStringErrorType> {
FStringParser::new(source).parse()
parse_expression(&fstring_body)
}
/// Parse an fstring from a string, located at a certain position in the sourcecode.
/// In case of errors, we will get the location and the error returned.
pub fn parse_located_fstring(
source: &str,
location: Location,
) -> Result<StringGroup, FStringError> {
parse_fstring(source).map_err(|error| FStringError { error, location })
pub fn parse_located_fstring(source: &str, location: Location) -> Result<Expr, FStringError> {
FStringParser::new(source, location)
.parse()
.map_err(|error| FStringError { error, location })
}
#[cfg(test)]
mod tests {
use crate::ast;
use super::*;
fn mk_ident(name: &str, row: usize, col: usize) -> ast::Expression {
ast::Expression {
location: ast::Location::new(row, col),
custom: (),
node: ast::ExpressionType::Identifier {
name: name.to_owned(),
},
}
fn parse_fstring(source: &str) -> Result<Expr, FStringErrorType> {
FStringParser::new(source, Location::default()).parse()
}
#[test]
fn test_parse_fstring() {
let source = String::from("{a}{ b }{{foo}}");
let source = "{a}{ b }{{foo}}";
let parse_ast = parse_fstring(&source).unwrap();
assert_eq!(
parse_ast,
Joined {
values: vec![
FormattedValue {
value: Box::new(mk_ident("a", 1, 1)),
conversion: None,
spec: None,
},
FormattedValue {
value: Box::new(mk_ident("b", 1, 2)),
conversion: None,
spec: None,
},
Constant {
value: "{foo}".to_owned()
}
]
}
);
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_parse_fstring_nested_spec() {
let source = String::from("{foo:{spec}}");
let source = "{foo:{spec}}";
let parse_ast = parse_fstring(&source).unwrap();
assert_eq!(
parse_ast,
FormattedValue {
value: Box::new(mk_ident("foo", 1, 1)),
conversion: None,
spec: Some(Box::new(FormattedValue {
value: Box::new(mk_ident("spec", 1, 1)),
conversion: None,
spec: None,
})),
}
);
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_parse_fstring_not_nested_spec() {
let source = String::from("{foo:spec}");
let source = "{foo:spec}";
let parse_ast = parse_fstring(&source).unwrap();
assert_eq!(
parse_ast,
FormattedValue {
value: Box::new(mk_ident("foo", 1, 1)),
conversion: None,
spec: Some(Box::new(Constant {
value: "spec".to_owned(),
})),
}
);
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_parse_empty_fstring() {
assert_eq!(
parse_fstring(""),
Ok(Constant {
value: String::new(),
}),
);
insta::assert_debug_snapshot!(parse_fstring("").unwrap());
}
#[test]
fn test_fstring_parse_selfdocumenting_base() {
let src = String::from("{user=}");
let parse_ast = parse_fstring(&src);
let src = "{user=}";
let parse_ast = parse_fstring(&src).unwrap();
assert!(parse_ast.is_ok());
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_fstring_parse_selfdocumenting_base_more() {
let src = String::from("mix {user=} with text and {second=}");
let parse_ast = parse_fstring(&src);
let src = "mix {user=} with text and {second=}";
let parse_ast = parse_fstring(&src).unwrap();
assert!(parse_ast.is_ok());
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_fstring_parse_selfdocumenting_format() {
let src = String::from("{user=:>10}");
let parse_ast = parse_fstring(&src);
let src = "{user=:>10}";
let parse_ast = parse_fstring(&src).unwrap();
assert!(parse_ast.is_ok());
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
@@ -414,36 +370,36 @@ mod tests {
#[test]
fn test_parse_fstring_not_equals() {
let source = String::from("{1 != 2}");
let parse_ast = parse_fstring(&source);
assert!(parse_ast.is_ok());
let source = "{1 != 2}";
let parse_ast = parse_fstring(&source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_parse_fstring_equals() {
let source = String::from("{42 == 42}");
let parse_ast = parse_fstring(&source);
assert!(parse_ast.is_ok());
let source = "{42 == 42}";
let parse_ast = parse_fstring(&source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_parse_fstring_selfdoc_prec_space() {
let source = String::from("{x =}");
let parse_ast = parse_fstring(&source);
assert!(parse_ast.is_ok());
let source = "{x =}";
let parse_ast = parse_fstring(&source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_parse_fstring_selfdoc_trailing_space() {
let source = String::from("{x= }");
let parse_ast = parse_fstring(&source);
assert!(parse_ast.is_ok());
let source = "{x= }";
let parse_ast = parse_fstring(&source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_parse_fstring_yield_expr() {
let source = String::from("{yield}");
let parse_ast = parse_fstring(&source);
assert!(parse_ast.is_ok());
let source = "{yield}";
let parse_ast = parse_fstring(&source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
}
+28 -16
View File
@@ -4,16 +4,22 @@ use std::collections::HashSet;
use crate::ast;
use crate::error::{LexicalError, LexicalErrorType};
type ParameterDefs = (Vec<ast::Parameter>, Vec<ast::Expression>);
type ParameterDef = (ast::Parameter, Option<ast::Expression>);
pub struct ArgumentList {
pub args: Vec<ast::Expr>,
pub keywords: Vec<ast::Keyword>,
}
type ParameterDefs = (Vec<ast::Arg>, Vec<ast::Arg>, Vec<ast::Expr>);
type ParameterDef = (ast::Arg, Option<ast::Expr>);
pub fn parse_params(
params: (Vec<ParameterDef>, Vec<ParameterDef>),
) -> Result<ParameterDefs, LexicalError> {
let mut names = vec![];
let mut posonly = Vec::with_capacity(params.0.len());
let mut names = Vec::with_capacity(params.1.len());
let mut defaults = vec![];
let mut try_default = |name: &ast::Parameter, default| {
let mut try_default = |name: &ast::Arg, default| {
if let Some(default) = default {
defaults.push(default);
} else if !defaults.is_empty() {
@@ -29,7 +35,7 @@ pub fn parse_params(
for (name, default) in params.0 {
try_default(&name, default)?;
names.push(name);
posonly.push(name);
}
for (name, default) in params.1 {
@@ -37,31 +43,37 @@ pub fn parse_params(
names.push(name);
}
Ok((names, defaults))
Ok((posonly, names, defaults))
}
type FunctionArgument = (Option<Option<String>>, ast::Expression);
type FunctionArgument = (Option<(ast::Location, Option<String>)>, ast::Expr);
pub fn parse_args(func_args: Vec<FunctionArgument>) -> Result<ast::ArgumentList, LexicalError> {
pub fn parse_args(func_args: Vec<FunctionArgument>) -> Result<ArgumentList, LexicalError> {
let mut args = vec![];
let mut keywords = vec![];
let mut keyword_names = HashSet::with_capacity_and_hasher(func_args.len(), RandomState::new());
for (name, value) in func_args {
match name {
Some(n) => {
if let Some(keyword_name) = n.clone() {
if keyword_names.contains(&keyword_name) {
Some((location, name)) => {
if let Some(keyword_name) = &name {
if keyword_names.contains(keyword_name) {
return Err(LexicalError {
error: LexicalErrorType::DuplicateKeywordArgumentError,
location: value.location,
location,
});
}
keyword_names.insert(keyword_name.clone());
}
keywords.push(ast::Keyword { name: n, value });
keywords.push(ast::Keyword::new(
location,
ast::KeywordData {
arg: name,
value: Box::new(value),
},
));
}
None => {
// Allow starred args after keyword arguments.
@@ -76,9 +88,9 @@ pub fn parse_args(func_args: Vec<FunctionArgument>) -> Result<ast::ArgumentList,
}
}
}
Ok(ast::ArgumentList { args, keywords })
Ok(ArgumentList { args, keywords })
}
fn is_starred(exp: &ast::Expression) -> bool {
matches!(exp.node, ast::ExpressionType::Starred { .. })
fn is_starred(exp: &ast::Expr) -> bool {
matches!(exp.node, ast::ExprKind::Starred { .. })
}
+11 -3
View File
@@ -111,9 +111,17 @@ pub static KEYWORDS: phf::Map<&'static str, Tok> = phf::phf_map! {
pub type Spanned = (Location, Tok, Location);
pub type LexResult = Result<Spanned, LexicalError>;
#[inline]
pub fn make_tokenizer(source: &str) -> impl Iterator<Item = LexResult> + '_ {
make_tokenizer_located(source, Location::new(0, 0))
}
pub fn make_tokenizer_located(
source: &str,
start_location: Location,
) -> impl Iterator<Item = LexResult> + '_ {
let nlh = NewlineHandler::new(source.chars());
Lexer::new(nlh)
Lexer::new(nlh, start_location)
}
// The newline handler is an iterator which collapses different newline
@@ -177,7 +185,7 @@ impl<T> Lexer<T>
where
T: Iterator<Item = char>,
{
pub fn new(input: T) -> Self {
pub fn new(input: T, start: Location) -> Self {
let mut lxr = Lexer {
chars: input,
at_begin_of_line: true,
@@ -185,7 +193,7 @@ where
indentation_stack: vec![Default::default()],
pending: Vec::new(),
chr0: None,
location: Location::new(0, 0),
location: start,
chr1: None,
chr2: None,
};
+17 -4
View File
@@ -1,15 +1,28 @@
use crate::token::Tok;
#[derive(Clone, Copy)]
pub enum Mode {
Program,
Statement,
Module,
Interactive,
Expression,
}
impl Mode {
pub(crate) fn to_marker(self) -> Tok {
match self {
Self::Module => Tok::StartModule,
Self::Interactive => Tok::StartInteractive,
Self::Expression => Tok::StartExpression,
}
}
}
impl std::str::FromStr for Mode {
type Err = ModeParseError;
fn from_str(s: &str) -> Result<Self, ModeParseError> {
match s {
"exec" | "single" => Ok(Mode::Program),
"eval" => Ok(Mode::Statement),
"exec" | "single" => Ok(Mode::Module),
"eval" => Ok(Mode::Expression),
_ => Err(ModeParseError { _priv: () }),
}
}
+54 -418
View File
@@ -12,7 +12,6 @@ use crate::error::ParseError;
use crate::lexer;
pub use crate::mode::Mode;
use crate::python;
use crate::token;
/*
* Parse python code.
@@ -20,33 +19,12 @@ use crate::token;
* https://github.com/antlr/grammars-v4/tree/master/python3
*/
macro_rules! do_lalr_parsing {
($input: expr, $pat: ident, $tok: ident) => {{
let lxr = lexer::make_tokenizer($input);
let marker_token = (Default::default(), token::Tok::$tok, Default::default());
let tokenizer = iter::once(Ok(marker_token)).chain(lxr);
match python::TopParser::new().parse(tokenizer) {
Err(err) => Err(ParseError::from(err)),
Ok(top) => {
if let ast::Top::$pat(x) = top {
Ok(x)
} else {
unreachable!()
}
}
}
}};
}
/// Parse a full python program, containing usually multiple lines.
pub fn parse_program(source: &str) -> Result<ast::Program, ParseError> {
do_lalr_parsing!(source, Program, StartProgram)
}
/// Parse a single statement.
pub fn parse_statement(source: &str) -> Result<Vec<ast::Statement>, ParseError> {
do_lalr_parsing!(source, Statement, StartStatement)
pub fn parse_program(source: &str) -> Result<ast::Suite, ParseError> {
parse(source, Mode::Module).map(|top| match top {
ast::Mod::Module { body, .. } => body,
_ => unreachable!(),
})
}
/// Parses a python expression
@@ -54,478 +32,136 @@ pub fn parse_statement(source: &str) -> Result<Vec<ast::Statement>, ParseError>
/// # Example
/// ```
/// extern crate num_bigint;
/// use num_bigint::BigInt;
/// use rustpython_parser::{parser, ast};
/// let expr = parser::parse_expression("1 + 2").unwrap();
///
/// assert_eq!(ast::Expression {
/// assert_eq!(
/// expr,
/// ast::Expr {
/// location: ast::Location::new(1, 3),
/// custom: (),
/// node: ast::ExpressionType::Binop {
/// a: Box::new(ast::Expression {
/// node: ast::ExprKind::BinOp {
/// left: Box::new(ast::Expr {
/// location: ast::Location::new(1, 1),
/// custom: (),
/// node: ast::ExpressionType::Number {
/// value: ast::Number::Integer { value: BigInt::from(1) }
/// node: ast::ExprKind::Constant {
/// value: ast::Constant::Int(1.into()),
/// kind: None,
/// }
/// }),
/// op: ast::Operator::Add,
/// b: Box::new(ast::Expression {
/// right: Box::new(ast::Expr {
/// location: ast::Location::new(1, 5),
/// custom: (),
/// node: ast::ExpressionType::Number {
/// value: ast::Number::Integer { value: BigInt::from(2) }
/// node: ast::ExprKind::Constant {
/// value: ast::Constant::Int(2.into()),
/// kind: None,
/// }
/// })
/// }
/// },
/// expr);
/// );
///
/// ```
pub fn parse_expression(source: &str) -> Result<ast::Expression, ParseError> {
do_lalr_parsing!(source, Expression, StartExpression)
pub fn parse_expression(source: &str) -> Result<ast::Expr, ParseError> {
parse(source, Mode::Expression).map(|top| match top {
ast::Mod::Expression { body } => *body,
_ => unreachable!(),
})
}
// Parse a given source code
pub fn parse(source: &str, mode: Mode) -> Result<ast::Top, ParseError> {
Ok(match mode {
Mode::Program => {
let ast = parse_program(source)?;
ast::Top::Program(ast)
}
Mode::Statement => {
let statement = parse_statement(source)?;
ast::Top::Statement(statement)
}
})
pub fn parse(source: &str, mode: Mode) -> Result<ast::Mod, ParseError> {
let lxr = lexer::make_tokenizer(source);
let marker_token = (Default::default(), mode.to_marker(), Default::default());
let tokenizer = iter::once(Ok(marker_token)).chain(lxr);
python::TopParser::new()
.parse(tokenizer)
.map_err(ParseError::from)
}
#[cfg(test)]
mod tests {
use super::ast;
use super::parse_expression;
use super::parse_program;
use super::parse_statement;
use num_bigint::BigInt;
fn mk_ident(name: &str, row: usize, col: usize) -> ast::Expression {
ast::Expression {
location: ast::Location::new(row, col),
custom: (),
node: ast::ExpressionType::Identifier {
name: name.to_owned(),
},
}
}
fn make_int(value: i32, row: usize, col: usize) -> ast::Expression {
ast::Expression {
location: ast::Location::new(row, col),
custom: (),
node: ast::ExpressionType::Number {
value: ast::Number::Integer {
value: BigInt::from(value),
},
},
}
}
fn make_string(value: &str, row: usize, col: usize) -> ast::Expression {
ast::Expression {
location: ast::Location::new(row, col),
custom: (),
node: ast::ExpressionType::String {
value: ast::StringGroup::Constant {
value: String::from(value),
},
},
}
}
fn as_statement(expr: ast::Expression) -> ast::Statement {
ast::Statement {
location: expr.location,
custom: (),
node: ast::StatementType::Expression { expression: expr },
}
}
use super::*;
#[test]
fn test_parse_empty() {
let parse_ast = parse_program("");
assert_eq!(parse_ast, Ok(ast::Program { statements: vec![] }))
let parse_ast = parse_program("").unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_parse_print_hello() {
let source = String::from("print('Hello world')");
let parse_ast = parse_program(&source).unwrap();
assert_eq!(
parse_ast,
ast::Program {
statements: vec![ast::Statement {
location: ast::Location::new(1, 1),
custom: (),
node: ast::StatementType::Expression {
expression: ast::Expression {
custom: (),
location: ast::Location::new(1, 6),
node: ast::ExpressionType::Call {
function: Box::new(mk_ident("print", 1, 1)),
args: vec![make_string("Hello world", 1, 8)],
keywords: vec![],
}
},
},
},],
}
);
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_parse_print_2() {
let source = String::from("print('Hello world', 2)");
let parse_ast = parse_program(&source).unwrap();
assert_eq!(
parse_ast,
ast::Program {
statements: vec![ast::Statement {
location: ast::Location::new(1, 1),
custom: (),
node: ast::StatementType::Expression {
expression: ast::Expression {
location: ast::Location::new(1, 6),
custom: (),
node: ast::ExpressionType::Call {
function: Box::new(mk_ident("print", 1, 1)),
args: vec![make_string("Hello world", 1, 8), make_int(2, 1, 22),],
keywords: vec![],
},
},
},
},],
}
);
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_parse_kwargs() {
let source = String::from("my_func('positional', keyword=2)");
let parse_ast = parse_program(&source).unwrap();
assert_eq!(
parse_ast,
ast::Program {
statements: vec![ast::Statement {
location: ast::Location::new(1, 1),
custom: (),
node: ast::StatementType::Expression {
expression: ast::Expression {
location: ast::Location::new(1, 8),
custom: (),
node: ast::ExpressionType::Call {
function: Box::new(mk_ident("my_func", 1, 1)),
args: vec![make_string("positional", 1, 10)],
keywords: vec![ast::Keyword {
name: Some("keyword".to_owned()),
value: make_int(2, 1, 31),
}],
}
},
},
},],
}
);
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_parse_if_elif_else() {
let source = String::from("if 1: 10\nelif 2: 20\nelse: 30");
let parse_ast = parse_statement(&source).unwrap();
assert_eq!(
parse_ast,
vec![ast::Statement {
location: ast::Location::new(1, 1),
custom: (),
node: ast::StatementType::If {
test: make_int(1, 1, 4),
body: vec![as_statement(make_int(10, 1, 7))],
orelse: Some(vec![ast::Statement {
location: ast::Location::new(2, 1),
custom: (),
node: ast::StatementType::If {
test: make_int(2, 2, 6),
body: vec![as_statement(make_int(20, 2, 9))],
orelse: Some(vec![as_statement(make_int(30, 3, 7))]),
}
},]),
}
}]
);
let parse_ast = parse_program(&source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_parse_lambda() {
let source = String::from("lambda x, y: x * y"); // lambda(x, y): x * y");
let parse_ast = parse_statement(&source);
assert_eq!(
parse_ast,
Ok(vec![as_statement(ast::Expression {
location: ast::Location::new(1, 1),
custom: (),
node: ast::ExpressionType::Lambda {
args: Box::new(ast::Parameters {
posonlyargs_count: 0,
args: vec![
ast::Parameter {
location: ast::Location::new(1, 8),
arg: String::from("x"),
annotation: None,
},
ast::Parameter {
location: ast::Location::new(1, 11),
arg: String::from("y"),
annotation: None,
}
],
kwonlyargs: vec![],
vararg: ast::Varargs::None,
kwarg: ast::Varargs::None,
defaults: vec![],
kw_defaults: vec![],
}),
body: Box::new(ast::Expression {
location: ast::Location::new(1, 16),
custom: (),
node: ast::ExpressionType::Binop {
a: Box::new(mk_ident("x", 1, 14)),
op: ast::Operator::Mult,
b: Box::new(mk_ident("y", 1, 18))
}
})
}
})])
)
let source = "lambda x, y: x * y"; // lambda(x, y): x * y";
let parse_ast = parse_program(&source).unwrap();
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_parse_tuples() {
let source = String::from("a, b = 4, 5");
let source = "a, b = 4, 5";
assert_eq!(
parse_statement(&source),
Ok(vec![ast::Statement {
location: ast::Location::new(1, 1),
custom: (),
node: ast::StatementType::Assign {
targets: vec![ast::Expression {
custom: (),
location: ast::Location::new(1, 1),
node: ast::ExpressionType::Tuple {
elements: vec![mk_ident("a", 1, 1), mk_ident("b", 1, 4),]
}
}],
value: ast::Expression {
location: ast::Location::new(1, 8),
custom: (),
node: ast::ExpressionType::Tuple {
elements: vec![make_int(4, 1, 8), make_int(5, 1, 11),]
}
}
}
}])
)
insta::assert_debug_snapshot!(parse_program(&source).unwrap());
}
#[test]
fn test_parse_class() {
let source = String::from(
"class Foo(A, B):\n def __init__(self):\n pass\n def method_with_default(self, arg='default'):\n pass",
);
assert_eq!(
parse_statement(&source),
Ok(vec![ast::Statement {
location: ast::Location::new(1, 1),
custom: (),
node: ast::StatementType::ClassDef {
name: String::from("Foo"),
bases: vec![mk_ident("A", 1, 11), mk_ident("B", 1, 14)],
keywords: vec![],
body: vec![
ast::Statement {
location: ast::Location::new(2, 2),
custom: (),
node: ast::StatementType::FunctionDef {
is_async: false,
name: String::from("__init__"),
args: Box::new(ast::Parameters {
posonlyargs_count: 0,
args: vec![ast::Parameter {
location: ast::Location::new(2, 15),
arg: String::from("self"),
annotation: None,
}],
kwonlyargs: vec![],
vararg: ast::Varargs::None,
kwarg: ast::Varargs::None,
defaults: vec![],
kw_defaults: vec![],
}),
body: vec![ast::Statement {
location: ast::Location::new(3, 3),
custom: (),
node: ast::StatementType::Pass,
}],
decorator_list: vec![],
returns: None,
}
},
ast::Statement {
location: ast::Location::new(4, 2),
custom: (),
node: ast::StatementType::FunctionDef {
is_async: false,
name: String::from("method_with_default"),
args: Box::new(ast::Parameters {
posonlyargs_count: 0,
args: vec![
ast::Parameter {
location: ast::Location::new(4, 26),
arg: String::from("self"),
annotation: None,
},
ast::Parameter {
location: ast::Location::new(4, 32),
arg: String::from("arg"),
annotation: None,
}
],
kwonlyargs: vec![],
vararg: ast::Varargs::None,
kwarg: ast::Varargs::None,
defaults: vec![make_string("default", 4, 37)],
kw_defaults: vec![],
}),
body: vec![ast::Statement {
location: ast::Location::new(5, 3),
custom: (),
node: ast::StatementType::Pass,
}],
decorator_list: vec![],
returns: None,
}
}
],
decorator_list: vec![],
}
}])
)
let source = "\
class Foo(A, B):
def __init__(self):
pass
def method_with_default(self, arg='default'):
pass";
insta::assert_debug_snapshot!(parse_program(&source).unwrap());
}
#[test]
fn test_parse_dict_comprehension() {
let source = String::from("{x1: x2 for y in z}");
let parse_ast = parse_expression(&source).unwrap();
assert_eq!(
parse_ast,
ast::Expression {
location: ast::Location::new(1, 1),
custom: (),
node: ast::ExpressionType::Comprehension {
kind: Box::new(ast::ComprehensionKind::Dict {
key: mk_ident("x1", 1, 2),
value: mk_ident("x2", 1, 6),
}),
generators: vec![ast::Comprehension {
location: ast::Location::new(1, 9),
target: mk_ident("y", 1, 13),
iter: mk_ident("z", 1, 18),
ifs: vec![],
is_async: false,
}],
}
}
);
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
fn test_parse_list_comprehension() {
let source = String::from("[x for y in z]");
let parse_ast = parse_expression(&source).unwrap();
assert_eq!(
parse_ast,
ast::Expression {
custom: (),
location: ast::Location::new(1, 1),
node: ast::ExpressionType::Comprehension {
kind: Box::new(ast::ComprehensionKind::List {
element: mk_ident("x", 1, 2),
}),
generators: vec![ast::Comprehension {
location: ast::Location::new(1, 4),
target: mk_ident("y", 1, 8),
iter: mk_ident("z", 1, 13),
ifs: vec![],
is_async: false,
}],
}
}
);
insta::assert_debug_snapshot!(parse_ast);
}
#[test]
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 parse_ast = parse_expression(&source).unwrap();
assert_eq!(
parse_ast,
ast::Expression {
custom: (),
location: ast::Location::new(1, 1),
node: ast::ExpressionType::Comprehension {
kind: Box::new(ast::ComprehensionKind::List {
element: mk_ident("x", 1, 2)
}),
generators: vec![
ast::Comprehension {
location: ast::Location::new(1, 4),
target: ast::Expression {
custom: (),
location: ast::Location::new(1, 8),
node: ast::ExpressionType::Tuple {
elements: vec![mk_ident("y", 1, 8), mk_ident("y2", 1, 11),],
}
},
iter: mk_ident("z", 1, 17),
ifs: vec![],
is_async: false,
},
ast::Comprehension {
location: ast::Location::new(1, 19),
target: mk_ident("a", 1, 23),
iter: mk_ident("b", 1, 28),
ifs: vec![
ast::Expression {
custom: (),
location: ast::Location::new(1, 35),
node: ast::ExpressionType::Compare {
vals: vec![mk_ident("a", 1, 33), make_int(5, 1, 37),],
ops: vec![ast::Comparison::Less],
}
},
ast::Expression {
custom: (),
location: ast::Location::new(1, 44),
node: ast::ExpressionType::Compare {
vals: vec![mk_ident("a", 1, 42), make_int(10, 1, 46),],
ops: vec![ast::Comparison::Greater],
},
},
],
is_async: false,
}
],
}
}
);
insta::assert_debug_snapshot!(parse_ast);
}
}
+425 -450
View File
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,63 @@
---
source: parser/src/fstring.rs
expression: parse_ast
---
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: JoinedStr {
values: [
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: Constant {
value: Str(
"user=",
),
kind: None,
},
},
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: Constant {
value: Str(
"",
),
kind: None,
},
},
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: FormattedValue {
value: Located {
location: Location {
row: 1,
column: 2,
},
custom: (),
node: Name {
id: "user",
ctx: Load,
},
},
conversion: None,
format_spec: None,
},
},
],
},
}
@@ -0,0 +1,137 @@
---
source: parser/src/fstring.rs
expression: parse_ast
---
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: JoinedStr {
values: [
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: Constant {
value: Str(
"mix ",
),
kind: None,
},
},
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: Constant {
value: Str(
"user=",
),
kind: None,
},
},
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: Constant {
value: Str(
"",
),
kind: None,
},
},
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: FormattedValue {
value: Located {
location: Location {
row: 1,
column: 2,
},
custom: (),
node: Name {
id: "user",
ctx: Load,
},
},
conversion: None,
format_spec: None,
},
},
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: Constant {
value: Str(
" with text and ",
),
kind: None,
},
},
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: Constant {
value: Str(
"second=",
),
kind: None,
},
},
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: Constant {
value: Str(
"",
),
kind: None,
},
},
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: FormattedValue {
value: Located {
location: Location {
row: 1,
column: 2,
},
custom: (),
node: Name {
id: "second",
ctx: Load,
},
},
conversion: None,
format_spec: None,
},
},
],
},
}
@@ -0,0 +1,77 @@
---
source: parser/src/fstring.rs
expression: parse_ast
---
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: JoinedStr {
values: [
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: Constant {
value: Str(
"user=",
),
kind: None,
},
},
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: Constant {
value: Str(
"",
),
kind: None,
},
},
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: FormattedValue {
value: Located {
location: Location {
row: 1,
column: 2,
},
custom: (),
node: Name {
id: "user",
ctx: Load,
},
},
conversion: None,
format_spec: Some(
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: Constant {
value: Str(
">10",
),
kind: None,
},
},
),
},
},
],
},
}
@@ -0,0 +1,17 @@
---
source: parser/src/fstring.rs
expression: "parse_fstring(\"\").unwrap()"
---
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: Constant {
value: Str(
"",
),
kind: None,
},
}
@@ -0,0 +1,72 @@
---
source: parser/src/fstring.rs
expression: parse_ast
---
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: JoinedStr {
values: [
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: FormattedValue {
value: Located {
location: Location {
row: 1,
column: 2,
},
custom: (),
node: Name {
id: "a",
ctx: Load,
},
},
conversion: None,
format_spec: None,
},
},
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: FormattedValue {
value: Located {
location: Location {
row: 1,
column: 3,
},
custom: (),
node: Name {
id: "b",
ctx: Load,
},
},
conversion: None,
format_spec: None,
},
},
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: Constant {
value: Str(
"{foo}",
),
kind: None,
},
},
],
},
}
@@ -0,0 +1,69 @@
---
source: parser/src/fstring.rs
expression: parse_ast
---
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: FormattedValue {
value: Located {
location: Location {
row: 1,
column: 5,
},
custom: (),
node: Compare {
left: Located {
location: Location {
row: 1,
column: 2,
},
custom: (),
node: Constant {
value: Int(
BigInt {
sign: Plus,
data: BigUint {
data: [
42,
],
},
},
),
kind: None,
},
},
ops: [
Eq,
],
comparators: [
Located {
location: Location {
row: 1,
column: 8,
},
custom: (),
node: Constant {
value: Int(
BigInt {
sign: Plus,
data: BigUint {
data: [
42,
],
},
},
),
kind: None,
},
},
],
},
},
conversion: None,
format_spec: None,
},
}
@@ -0,0 +1,49 @@
---
source: parser/src/fstring.rs
expression: parse_ast
---
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: FormattedValue {
value: Located {
location: Location {
row: 1,
column: 2,
},
custom: (),
node: Name {
id: "foo",
ctx: Load,
},
},
conversion: None,
format_spec: Some(
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: FormattedValue {
value: Located {
location: Location {
row: 1,
column: 2,
},
custom: (),
node: Name {
id: "spec",
ctx: Load,
},
},
conversion: None,
format_spec: None,
},
},
),
},
}
@@ -0,0 +1,69 @@
---
source: parser/src/fstring.rs
expression: parse_ast
---
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: FormattedValue {
value: Located {
location: Location {
row: 1,
column: 4,
},
custom: (),
node: Compare {
left: Located {
location: Location {
row: 1,
column: 2,
},
custom: (),
node: Constant {
value: Int(
BigInt {
sign: Plus,
data: BigUint {
data: [
1,
],
},
},
),
kind: None,
},
},
ops: [
NotEq,
],
comparators: [
Located {
location: Location {
row: 1,
column: 7,
},
custom: (),
node: Constant {
value: Int(
BigInt {
sign: Plus,
data: BigUint {
data: [
2,
],
},
},
),
kind: None,
},
},
],
},
},
conversion: None,
format_spec: None,
},
}
@@ -0,0 +1,40 @@
---
source: parser/src/fstring.rs
expression: parse_ast
---
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: FormattedValue {
value: Located {
location: Location {
row: 1,
column: 2,
},
custom: (),
node: Name {
id: "foo",
ctx: Load,
},
},
conversion: None,
format_spec: Some(
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: Constant {
value: Str(
"spec",
),
kind: None,
},
},
),
},
}
@@ -0,0 +1,63 @@
---
source: parser/src/fstring.rs
expression: parse_ast
---
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: JoinedStr {
values: [
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: Constant {
value: Str(
"x =",
),
kind: None,
},
},
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: Constant {
value: Str(
"",
),
kind: None,
},
},
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: FormattedValue {
value: Located {
location: Location {
row: 1,
column: 2,
},
custom: (),
node: Name {
id: "x",
ctx: Load,
},
},
conversion: None,
format_spec: None,
},
},
],
},
}
@@ -0,0 +1,63 @@
---
source: parser/src/fstring.rs
expression: parse_ast
---
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: JoinedStr {
values: [
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: Constant {
value: Str(
"x=",
),
kind: None,
},
},
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: Constant {
value: Str(
" ",
),
kind: None,
},
},
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: FormattedValue {
value: Located {
location: Location {
row: 1,
column: 2,
},
custom: (),
node: Name {
id: "x",
ctx: Load,
},
},
conversion: None,
format_spec: None,
},
},
],
},
}
@@ -0,0 +1,25 @@
---
source: parser/src/fstring.rs
expression: parse_ast
---
Located {
location: Location {
row: 0,
column: 0,
},
custom: (),
node: FormattedValue {
value: Located {
location: Location {
row: 1,
column: 2,
},
custom: (),
node: Yield {
value: None,
},
},
conversion: None,
format_spec: None,
},
}
@@ -0,0 +1,160 @@
---
source: parser/src/parser.rs
expression: parse_program(&source).unwrap()
---
[
Located {
location: Location {
row: 1,
column: 1,
},
custom: (),
node: ClassDef {
name: "Foo",
bases: [
Located {
location: Location {
row: 1,
column: 11,
},
custom: (),
node: Name {
id: "A",
ctx: Load,
},
},
Located {
location: Location {
row: 1,
column: 14,
},
custom: (),
node: Name {
id: "B",
ctx: Load,
},
},
],
keywords: [],
body: [
Located {
location: Location {
row: 2,
column: 2,
},
custom: (),
node: FunctionDef {
name: "__init__",
args: Arguments {
posonlyargs: [],
args: [
Located {
location: Location {
row: 2,
column: 15,
},
custom: (),
node: ArgData {
arg: "self",
annotation: None,
type_comment: None,
},
},
],
vararg: None,
kwonlyargs: [],
kw_defaults: [],
kwarg: None,
defaults: [],
},
body: [
Located {
location: Location {
row: 3,
column: 3,
},
custom: (),
node: Pass,
},
],
decorator_list: [],
returns: None,
type_comment: None,
},
},
Located {
location: Location {
row: 4,
column: 2,
},
custom: (),
node: FunctionDef {
name: "method_with_default",
args: Arguments {
posonlyargs: [],
args: [
Located {
location: Location {
row: 4,
column: 26,
},
custom: (),
node: ArgData {
arg: "self",
annotation: None,
type_comment: None,
},
},
Located {
location: Location {
row: 4,
column: 32,
},
custom: (),
node: ArgData {
arg: "arg",
annotation: None,
type_comment: None,
},
},
],
vararg: None,
kwonlyargs: [],
kw_defaults: [],
kwarg: None,
defaults: [
Located {
location: Location {
row: 4,
column: 37,
},
custom: (),
node: Constant {
value: Str(
"default",
),
kind: None,
},
},
],
},
body: [
Located {
location: Location {
row: 5,
column: 3,
},
custom: (),
node: Pass,
},
],
decorator_list: [],
returns: None,
type_comment: None,
},
},
],
decorator_list: [],
},
},
]
@@ -0,0 +1,63 @@
---
source: parser/src/parser.rs
expression: parse_ast
---
Located {
location: Location {
row: 1,
column: 1,
},
custom: (),
node: DictComp {
key: Located {
location: Location {
row: 1,
column: 2,
},
custom: (),
node: Name {
id: "x1",
ctx: Load,
},
},
value: Located {
location: Location {
row: 1,
column: 6,
},
custom: (),
node: Name {
id: "x2",
ctx: Load,
},
},
generators: [
Comprehension {
target: Located {
location: Location {
row: 1,
column: 13,
},
custom: (),
node: Name {
id: "y",
ctx: Load,
},
},
iter: Located {
location: Location {
row: 1,
column: 18,
},
custom: (),
node: Name {
id: "z",
ctx: Load,
},
},
ifs: [],
is_async: false,
},
],
},
}
@@ -0,0 +1,192 @@
---
source: parser/src/parser.rs
expression: parse_ast
---
Located {
location: Location {
row: 1,
column: 1,
},
custom: (),
node: ListComp {
elt: Located {
location: Location {
row: 1,
column: 2,
},
custom: (),
node: Name {
id: "x",
ctx: Load,
},
},
generators: [
Comprehension {
target: Located {
location: Location {
row: 1,
column: 8,
},
custom: (),
node: Tuple {
elts: [
Located {
location: Location {
row: 1,
column: 8,
},
custom: (),
node: Name {
id: "y",
ctx: Load,
},
},
Located {
location: Location {
row: 1,
column: 11,
},
custom: (),
node: Name {
id: "y2",
ctx: Load,
},
},
],
ctx: Load,
},
},
iter: Located {
location: Location {
row: 1,
column: 17,
},
custom: (),
node: Name {
id: "z",
ctx: Load,
},
},
ifs: [],
is_async: false,
},
Comprehension {
target: Located {
location: Location {
row: 1,
column: 23,
},
custom: (),
node: Name {
id: "a",
ctx: Load,
},
},
iter: Located {
location: Location {
row: 1,
column: 28,
},
custom: (),
node: Name {
id: "b",
ctx: Load,
},
},
ifs: [
Located {
location: Location {
row: 1,
column: 35,
},
custom: (),
node: Compare {
left: Located {
location: Location {
row: 1,
column: 33,
},
custom: (),
node: Name {
id: "a",
ctx: Load,
},
},
ops: [
Lt,
],
comparators: [
Located {
location: Location {
row: 1,
column: 37,
},
custom: (),
node: Constant {
value: Int(
BigInt {
sign: Plus,
data: BigUint {
data: [
5,
],
},
},
),
kind: None,
},
},
],
},
},
Located {
location: Location {
row: 1,
column: 44,
},
custom: (),
node: Compare {
left: Located {
location: Location {
row: 1,
column: 42,
},
custom: (),
node: Name {
id: "a",
ctx: Load,
},
},
ops: [
Gt,
],
comparators: [
Located {
location: Location {
row: 1,
column: 46,
},
custom: (),
node: Constant {
value: Int(
BigInt {
sign: Plus,
data: BigUint {
data: [
10,
],
},
},
),
kind: None,
},
},
],
},
},
],
is_async: false,
},
],
},
}
@@ -0,0 +1,5 @@
---
source: parser/src/parser.rs
expression: parse_ast
---
[]
@@ -0,0 +1,159 @@
---
source: parser/src/parser.rs
expression: parse_ast
---
[
Located {
location: Location {
row: 1,
column: 1,
},
custom: (),
node: If {
test: Located {
location: Location {
row: 1,
column: 4,
},
custom: (),
node: Constant {
value: Int(
BigInt {
sign: Plus,
data: BigUint {
data: [
1,
],
},
},
),
kind: None,
},
},
body: [
Located {
location: Location {
row: 1,
column: 7,
},
custom: (),
node: Expr {
value: Located {
location: Location {
row: 1,
column: 7,
},
custom: (),
node: Constant {
value: Int(
BigInt {
sign: Plus,
data: BigUint {
data: [
10,
],
},
},
),
kind: None,
},
},
},
},
],
orelse: [
Located {
location: Location {
row: 2,
column: 1,
},
custom: (),
node: If {
test: Located {
location: Location {
row: 2,
column: 6,
},
custom: (),
node: Constant {
value: Int(
BigInt {
sign: Plus,
data: BigUint {
data: [
2,
],
},
},
),
kind: None,
},
},
body: [
Located {
location: Location {
row: 2,
column: 9,
},
custom: (),
node: Expr {
value: Located {
location: Location {
row: 2,
column: 9,
},
custom: (),
node: Constant {
value: Int(
BigInt {
sign: Plus,
data: BigUint {
data: [
20,
],
},
},
),
kind: None,
},
},
},
},
],
orelse: [
Located {
location: Location {
row: 3,
column: 7,
},
custom: (),
node: Expr {
value: Located {
location: Location {
row: 3,
column: 7,
},
custom: (),
node: Constant {
value: Int(
BigInt {
sign: Plus,
data: BigUint {
data: [
30,
],
},
},
),
kind: None,
},
},
},
},
],
},
},
],
},
},
]
@@ -0,0 +1,84 @@
---
source: parser/src/parser.rs
expression: parse_ast
---
[
Located {
location: Location {
row: 1,
column: 1,
},
custom: (),
node: Expr {
value: Located {
location: Location {
row: 1,
column: 8,
},
custom: (),
node: Call {
func: Located {
location: Location {
row: 1,
column: 1,
},
custom: (),
node: Name {
id: "my_func",
ctx: Load,
},
},
args: [
Located {
location: Location {
row: 1,
column: 10,
},
custom: (),
node: Constant {
value: Str(
"positional",
),
kind: None,
},
},
],
keywords: [
Located {
location: Location {
row: 1,
column: 23,
},
custom: (),
node: KeywordData {
arg: Some(
"keyword",
),
value: Located {
location: Location {
row: 1,
column: 31,
},
custom: (),
node: Constant {
value: Int(
BigInt {
sign: Plus,
data: BigUint {
data: [
2,
],
},
},
),
kind: None,
},
},
},
},
],
},
},
},
},
]
@@ -0,0 +1,90 @@
---
source: parser/src/parser.rs
expression: parse_ast
---
[
Located {
location: Location {
row: 1,
column: 1,
},
custom: (),
node: Expr {
value: Located {
location: Location {
row: 1,
column: 1,
},
custom: (),
node: Lambda {
args: Arguments {
posonlyargs: [],
args: [
Located {
location: Location {
row: 1,
column: 8,
},
custom: (),
node: ArgData {
arg: "x",
annotation: None,
type_comment: None,
},
},
Located {
location: Location {
row: 1,
column: 11,
},
custom: (),
node: ArgData {
arg: "y",
annotation: None,
type_comment: None,
},
},
],
vararg: None,
kwonlyargs: [],
kw_defaults: [],
kwarg: None,
defaults: [],
},
body: Located {
location: Location {
row: 1,
column: 16,
},
custom: (),
node: BinOp {
left: Located {
location: Location {
row: 1,
column: 14,
},
custom: (),
node: Name {
id: "x",
ctx: Load,
},
},
op: Mult,
right: Located {
location: Location {
row: 1,
column: 18,
},
custom: (),
node: Name {
id: "y",
ctx: Load,
},
},
},
},
},
},
},
},
]
@@ -0,0 +1,52 @@
---
source: parser/src/parser.rs
expression: parse_ast
---
Located {
location: Location {
row: 1,
column: 1,
},
custom: (),
node: ListComp {
elt: Located {
location: Location {
row: 1,
column: 2,
},
custom: (),
node: Name {
id: "x",
ctx: Load,
},
},
generators: [
Comprehension {
target: Located {
location: Location {
row: 1,
column: 8,
},
custom: (),
node: Name {
id: "y",
ctx: Load,
},
},
iter: Located {
location: Location {
row: 1,
column: 13,
},
custom: (),
node: Name {
id: "z",
ctx: Load,
},
},
ifs: [],
is_async: false,
},
],
},
}
@@ -0,0 +1,71 @@
---
source: parser/src/parser.rs
expression: parse_ast
---
[
Located {
location: Location {
row: 1,
column: 1,
},
custom: (),
node: Expr {
value: Located {
location: Location {
row: 1,
column: 6,
},
custom: (),
node: Call {
func: Located {
location: Location {
row: 1,
column: 1,
},
custom: (),
node: Name {
id: "print",
ctx: Load,
},
},
args: [
Located {
location: Location {
row: 1,
column: 8,
},
custom: (),
node: Constant {
value: Str(
"Hello world",
),
kind: None,
},
},
Located {
location: Location {
row: 1,
column: 22,
},
custom: (),
node: Constant {
value: Int(
BigInt {
sign: Plus,
data: BigUint {
data: [
2,
],
},
},
),
kind: None,
},
},
],
keywords: [],
},
},
},
},
]
@@ -0,0 +1,51 @@
---
source: parser/src/parser.rs
expression: parse_ast
---
[
Located {
location: Location {
row: 1,
column: 1,
},
custom: (),
node: Expr {
value: Located {
location: Location {
row: 1,
column: 6,
},
custom: (),
node: Call {
func: Located {
location: Location {
row: 1,
column: 1,
},
custom: (),
node: Name {
id: "print",
ctx: Load,
},
},
args: [
Located {
location: Location {
row: 1,
column: 8,
},
custom: (),
node: Constant {
value: Str(
"Hello world",
),
kind: None,
},
},
],
keywords: [],
},
},
},
},
]
@@ -0,0 +1,104 @@
---
source: parser/src/parser.rs
expression: parse_program(&source).unwrap()
---
[
Located {
location: Location {
row: 1,
column: 1,
},
custom: (),
node: Assign {
targets: [
Located {
location: Location {
row: 1,
column: 1,
},
custom: (),
node: Tuple {
elts: [
Located {
location: Location {
row: 1,
column: 1,
},
custom: (),
node: Name {
id: "a",
ctx: Load,
},
},
Located {
location: Location {
row: 1,
column: 4,
},
custom: (),
node: Name {
id: "b",
ctx: Load,
},
},
],
ctx: Load,
},
},
],
value: Located {
location: Location {
row: 1,
column: 8,
},
custom: (),
node: Tuple {
elts: [
Located {
location: Location {
row: 1,
column: 8,
},
custom: (),
node: Constant {
value: Int(
BigInt {
sign: Plus,
data: BigUint {
data: [
4,
],
},
},
),
kind: None,
},
},
Located {
location: Location {
row: 1,
column: 11,
},
custom: (),
node: Constant {
value: Int(
BigInt {
sign: Plus,
data: BigUint {
data: [
5,
],
},
},
),
kind: None,
},
},
],
ctx: Load,
},
},
type_comment: None,
},
},
]
+4 -4
View File
@@ -15,8 +15,8 @@ pub enum Tok {
Newline,
Indent,
Dedent,
StartProgram,
StartStatement,
StartModule,
StartInteractive,
StartExpression,
EndOfFile,
Lpar,
@@ -136,8 +136,8 @@ impl fmt::Display for Tok {
Newline => f.write_str("Newline"),
Indent => f.write_str("Indent"),
Dedent => f.write_str("Dedent"),
StartProgram => f.write_str("StartProgram"),
StartStatement => f.write_str("StartStatement"),
StartModule => f.write_str("StartProgram"),
StartInteractive => f.write_str("StartInteractive"),
StartExpression => f.write_str("StartExpression"),
EndOfFile => f.write_str("EOF"),
Lpar => f.write_str("'('"),