use std::marker::PhantomData;
use ast::*;
use errors::PyParseError;
use expressions::ExpressionParser;
use functions::decorated;
use helpers::*;
macro_rules! call_test {
( $i:expr, $($args:tt)* ) => { call!($i, ExpressionParser::<NewlinesAreNotSpaces>::test, $($args)*) }
}
named_args!(pub statement(indent: usize) <StrSpan, Vec<Statement>>,
alt!(
call!(compound_stmt, indent) => { |stmt| vec![Statement::Compound(Box::new(stmt))] }
| preceded!(indent!(indent), call!(simple_stmt))
)
);
named_args!(simple_stmt() <StrSpan, Vec<Statement>>,
return_error!(
do_parse!(
stmts: separated_nonempty_list!(ws_nonl!(semicolon), call!(small_stmt)) >>
opt!(semicolon) >> (
stmts
)
)
)
);
named!(small_stmt<StrSpan, Statement>,
alt!(
switch!(peek!(ws_nonl!(first_word)),
"del" => return_error!(del_stmt)
| "pass" => return_error!(pass_stmt)
| "import" => return_error!(import_stmt)
| "from" => return_error!(import_stmt)
| "global" => return_error!(global_stmt)
| "nonlocal" => return_error!(nonlocal_stmt)
| "assert" => return_error!(assert_stmt)
)
| flow_stmt
| expr_stmt
)
);
named!(expr_stmt<StrSpan, Statement>,
do_parse!(
lhs: call!(ExpressionParser::<NewlinesAreNotSpaces>::testlist_star_expr) >>
r: ws_nonl!(alt!(
do_parse!(
char!(':') >>
typed: call!(ExpressionParser::<NewlinesAreNotSpaces>::test) >>
rhs: opt!(ws_nonl!(preceded!(char!('='), alt!(
call!(ExpressionParser::<NewlinesAreNotSpaces>::yield_expr) => { |e| vec![e] }
| call!(ExpressionParser::<NewlinesAreNotSpaces>::testlist)
)))) >> (
match rhs {
None => Statement::TypeAnnotation(lhs.clone(), *typed),
Some(rhs) => Statement::TypedAssignment(lhs.clone(), *typed, rhs),
}
)
)
| do_parse!(
op: augassign >>
rhs: alt!(
call!(ExpressionParser::<NewlinesAreNotSpaces>::yield_expr) => { |e| vec![e] }
| call!(ExpressionParser::<NewlinesAreNotSpaces>::testlist)
) >> (
Statement::AugmentedAssignment(lhs.clone(), op, rhs)
)
)
| do_parse!(
rhs: many0!(ws_nonl!(preceded!(char!('='), alt!(
call!(ExpressionParser::<NewlinesAreNotSpaces>::yield_expr) => { |e| vec![e] }
| call!(ExpressionParser::<NewlinesAreNotSpaces>::testlist_star_expr)
)))) >> (
Statement::Assignment(lhs, rhs)
)
)
)) >>
(r)
)
);
named!(augassign<StrSpan, AugAssignOp>,
ws_nonl!(alt!(
tag!("+=") => { |_| AugAssignOp::Add }
| tag!("-=") => { |_| AugAssignOp::Sub }
| tag!("*=") => { |_| AugAssignOp::Mult }
| tag!("@=") => { |_| AugAssignOp::MatMult }
| tag!("/=") => { |_| AugAssignOp::Div }
| tag!("%=") => { |_| AugAssignOp::Mod }
| tag!("&=") => { |_| AugAssignOp::BitAnd }
| tag!("|=") => { |_| AugAssignOp::BitOr }
| tag!("^=") => { |_| AugAssignOp::BitXor }
| tag!("<<=") => { |_| AugAssignOp::Lshift }
| tag!(">>=") => { |_| AugAssignOp::Rshift }
| tag!("**=") => { |_| AugAssignOp::Power }
| tag!("//=") => { |_| AugAssignOp::Floordiv }
))
);
named!(del_stmt<StrSpan, Statement>,
map!(delimited!(tuple!(keyword!("del"), spaces_nonl), ExpressionParser::<NewlinesAreNotSpaces>::exprlist, opt!(char!(','))), |v:Vec<_>| Statement::Del(v))
);
named!(pass_stmt<StrSpan, Statement>,
map!(terminated!(keyword!("pass"), spaces_nonl), |_| Statement::Pass)
);
named!(flow_stmt<StrSpan, Statement>,
alt!(
keyword!("break") => { |_| Statement::Break }
| keyword!("continue") => { |_| Statement::Continue }
| preceded!(
tuple!(keyword!("return"), spaces_nonl),
ws_nonl!(call!(ExpressionParser::<NewlinesAreNotSpaces>::testlist_star_expr))
) => { |e| Statement::Return(e) }
| raise_stmt
| call!(ExpressionParser::<NewlinesAreNotSpaces>::yield_expr)
=> { |e| Statement::Expressions(vec![e]) }
)
);
named!(raise_stmt<StrSpan, Statement>,
do_parse!(
keyword!("raise") >>
spaces_nonl >>
t: return_error!(opt!(tuple!(
call_test!(),
opt!(preceded!(ws_nonl!(keyword!("from")), call_test!()))
))) >> (
match t {
Some((exc, Some(from_exc))) => Statement::RaiseExcFrom(*exc, *from_exc),
Some((exc, None)) => Statement::RaiseExc(*exc),
None => Statement::Raise,
}
)
)
);
named!(global_stmt<StrSpan, Statement>,
map!(preceded!(tuple!(keyword!("global"), spaces_nonl),
ws_nonl!(separated_nonempty_list!(ws_nonl!(char!(',')), name))
), |names| Statement::Global(names))
);
named!(nonlocal_stmt<StrSpan, Statement>,
map!(preceded!(tuple!(keyword!("nonlocal"), spaces_nonl),
ws_nonl!(separated_nonempty_list!(ws_nonl!(char!(',')), name))
), |names| Statement::Nonlocal(names))
);
named!(assert_stmt<StrSpan, Statement>,
do_parse!(
keyword!("assert") >>
spaces_nonl >>
assertion: call_test!() >>
msg: opt!(preceded!(ws_nonl!(char!(',')), call_test!())) >> (
Statement::Assert(*assertion, msg.map(|m| *m))
)
)
);
named!(import_stmt<StrSpan, Statement>,
alt!(
import_name => { |i| Statement::Import(i) }
| import_from => { |i| Statement::Import(i) }
)
);
named!(import_name<StrSpan, Import>,
map!(preceded!(tuple!(keyword!("import"), spaces_nonl), call!(ImportParser::<NewlinesAreNotSpaces>::dotted_as_names)),
|names| Import::Import { names }
)
);
named!(import_from<StrSpan, Import>,
do_parse!(
keyword!("from") >>
spaces_nonl >>
import_from: alt!(
do_parse!(
leading_dots: ws_nonl!(map!(many0!(char!('.')), |dots| dots.len())) >>
from_name: opt!(call!(ImportParser::<NewlinesAreNotSpaces>::dotted_name)) >> (
(leading_dots, from_name.unwrap_or(Vec::new()))
)
)
| call!(ImportParser::<NewlinesAreNotSpaces>::dotted_name) => { |n| (0, n) }
) >>
spaces_nonl >>
dbg_dmp!(keyword!("import")) >>
spaces_nonl >>
names: alt!(
char!('*') => { |_| Vec::new() }
| ws_nonl!(delimited!(char!('('), call!(ImportParser::<NewlinesAreSpaces>::import_as_names), char!(')')))
| call!(ImportParser::<NewlinesAreNotSpaces>::import_as_names)
) >>
({
let (leading_dots, path) = import_from;
if names.len() > 0 {
Import::ImportFrom { leading_dots, path, names }
}
else {
Import::ImportStarFrom { leading_dots, path }
}
})
)
);
pub(crate) struct ImportParser<ANS: AreNewlinesSpaces> {
_phantom: PhantomData<ANS>,
}
impl<ANS: AreNewlinesSpaces> ImportParser<ANS> {
named!(import_as_name<StrSpan, (Name, Option<Name>)>,
tuple!(name, opt!(do_parse!(
spaces!() >>
keyword!("as") >>
spaces!() >>
name: name >> (
name
)
)))
);
named!(dotted_as_name<StrSpan, (Vec<Name>, Option<Name>)>,
tuple!(call!(Self::dotted_name), opt!(do_parse!(
spaces!() >>
keyword!("as") >>
spaces!() >>
name: name >> (
name
)
)))
);
named!(import_as_names<StrSpan, Vec<(Name, Option<Name>)>>,
ws_auto!(terminated!(
separated_nonempty_list!(ws_auto!(char!(',')), call!(Self::import_as_name)),
opt!(ws_auto!(char!(',')))
))
);
named!(dotted_as_names<StrSpan, Vec<(Vec<Name>, Option<Name>)>>,
separated_nonempty_list!(ws_nonl!(char!(',')), call!(Self::dotted_as_name))
);
named!(pub dotted_name<StrSpan, Vec<Name>>,
separated_nonempty_list!(ws_nonl!(char!('.')), name)
);
}
named_args!(pub block(indent: usize) <StrSpan, Vec<Statement>>,
alt!(
do_parse!(
new_indent: peek!(
preceded!(
newline,
return_error!(
::nom::ErrorKind::Custom(PyParseError::ExpectedIndent.into()),
do_parse!(
count!(char!(' '), indent) >>
new_spaces: many1!(char!(' ')) >> ({
indent + new_spaces.len()
})
)
)
)
) >>
stmts: fold_many1_fixed!(
do_parse!(
newline >>
r: call!(statement, new_indent) >>
(r)
),
Vec::new(),
|mut acc: Vec<_>, stmt| { acc.extend(stmt); acc }
) >>
(stmts)
)
| call!(simple_stmt)
)
);
named_args!(cond_and_block(indent: usize) <StrSpan, (Expression, Vec<Statement>)>,
return_error!(do_parse!(
spaces_nonl >>
cond: call!(ExpressionParser::<NewlinesAreNotSpaces>::test) >>
ws_nonl!(char!(':')) >>
block: call!(block, indent) >> (
(*cond, block)
)
))
);
named_args!(pub func_body_suite(indent: usize) <StrSpan, Vec<Statement>>,
call!(block, indent)
);
named_args!(compound_stmt(indent: usize) <StrSpan, CompoundStatement>,
alt!(
switch!(peek!(preceded!(indent!(indent), first_word)),
"if" => return_error!(call!(if_stmt, indent))
| "for" => return_error!(call!(for_stmt, indent))
| "while" => return_error!(call!(while_stmt, indent))
| "with" => return_error!(call!(with_stmt, indent))
| "try" => return_error!(call!(try_stmt, indent))
| "def" => return_error!(call!(decorated, indent))
| "class" => return_error!(call!(decorated, indent))
| "async" => return_error!(alt!(
call!(decorated, indent) | call!(for_stmt, indent)
))
)
| call!(decorated, indent)
)
);
named_args!(else_block(indent: usize) <StrSpan, Option<Vec<Statement>>>,
opt!(
preceded!(
tuple!(newline, indent!(indent), tag!("else"), ws_nonl!(char!(':'))),
call!(block, indent)
)
)
);
named_args!(if_stmt(indent: usize) <StrSpan, CompoundStatement>,
do_parse!(
indent!(indent) >>
keyword!("if") >>
if_block: call!(cond_and_block, indent) >>
elif_blocks: many0!(
preceded!(
tuple!(newline, indent!(indent), keyword!("elif")),
call!(cond_and_block, indent)
)
) >>
else_block: call!(else_block, indent) >> ({
let mut blocks: Vec<_> = elif_blocks;
blocks.insert(0, if_block);
CompoundStatement::If(blocks, else_block)
})
)
);
named_args!(while_stmt(indent: usize) <StrSpan, CompoundStatement>,
do_parse!(
indent!(indent) >>
keyword!("while") >>
while_block: call!(cond_and_block, indent) >>
else_block: call!(else_block, indent) >> ({
let (cond, while_block) = while_block;
CompoundStatement::While(cond, while_block, else_block)
})
)
);
named_args!(for_stmt(indent: usize) <StrSpan, CompoundStatement>,
do_parse!(
indent!(indent) >>
async: opt!(tuple!(tag!("async"), space_sep_nonl)) >>
keyword!("for") >>
spaces_nonl >>
item: call!(ExpressionParser::<NewlinesAreNotSpaces>::exprlist) >>
ws_nonl!(keyword!("in")) >>
iterator: call!(ExpressionParser::<NewlinesAreNotSpaces>::testlist) >>
spaces_nonl >>
ws_nonl!(char!(':')) >>
for_block: call!(block, indent) >>
else_block: call!(else_block, indent) >> ({
CompoundStatement::For {
async: async.is_some(),
item, iterator, for_block, else_block
}
})
)
);
named_args!(try_stmt(indent: usize) <StrSpan, CompoundStatement>,
do_parse!(
indent!(indent) >>
tag!("try") >>
ws_nonl!(char!(':')) >>
try_block: call!(block, indent) >>
except_clauses: many0!(do_parse!(
newline >>
indent!(indent) >>
keyword!("except") >>
spaces_nonl >>
catch_what: call!(ExpressionParser::<NewlinesAreNotSpaces>::test) >>
spaces_nonl >>
catch_as: opt!(ws_nonl!(preceded!(keyword!("as"), name))) >>
ws_nonl!(char!(':')) >>
block: call!(block, indent) >> (
(*catch_what, catch_as, block)
)
)) >>
last_except: opt!(do_parse!(
newline >>
indent!(indent) >>
tag!("except") >>
ws_nonl!(char!(':')) >>
r: call!(block, indent) >>
(r)
)) >>
else_block: opt!(do_parse!(
newline >>
indent!(indent) >>
tag!("else") >>
ws_nonl!(char!(':')) >>
r: call!(block, indent) >>
(r)
)) >>
finally_block: opt!(do_parse!(
newline >>
indent!(indent) >>
tag!("finally") >>
ws_nonl!(char!(':')) >>
r: call!(block, indent) >>
(r)
)) >> (
CompoundStatement::Try(Try {
try_block, except_clauses,
last_except: last_except.unwrap_or_default(),
else_block: else_block.unwrap_or_default(),
finally_block: finally_block.unwrap_or_default()
})
)
)
);
named_args!(with_stmt(indent: usize) <StrSpan, CompoundStatement>,
do_parse!(
indent!(indent) >>
keyword!("with") >>
spaces_nonl >>
contexts: separated_nonempty_list!(ws_nonl!(char!(',')), do_parse!(
context: call!(ExpressionParser::<NewlinesAreNotSpaces>::expr) >>
as_: opt!(preceded!(
ws_nonl!(keyword!("as")),
call!(ExpressionParser::<NewlinesAreNotSpaces>::expr)
)) >> (
(*context, as_.map(|e| *e))
)
)) >>
ws_nonl!(char!(':')) >>
code: call!(block, indent) >> (
CompoundStatement::With(contexts, code)
)
)
);
#[cfg(test)]
mod tests {
use super::*;
use helpers::{assert_parse_eq, make_strspan};
#[test]
fn test_statement_indent() {
assert_parse_eq(
statement(make_strspan("del foo"), 0),
Ok((
make_strspan(""),
vec![Statement::Del(vec![Expression::Name("foo".to_string())])],
)),
);
assert_parse_eq(
statement(make_strspan(" del foo"), 1),
Ok((
make_strspan(""),
vec![Statement::Del(vec![Expression::Name("foo".to_string())])],
)),
);
assert!(statement(make_strspan(" del foo"), 0).is_err());
assert!(statement(make_strspan(" del foo"), 1).is_err());
assert!(statement(make_strspan("del foo"), 1).is_err());
}
#[test]
fn test_block() {
assert_parse_eq(
block(make_strspan("\n del foo"), 0),
Ok((
make_strspan(""),
vec![Statement::Del(vec![Expression::Name("foo".to_string())])],
)),
);
assert_parse_eq(
block(make_strspan("\n del foo"), 1),
Ok((
make_strspan(""),
vec![Statement::Del(vec![Expression::Name("foo".to_string())])],
)),
);
assert_parse_eq(
block(make_strspan("\n del foo"), 1),
Ok((
make_strspan(""),
vec![Statement::Del(vec![Expression::Name("foo".to_string())])],
)),
);
assert!(block(make_strspan("\ndel foo"), 0).is_err());
assert!(block(make_strspan("\ndel foo"), 1).is_err());
assert!(block(make_strspan("\n del foo"), 1).is_err());
assert_parse_eq(
block(make_strspan("\n del foo\n del foo"), 0),
Ok((
make_strspan(""),
vec![
Statement::Del(vec![Expression::Name("foo".to_string())]),
Statement::Del(vec![Expression::Name("foo".to_string())]),
],
)),
);
assert_parse_eq(
block(make_strspan("\n del foo\n del foo"), 1),
Ok((
make_strspan(""),
vec![
Statement::Del(vec![Expression::Name("foo".to_string())]),
Statement::Del(vec![Expression::Name("foo".to_string())]),
],
)),
);
assert_parse_eq(
block(make_strspan("\n del foo\n del foo"), 1),
Ok((
make_strspan(""),
vec![
Statement::Del(vec![Expression::Name("foo".to_string())]),
Statement::Del(vec![Expression::Name("foo".to_string())]),
],
)),
);
assert_parse_eq(
block(make_strspan("\n del foo\ndel foo"), 0),
Ok((
make_strspan("\ndel foo"),
vec![Statement::Del(vec![Expression::Name("foo".to_string())])],
)),
);
}
#[test]
fn test_unexpected_indent() {
use errors::PyParseError;
assert_eq!(
statement(make_strspan(" del foo"), 0),
Err(::nom::Err::Failure(::nom::Context::Code(
::nom_locate::LocatedSpan {
line: 1,
offset: 0,
fragment: ::nom::types::CompleteStr(" del foo")
},
::nom::ErrorKind::Custom(PyParseError::UnexpectedIndent.into())
)))
);
assert_eq!(
block(make_strspan("\n del foo\n del foo"), 0),
Err(::nom::Err::Failure(::nom::Context::Code(
::nom_locate::LocatedSpan {
line: 3,
offset: 11,
fragment: ::nom::types::CompleteStr(" del foo")
},
::nom::ErrorKind::Custom(PyParseError::UnexpectedIndent.into())
)))
);
}
#[test]
fn test_del() {
assert_parse_eq(
statement(make_strspan("del foo"), 0),
Ok((
make_strspan(""),
vec![Statement::Del(vec![Expression::Name("foo".to_string())])],
)),
);
assert_parse_eq(
statement(make_strspan("del foo, bar"), 0),
Ok((
make_strspan(""),
vec![Statement::Del(vec![
Expression::Name("foo".to_string()),
Expression::Name("bar".to_string()),
])],
)),
);
}
#[test]
fn test_assert1() {
assert_parse_eq(
block(make_strspan("assert foo"), 0),
Ok((
make_strspan(""),
vec![Statement::Assert(Expression::Name("foo".to_string()), None)],
)),
);
}
#[test]
fn test_assert2() {
assert_parse_eq(
block(make_strspan("assert foo and bar"), 0),
Ok((
make_strspan(""),
vec![Statement::Assert(
Expression::Bop(
Bop::And,
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Name("bar".to_string())),
),
None,
)],
)),
);
}
#[test]
fn test_assert3() {
assert_parse_eq(
block(make_strspan("assert (foo and bar)"), 0),
Ok((
make_strspan(""),
vec![Statement::Assert(
Expression::Bop(
Bop::And,
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Name("bar".to_string())),
),
None,
)],
)),
);
}
#[test]
fn test_assert4() {
assert_parse_eq(
block(make_strspan("assert (foo and\n bar)"), 0),
Ok((
make_strspan(""),
vec![Statement::Assert(
Expression::Bop(
Bop::And,
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Name("bar".to_string())),
),
None,
)],
)),
);
}
#[test]
fn test_if() {
assert_parse_eq(
compound_stmt(make_strspan("if foo:\n del bar"), 0),
Ok((
make_strspan(""),
CompoundStatement::If(
vec![(
Expression::Name("foo".to_string()),
vec![Statement::Del(vec![Expression::Name("bar".to_string())])],
)],
None,
),
)),
);
}
#[test]
fn test_if_not() {
assert_parse_eq(
compound_stmt(make_strspan("if not foo:\n del bar"), 0),
Ok((
make_strspan(""),
CompoundStatement::If(
vec![(
Expression::Uop(Uop::Not, Box::new(Expression::Name("foo".to_string()))),
vec![Statement::Del(vec![Expression::Name("bar".to_string())])],
)],
None,
),
)),
);
}
#[test]
fn test_elif() {
assert_parse_eq(
compound_stmt(make_strspan("if foo:\n del bar\nelif foo:\n del baz"), 0),
Ok((
make_strspan(""),
CompoundStatement::If(
vec![
(
Expression::Name("foo".to_string()),
vec![Statement::Del(vec![Expression::Name("bar".to_string())])],
),
(
Expression::Name("foo".to_string()),
vec![Statement::Del(vec![Expression::Name("baz".to_string())])],
),
],
None,
),
)),
);
}
#[test]
fn test_if_else() {
assert_parse_eq(
compound_stmt(make_strspan("if foo:\n del bar\nelse:\n del qux"), 0),
Ok((
make_strspan(""),
CompoundStatement::If(
vec![(
Expression::Name("foo".to_string()),
vec![Statement::Del(vec![Expression::Name("bar".to_string())])],
)],
Some(vec![Statement::Del(vec![Expression::Name(
"qux".to_string(),
)])]),
),
)),
);
}
#[test]
fn test_elif_else() {
assert_parse_eq(
compound_stmt(
make_strspan("if foo:\n del bar\nelif foo:\n del baz\nelse:\n del qux"),
0,
),
Ok((
make_strspan(""),
CompoundStatement::If(
vec![
(
Expression::Name("foo".to_string()),
vec![Statement::Del(vec![Expression::Name("bar".to_string())])],
),
(
Expression::Name("foo".to_string()),
vec![Statement::Del(vec![Expression::Name("baz".to_string())])],
),
],
Some(vec![Statement::Del(vec![Expression::Name(
"qux".to_string(),
)])]),
),
)),
);
}
#[test]
fn test_nested_if() {
assert_parse_eq(
compound_stmt(make_strspan("if foo:\n if foo:\n del bar"), 0),
Ok((
make_strspan(""),
CompoundStatement::If(
vec![(
Expression::Name("foo".to_string()),
vec![Statement::Compound(Box::new(CompoundStatement::If(
vec![(
Expression::Name("foo".to_string()),
vec![Statement::Del(vec![Expression::Name("bar".to_string())])],
)],
None,
)))],
)],
None,
),
)),
);
}
#[test]
fn test_dangling_else_1() {
assert_parse_eq(
compound_stmt(
make_strspan("if foo:\n if foo:\n del bar\nelse:\n del qux"),
0,
),
Ok((
make_strspan(""),
CompoundStatement::If(
vec![(
Expression::Name("foo".to_string()),
vec![Statement::Compound(Box::new(CompoundStatement::If(
vec![(
Expression::Name("foo".to_string()),
vec![Statement::Del(vec![Expression::Name("bar".to_string())])],
)],
None,
)))],
)],
Some(vec![Statement::Del(vec![Expression::Name(
"qux".to_string(),
)])]),
),
)),
);
}
#[test]
fn test_dangling_else_2() {
assert_parse_eq(
compound_stmt(
make_strspan("if foo:\n if foo:\n del bar\n else:\n del qux"),
0,
),
Ok((
make_strspan(""),
CompoundStatement::If(
vec![(
Expression::Name("foo".to_string()),
vec![Statement::Compound(Box::new(CompoundStatement::If(
vec![(
Expression::Name("foo".to_string()),
vec![Statement::Del(vec![Expression::Name("bar".to_string())])],
)],
Some(vec![Statement::Del(vec![Expression::Name(
"qux".to_string(),
)])]),
)))],
)],
None,
),
)),
);
}
#[test]
fn test_while() {
assert_parse_eq(
compound_stmt(make_strspan("while foo:\n del bar"), 0),
Ok((
make_strspan(""),
CompoundStatement::While(
Expression::Name("foo".to_string()),
vec![Statement::Del(vec![Expression::Name("bar".to_string())])],
None,
),
)),
);
}
#[test]
fn test_while_else() {
assert_parse_eq(
compound_stmt(make_strspan("while foo:\n del bar\nelse:\n del qux"), 0),
Ok((
make_strspan(""),
CompoundStatement::While(
Expression::Name("foo".to_string()),
vec![Statement::Del(vec![Expression::Name("bar".to_string())])],
Some(vec![Statement::Del(vec![Expression::Name(
"qux".to_string(),
)])]),
),
)),
);
}
#[test]
fn test_for() {
assert_parse_eq(
compound_stmt(make_strspan("for foo in bar:\n del baz"), 0),
Ok((
make_strspan(""),
CompoundStatement::For {
async: false,
item: vec![Expression::Name("foo".to_string())],
iterator: vec![Expression::Name("bar".to_string())],
for_block: vec![Statement::Del(vec![Expression::Name("baz".to_string())])],
else_block: None,
},
)),
);
}
#[test]
fn test_for_in_ternary() {
assert_parse_eq(
compound_stmt(make_strspan("for foo in bar if baz else qux:\n pass"), 0),
Ok((
make_strspan(""),
CompoundStatement::For {
async: false,
item: vec![Expression::Name("foo".to_string())],
iterator: vec![Expression::Ternary(
Box::new(Expression::Name("bar".to_string())),
Box::new(Expression::Name("baz".to_string())),
Box::new(Expression::Name("qux".to_string())),
)],
for_block: vec![Statement::Pass],
else_block: None,
},
)),
);
}
#[test]
fn test_for_else() {
assert_parse_eq(
compound_stmt(
make_strspan("for foo in bar:\n del baz\nelse:\n del qux"),
0,
),
Ok((
make_strspan(""),
CompoundStatement::For {
async: false,
item: vec![Expression::Name("foo".to_string())],
iterator: vec![Expression::Name("bar".to_string())],
for_block: vec![Statement::Del(vec![Expression::Name("baz".to_string())])],
else_block: Some(vec![Statement::Del(vec![Expression::Name(
"qux".to_string(),
)])]),
},
)),
);
}
#[test]
fn test_raise() {
assert_parse_eq(
small_stmt(make_strspan("raise")),
Ok((make_strspan(""), Statement::Raise)),
);
assert_parse_eq(
small_stmt(make_strspan("raise exc")),
Ok((
make_strspan(""),
Statement::RaiseExc(Expression::Name("exc".to_string())),
)),
);
assert_parse_eq(
small_stmt(make_strspan("raise exc from exc2")),
Ok((
make_strspan(""),
Statement::RaiseExcFrom(
Expression::Name("exc".to_string()),
Expression::Name("exc2".to_string()),
),
)),
);
}
#[test]
fn test_assign() {
assert_parse_eq(
small_stmt(make_strspan("foo = bar")),
Ok((
make_strspan(""),
Statement::Assignment(
vec![Expression::Name("foo".to_string())],
vec![vec![Expression::Name("bar".to_string())]],
),
)),
);
assert_parse_eq(
small_stmt(make_strspan("foo = bar = baz")),
Ok((
make_strspan(""),
Statement::Assignment(
vec![Expression::Name("foo".to_string())],
vec![
vec![Expression::Name("bar".to_string())],
vec![Expression::Name("baz".to_string())],
],
),
)),
);
}
#[test]
fn test_typeannotation() {
assert_parse_eq(
small_stmt(make_strspan("foo: bar")),
Ok((
make_strspan(""),
Statement::TypeAnnotation(
vec![Expression::Name("foo".to_string())],
Expression::Name("bar".to_string()),
),
)),
);
}
#[test]
fn test_augassign() {
assert_parse_eq(
small_stmt(make_strspan("foo:bar = baz")),
Ok((
make_strspan(""),
Statement::TypedAssignment(
vec![Expression::Name("foo".to_string())],
Expression::Name("bar".to_string()),
vec![Expression::Name("baz".to_string())],
),
)),
);
}
#[test]
fn test_augassign_yield() {
assert_parse_eq(
small_stmt(make_strspan("foo:bar = yield baz")),
Ok((
make_strspan(""),
Statement::TypedAssignment(
vec![Expression::Name("foo".to_string())],
Expression::Name("bar".to_string()),
vec![Expression::Yield(vec![Expression::Name("baz".to_string())])],
),
)),
);
}
#[test]
fn test_unpack_assign() {
assert_parse_eq(
small_stmt(make_strspan("foo, bar = baz, qux")),
Ok((
make_strspan(""),
Statement::Assignment(
vec![
Expression::Name("foo".to_string()),
Expression::Name("bar".to_string()),
],
vec![vec![
Expression::Name("baz".to_string()),
Expression::Name("qux".to_string()),
]],
),
)),
);
assert_parse_eq(
small_stmt(make_strspan("foo = bar = baz")),
Ok((
make_strspan(""),
Statement::Assignment(
vec![Expression::Name("foo".to_string())],
vec![
vec![Expression::Name("bar".to_string())],
vec![Expression::Name("baz".to_string())],
],
),
)),
);
}
#[test]
fn test_with() {
assert_parse_eq(
with_stmt(make_strspan("with foo:\n del bar"), 0),
Ok((
make_strspan(""),
CompoundStatement::With(
vec![(Expression::Name("foo".to_string()), None)],
vec![Statement::Del(vec![Expression::Name("bar".to_string())])],
),
)),
);
assert_parse_eq(
with_stmt(make_strspan("with foo as bar:\n del baz"), 0),
Ok((
make_strspan(""),
CompoundStatement::With(
vec![(
Expression::Name("foo".to_string()),
Some(Expression::Name("bar".to_string())),
)],
vec![Statement::Del(vec![Expression::Name("baz".to_string())])],
),
)),
);
}
#[test]
fn test_try() {
assert_parse_eq(
try_stmt(make_strspan("try:\n del foo\nexcept Bar:\n del baz"), 0),
Ok((
make_strspan(""),
CompoundStatement::Try(Try {
try_block: vec![Statement::Del(vec![Expression::Name("foo".to_string())])],
except_clauses: vec![(
Expression::Name("Bar".to_string()),
None,
vec![Statement::Del(vec![Expression::Name("baz".to_string())])],
)],
last_except: vec![],
else_block: vec![],
finally_block: vec![],
}),
)),
);
assert_parse_eq(
try_stmt(make_strspan("try:\n del foo\nexcept:\n del baz"), 0),
Ok((
make_strspan(""),
CompoundStatement::Try(Try {
try_block: vec![Statement::Del(vec![Expression::Name("foo".to_string())])],
except_clauses: vec![],
last_except: vec![Statement::Del(vec![Expression::Name("baz".to_string())])],
else_block: vec![],
finally_block: vec![],
}),
)),
);
assert_parse_eq(
try_stmt(make_strspan("try:\n del foo\nelse:\n del baz"), 0),
Ok((
make_strspan(""),
CompoundStatement::Try(Try {
try_block: vec![Statement::Del(vec![Expression::Name("foo".to_string())])],
except_clauses: vec![],
last_except: vec![],
else_block: vec![Statement::Del(vec![Expression::Name("baz".to_string())])],
finally_block: vec![],
}),
)),
);
assert_parse_eq(
try_stmt(make_strspan("try:\n del foo\nfinally:\n del baz"), 0),
Ok((
make_strspan(""),
CompoundStatement::Try(Try {
try_block: vec![Statement::Del(vec![Expression::Name("foo".to_string())])],
except_clauses: vec![],
last_except: vec![],
else_block: vec![],
finally_block: vec![Statement::Del(vec![Expression::Name("baz".to_string())])],
}),
)),
);
}
#[test]
fn test_import() {
assert_parse_eq(
statement(make_strspan("import foo"), 0),
Ok((
make_strspan(""),
vec![Statement::Import(Import::Import {
names: vec![(vec!["foo".to_string()], None)],
})],
)),
);
}
#[test]
fn test_import_from() {
assert_parse_eq(
statement(make_strspan("from . import foo"), 0),
Ok((
make_strspan(""),
vec![Statement::Import(Import::ImportFrom {
leading_dots: 1,
path: vec![],
names: vec![("foo".to_string(), None)],
})],
)),
);
assert_parse_eq(
statement(make_strspan("from . import foo as bar"), 0),
Ok((
make_strspan(""),
vec![Statement::Import(Import::ImportFrom {
leading_dots: 1,
path: vec![],
names: vec![("foo".to_string(), Some("bar".to_string()))],
})],
)),
);
assert_parse_eq(
statement(make_strspan("from qux import foo"), 0),
Ok((
make_strspan(""),
vec![Statement::Import(Import::ImportFrom {
leading_dots: 0,
path: vec!["qux".to_string()],
names: vec![("foo".to_string(), None)],
})],
)),
);
assert_parse_eq(
statement(make_strspan("from qux import foo as bar"), 0),
Ok((
make_strspan(""),
vec![Statement::Import(Import::ImportFrom {
leading_dots: 0,
path: vec!["qux".to_string()],
names: vec![("foo".to_string(), Some("bar".to_string()))],
})],
)),
);
assert_parse_eq(
statement(make_strspan("from .qux import foo"), 0),
Ok((
make_strspan(""),
vec![Statement::Import(Import::ImportFrom {
leading_dots: 1,
path: vec!["qux".to_string()],
names: vec![("foo".to_string(), None)],
})],
)),
);
assert_parse_eq(
statement(make_strspan("from .qux import foo as bar"), 0),
Ok((
make_strspan(""),
vec![Statement::Import(Import::ImportFrom {
leading_dots: 1,
path: vec!["qux".to_string()],
names: vec![("foo".to_string(), Some("bar".to_string()))],
})],
)),
);
}
}