use std::marker::PhantomData;
use helpers::*;
use functions::varargslist;
use bytes::bytes;
use strings::string;
use numbers::number;
use ast::*;
#[derive(Clone, Debug, PartialEq)]
enum TestlistCompReturn {
Comp(Box<SetItem>, Vec<ComprehensionChunk>), Lit(Vec<SetItem>), Single(SetItem), }
pub(crate) struct ExpressionParser<ANS: AreNewlinesSpaces> {
_phantom: PhantomData<ANS>,
}
impl<ANS: AreNewlinesSpaces> ExpressionParser<ANS> {
named!(pub test<StrSpan, Box<Expression>>,
alt!(
call!(Self::lambdef)
| do_parse!(
left: call!(Self::or_test) >>
right: opt!(do_parse!(
ws_auto!(keyword!("if")) >>
cond: call!(Self::or_test) >>
ws_auto!(keyword!("else")) >>
right: call!(Self::test) >> (
(cond, right)
)
)) >> (
match right {
None => left,
Some((cond, right)) => Box::new(Expression::Ternary(left, cond, right)),
}
)
)
)
);
named!(test_nocond<StrSpan, Box<Expression>>,
alt!(
call!(Self::lambdef_nocond)
| call!(Self::or_test)
)
);
named!(lambdef<StrSpan, Box<Expression>>,
ws_auto!(do_parse!(
keyword!("lambda") >>
args: opt!(varargslist) >>
spaces!() >>
char!(':') >>
spaces!() >>
code: call!(Self::test) >> (
Box::new(Expression::Lambdef(args.unwrap_or_default(), code))
)
))
);
named!(lambdef_nocond<StrSpan, Box<Expression>>,
do_parse!(
keyword!("lambda") >>
args: opt!(varargslist) >>
char!(':') >>
code: call!(Self::test_nocond) >> (
Box::new(Expression::Lambdef(args.unwrap_or_default(), code))
)
)
);
}
macro_rules! bop {
( $name:ident, $child:path, $tag:ident!($($args:tt)*) ) => {
named!(pub $name<StrSpan, Box<Expression>>,
do_parse!(
first: call!($child) >>
r: fold_many0!(
tuple!(
delimited!(spaces!(), $tag!($($args)*), spaces!()),
$child
),
(first, Vec::new()),
|(first, mut acc):(_,Vec<_>), (op, f):(_,Box<_>)| { acc.push((op, *f)); (first, acc) }
) >> ({
let (first, rest) = r;
match rest.len() {
0 => first,
1 => {
let (op, ref rhs) = rest[0];
Box::new(Expression::Bop(op, first, Box::new(rhs.clone())))
}
_ => Box::new(Expression::MultiBop(first, rest))
}
})
)
);
}
}
impl<ANS: AreNewlinesSpaces> ExpressionParser<ANS> {
bop!(or_test, Self::and_test, alt!(
keyword!("or") => { |_| Bop::Or }
));
bop!(and_test, Self::not_test, alt!(
keyword!("and") => { |_| Bop::And }
));
named!(not_test<StrSpan, Box<Expression>>,
alt!(
preceded!(tuple!(keyword!("not"), spaces!()), call!(Self::not_test)) => { |e| Box::new(Expression::Uop(Uop::Not, e)) }
| call!(Self::comparison)
)
);
bop!(comparison, Self::expr, alt!(
tag!("==") => { |_| Bop::Eq }
| tag!("<=") => { |_| Bop::Leq }
| tag!(">=") => { |_| Bop::Geq }
| char!('<') => { |_| Bop::Lt }
| char!('>') => { |_| Bop::Gt }
| tag!("!=") => { |_| Bop::Neq }
| tag!("in") => { |_| Bop::In }
| tuple!(tag!("not"), space_sep!(), keyword!("in")) => { |_| Bop::NotIn }
| tuple!(tag!("is"), space_sep!(), keyword!("not")) => { |_| Bop::IsNot }
| tuple!(tag!("is"), space_sep!()) => { |_| Bop::Is }
));
named!(pub star_expr<StrSpan, Box<Expression>>,
do_parse!(char!('*') >> spaces!() >> e: call!(Self::expr) >> (Box::new(Expression::Star(e))))
);
bop!(expr, Self::xor_expr, alt!(
char!('|') => { |_| Bop::BitOr }
));
bop!(xor_expr, Self::and_expr, alt!(
char!('^') => { |_| Bop::BitXor }
));
bop!(and_expr, Self::shift_expr, alt!(
char!('&') => { |_| Bop::BitAnd }
));
bop!(shift_expr, Self::arith_expr, alt!(
tag!("<<") => { |_| Bop::Lshift }
| tag!(">>") => { |_| Bop::Rshift }
));
bop!(arith_expr, Self::term, alt!(
char!('+') => { |_| Bop::Add }
| char!('-') => { |_| Bop::Sub }
));
bop!(term, Self::factor, alt!(
char!('*') => { |_| Bop::Mult }
| char!('@') => { |_| Bop::Matmult }
| char!('%') => { |_| Bop::Mod }
| tag!("//") => { |_| Bop::Floordiv }
| char!('/') => { |_| Bop::Div }
));
named!(factor<StrSpan, Box<Expression>>,
alt!(
do_parse!(spaces!() >> char!('+') >> spaces!() >> e: call!(Self::factor) >> (Box::new(Expression::Uop(Uop::Plus, e))))
| do_parse!(spaces!() >> char!('-') >> spaces!() >> e: call!(Self::factor) >> (Box::new(Expression::Uop(Uop::Minus, e))))
| do_parse!(spaces!() >> char!('~') >> spaces!() >> e: call!(Self::factor) >> (Box::new(Expression::Uop(Uop::Invert, e))))
| call!(Self::power)
)
);
named!(power<StrSpan, Box<Expression>>,
do_parse!(
lhs: call!(Self::atom_expr) >>
rhs: opt!(do_parse!(spaces!() >> tag!("**") >> spaces!() >> e: call!(Self::factor) >> (e))) >> (
match rhs {
Some(r) => Box::new(Expression::Bop(Bop::Power, lhs, r)),
None => lhs,
}
)
)
);
} enum Trailer { Call(Vec<Argument>), Subscript(Vec<Subscript>), Attribute(Name) }
impl<ANS: AreNewlinesSpaces> ExpressionParser<ANS> {
named!(atom_expr<StrSpan, Box<Expression>>,
do_parse!(
lhs: call!(Self::atom) >>
trailers: fold_many0!(
ws_auto!(alt!(
delimited!(char!('('), ws_comm!(call!(ExpressionParser::<NewlinesAreSpaces>::arglist)), char!(')')) => { |args| Trailer::Call(args) }
| delimited!(char!('['), ws_comm!(separated_list!(char!(','), call!(ExpressionParser::<NewlinesAreSpaces>::subscript))), char!(']')) => { |i| Trailer::Subscript(i) }
| preceded!(ws_auto!(char!('.')), name) => { |name| Trailer::Attribute(name) }
)),
lhs,
|acc, item| Box::new(match item {
Trailer::Call(args) => Expression::Call(acc, args),
Trailer::Subscript(i) => Expression::Subscript(acc, i),
Trailer::Attribute(name) => Expression::Attribute(acc, name),
})
) >> (
trailers
)
)
);
named!(atom<StrSpan, Box<Expression>>,
map!(alt!(
tag!("...") => { |_| Expression::Ellipsis }
| keyword!("None") => { |_| Expression::None }
| keyword!("True") => { |_| Expression::True }
| keyword!("False") => { |_| Expression::False }
| separated_nonempty_list!(spaces!(), string) => { |s| Expression::String(s) }
| separated_nonempty_list!(spaces!(), bytes) => { |v| {
let mut v2 = Vec::new();
for b in v { v2.extend(b) }
Expression::Bytes(v2)
}}
| number
| name => { |n| Expression::Name(n) }
| tuple!(char!('['), ws_comm!(opt!(char!(' '))), char!(']')) => { |_| Expression::ListLiteral(vec![]) }
| tuple!(char!('{'), ws_comm!(opt!(char!(' '))), char!('}')) => { |_| Expression::DictLiteral(vec![]) }
| tuple!(char!('('), ws_comm!(opt!(char!(' '))), char!(')')) => { |_| Expression::TupleLiteral(vec![]) }
| delimited!(char!('{'), ws_comm!(map!(
call!(ExpressionParser::<NewlinesAreSpaces>::dictorsetmaker), |e:Box<_>| *e
)), char!('}'))
| map_opt!(ws_auto!(delimited!(char!('('), ws_comm!(
call!(ExpressionParser::<NewlinesAreSpaces>::testlist_comp)
), char!(')'))), |ret| {
match ret {
TestlistCompReturn::Comp(e, comp) => Some(Expression::Generator(e, comp)),
TestlistCompReturn::Lit(v) => Some(Expression::TupleLiteral(v)),
TestlistCompReturn::Single(SetItem::Unique(e)) => Some(e),
TestlistCompReturn::Single(SetItem::Star(_)) => None,
}
})
| delimited!(char!('('), ws_comm!(
call!(ExpressionParser::<NewlinesAreSpaces>::yield_expr)
), char!(')'))
| delimited!(char!('['), ws_comm!(
call!(ExpressionParser::<NewlinesAreSpaces>::testlist_comp)
), char!(']')) => { |ret| {
match ret {
TestlistCompReturn::Comp(e, comp) => Expression::ListComp(e, comp),
TestlistCompReturn::Lit(v) => Expression::ListLiteral(v),
TestlistCompReturn::Single(e) => Expression::ListLiteral(vec![e]),
}}
}
), |e| Box::new(e))
);
named!(testlist_comp<StrSpan, TestlistCompReturn>,
do_parse!(
first: ws_auto!(alt!(
call!(Self::test) => { |e: Box<_>| SetItem::Unique(*e) }
| preceded!(char!('*'), call!(Self::expr)) => { |e: Box<_>| SetItem::Star(*e) }
)) >>
r: alt!(
call!(Self::comp_for) => { |comp| TestlistCompReturn::Comp(Box::new(first), comp) }
| opt!(delimited!(
ws_auto!(char!(',')),
separated_list!(ws_auto!(char!(',')),
alt!(
call!(Self::test) => { |e: Box<_>| SetItem::Unique(*e) }
| preceded!(char!('*'), call!(Self::expr)) => { |e: Box<_>| SetItem::Star(*e) }
)
),
ws_auto!(opt!(char!(',')))
)) => { |v: Option<Vec<SetItem>>| {
match v {
Some(v) => {
let mut v = v;
v.insert(0, first);
TestlistCompReturn::Lit(v)
},
None => TestlistCompReturn::Single(first),
}
}}
) >> (
r
)
)
);
named!(subscript<StrSpan, Subscript>,
ws_comm!(alt!(
preceded!(char!(':'), call!(Self::subscript_trail, None))
| do_parse!(
first: call!(Self::test) >>
r: opt!(ws_comm!(preceded!(char!(':'), call!(Self::subscript_trail, Some(*first.clone()))))) >> ( r.unwrap_or(Subscript::Simple(*first))
)
)
))
);
named_args!(subscript_trail(first: Option<Expression>) <StrSpan, Subscript>,
do_parse!(
second: opt!(call!(Self::test)) >>
third: opt!(preceded!(char!(':'), opt!(call!(Self::test)))) >> ({
let second = second.map(|s| *s);
match third {
None => Subscript::Double(first, second),
Some(None) => Subscript::Triple(first, second, None),
Some(Some(t)) => Subscript::Triple(first, second, Some(*t)),
}
})
)
);
named!(pub exprlist<StrSpan, Vec<Expression>>,
separated_nonempty_list!(ws_auto!(char!(',')), map!(alt!(call!(Self::expr)|call!(Self::star_expr)), |e| *e))
);
named!(pub testlist<StrSpan, Vec<Expression>>,
separated_nonempty_list!(ws_auto!(char!(',')), map!(call!(Self::test), |e| *e))
);
named!(pub possibly_empty_testlist<StrSpan, Vec<Expression>>,
alt!(
tuple!(separated_nonempty_list!(ws_auto!(char!(',')), map!(call!(Self::test), |e:Box<_>| *e)), opt!(ws_auto!(char!(',')))) => { |(mut e, comma):(Vec<_>, _)|
match (e.len(), comma) {
(0, _) => unreachable!(),
(1, Some(_)) => vec![Expression::TupleLiteral(vec![SetItem::Unique(e.remove(0))])], (1, None) => vec![e.remove(0)], (_, _) => e,
}
}
| tag!("") => { |_| Vec::new() }
)
);
}
impl ExpressionParser<NewlinesAreSpaces> {
named!(dictorsetmaker<StrSpan, Box<Expression>>,
ws_comm!(alt!(
do_parse!(
tag!("**") >>
e: map!(call!(Self::expr), |e: Box<_>| DictItem::Star(*e)) >>
r: call!(Self::dictmaker, e) >>
(r)
)
| do_parse!(
tag!("*") >>
e: map!(call!(Self::expr), |e: Box<_>| SetItem::Star(*e)) >>
r: call!(Self::setmaker, e) >>
(r)
)
| do_parse!(
key: call!(Self::test) >>
r: alt!(
do_parse!(
char!(':') >>
item: map!(call!(Self::test), |value: Box<_>| DictItem::Unique(*key.clone(), *value)) >> r: call!(Self::dictmaker, item) >>
(r)
)
| call!(Self::setmaker, SetItem::Unique(*key))
) >>
(r)
)
))
);
named_args!(dictmaker(item1: DictItem) <StrSpan, Box<Expression>>,
map!(
opt!(alt!(
ws_comm!(delimited!(char!(','), separated_list!(char!(','), call!(Self::dictitem)), opt!(ws_comm!(char!(','))))) => { |v: Vec<_>| {
let mut v = v;
v.insert(0, item1.clone()); Box::new(Expression::DictLiteral(v))
}}
| preceded!(peek!(keyword!("for")), call!(Self::comp_for)) => { |comp| {
Box::new(Expression::DictComp(Box::new(item1.clone()), comp)) }}
)),
|rest| {
match rest {
Some(r) => r,
None => Box::new(Expression::DictLiteral(vec![item1])),
}
}
)
);
named_args!(setmaker(item1: SetItem) <StrSpan, Box<Expression>>,
do_parse!(
rest:opt!(alt!(
ws_comm!(delimited!(char!(','), separated_list!(char!(','), call!(Self::setitem)), opt!(ws_comm!(char!(','))))) => { |v: Vec<_>| {
let mut v = v;
v.insert(0, item1.clone()); Box::new(Expression::SetLiteral(v))
}}
| call!(Self::comp_for) => { |comp| {
Box::new(Expression::SetComp(Box::new(item1.clone()), comp)) }}
)) >> (
match rest {
Some(r) => r,
None => Box::new(Expression::SetLiteral(vec![item1])),
}
)
)
);
named!(dictitem<StrSpan, DictItem>,
ws_comm!(alt!(
preceded!(tag!("**"), call!(Self::expr)) => { |e:Box<_>| DictItem::Star(*e) }
| tuple!(call!(Self::test), char!(':'), call!(Self::test)) => { |(e1,_,e2): (Box<_>,_,Box<_>)| DictItem::Unique(*e1,*e2) }
))
);
named!(setitem<StrSpan, SetItem>,
ws_comm!(alt!(
preceded!(tag!("*"), call!(Self::expr)) => { |e:Box<_>| SetItem::Star(*e) }
|call!(Self::test) => { |e:Box<_>| SetItem::Unique(*e) }
))
);
}
impl<ANS: AreNewlinesSpaces> ExpressionParser<ANS> {
named!(pub arglist<StrSpan, Vec<Argument>>,
ws_comm!(do_parse!(
args: separated_list!(ws_comm!(char!(',')),
alt!(
preceded!(tag!("**"), call!(Self::test)) => { |kwargs: Box<_>| Argument::Kwargs(*kwargs) }
| preceded!(char!('*'), call!(Self::test)) => { |args: Box<_>| Argument::Starargs(*args) }
| do_parse!(
name: name >>
value: preceded!(char!('='), call!(Self::test)) >> (
Argument::Keyword(name.to_string(), *value)
)
)
| do_parse!(
test1: call!(Self::test) >>
next: opt!(ws_comm!(alt!(call!(Self::comp_for)))) >> (
match next {
Some(e) => Argument::Positional(Expression::Generator(Box::new(SetItem::Unique(*test1)), e)),
None => Argument::Positional(*test1)
}
)
)
)
) >>
opt!(ws_comm!(char!(','))) >>
(args)
))
);
named_args!(comp_iter(acc: Vec<ComprehensionChunk>) <StrSpan, Vec<ComprehensionChunk>>,
alt!(
call!(Self::comp_for2, acc.clone()) | call!(Self::comp_if, acc)
)
);
named_args!(opt_comp_iter(acc: Vec<ComprehensionChunk>) <StrSpan, Vec<ComprehensionChunk>>,
map!(opt!(call!(Self::comp_iter, acc.clone())), |r| r.unwrap_or(acc)) );
named!(comp_for<StrSpan, Vec<ComprehensionChunk>>,
call!(Self::comp_for2, Vec::new())
);
named_args!(comp_for2(acc: Vec<ComprehensionChunk>) <StrSpan, Vec<ComprehensionChunk>>,
do_parse!(
async: map!(opt!(terminated!(tag!("async"), space_sep!())), |o| o.is_some()) >>
keyword!("for") >>
spaces!() >>
item: call!(Self::exprlist) >>
spaces!() >>
keyword!("in") >>
spaces!() >>
iterator: map!(call!(Self::or_test), |e| *e) >>
spaces!() >>
r: call!(Self::opt_comp_iter, { let mut acc = acc; acc.push(ComprehensionChunk::For { async, item, iterator }); acc }) >> (
r
)
)
);
named_args!(comp_if(acc: Vec<ComprehensionChunk>) <StrSpan, Vec<ComprehensionChunk>>,
do_parse!(
keyword!("if") >>
spaces!() >>
cond: map!(call!(Self::test_nocond), |e| *e) >>
spaces!() >>
r: call!(Self::opt_comp_iter, { let mut acc = acc; acc.push(ComprehensionChunk::If { cond }); acc }) >> (
r
)
)
);
named!(pub yield_expr<StrSpan, Expression>,
ws_auto!(preceded!(
keyword!("yield"),
ws_auto!(alt!(
preceded!(ws_auto!(keyword!("from")), call!(Self::test)) => { |e| Expression::YieldFrom(e) }
| call!(Self::testlist) => { |e| Expression::Yield(e) }
| tag!("") => { |_| Expression::Yield(Vec::new()) }
))
))
);
}
#[cfg(test)]
mod tests {
use helpers::{NewlinesAreNotSpaces, make_strspan, assert_parse_eq};
use super::*;
#[cfg(feature="wtf8")]
fn new_pystring(prefix: &str, s: &str) -> PyString {
PyString { prefix: prefix.to_string(), content: PyStringContent::from_str(s) }
}
#[cfg(not(feature="wtf8"))]
fn new_pystring(prefix: &str, s: &str) -> PyString {
PyString { prefix: prefix.to_string(), content: s.to_string() }
}
#[test]
fn test_string() {
let atom = ExpressionParser::<NewlinesAreNotSpaces>::atom;
assert_parse_eq(atom(make_strspan(r#""foo" "#)), Ok((make_strspan(" "),
Box::new(Expression::String(vec![new_pystring("", "foo")])))
));
assert_parse_eq(atom(make_strspan(r#""foo" "bar""#)), Ok((make_strspan(""),
Box::new(Expression::String(vec![new_pystring("", "foo"), new_pystring("", "bar")])))
));
assert_parse_eq(atom(make_strspan(r#""fo\"o" "#)), Ok((make_strspan(" "),
Box::new(Expression::String(vec![new_pystring("", "fo\"o")])))
));
assert_parse_eq(atom(make_strspan(r#""fo"o" "#)), Ok((make_strspan(r#"o" "#),
Box::new(Expression::String(vec![new_pystring("", "fo")])))
));
assert_parse_eq(atom(make_strspan(r#""fo \" o" "#)), Ok((make_strspan(" "),
Box::new(Expression::String(vec![new_pystring("", "fo \" o")])))
));
assert_parse_eq(atom(make_strspan(r#"'fo \' o' "#)), Ok((make_strspan(" "),
Box::new(Expression::String(vec![new_pystring("", "fo ' o")])))
));
assert_parse_eq(atom(make_strspan(r#"r'fo \' o' "#)), Ok((make_strspan(" "),
Box::new(Expression::String(vec![new_pystring("r", "fo \\' o")])))
));
assert_parse_eq(atom(make_strspan(r#"'\x8a'"#)), Ok((make_strspan(""),
Box::new(Expression::String(vec![new_pystring("", "\u{8a}")])))
));
assert_parse_eq(atom(make_strspan(r#"'\N{snowman}'"#)), Ok((make_strspan(""),
Box::new(Expression::String(vec![new_pystring("", "☃")])))
));
}
#[test]
fn test_triple_quotes_string() {
let atom = ExpressionParser::<NewlinesAreNotSpaces>::atom;
assert_parse_eq(atom(make_strspan(r#"'''fo ' o''' "#)), Ok((make_strspan(" "), Box::new(Expression::String(vec![new_pystring("", "fo ' o")])))));
}
#[test]
fn test_bytes() {
let atom = ExpressionParser::<NewlinesAreNotSpaces>::atom;
assert_parse_eq(atom(make_strspan(r#"b"foo" "#)), Ok((make_strspan(" "),
Box::new(Expression::Bytes(b"foo".to_vec())))
));
assert_parse_eq(atom(make_strspan(r#"b"foo" "bar""#)), Ok((make_strspan(""),
Box::new(Expression::Bytes(b"foobar".to_vec())))
));
assert_parse_eq(atom(make_strspan(r#"b"fo\"o" "#)), Ok((make_strspan(" "),
Box::new(Expression::Bytes(b"fo\"o".to_vec())))
));
assert_parse_eq(atom(make_strspan(r#"b"fo"o" "#)), Ok((make_strspan(r#"o" "#),
Box::new(Expression::Bytes(b"fo".to_vec())))
));
assert_parse_eq(atom(make_strspan(r#"b"fo \" o" "#)), Ok((make_strspan(" "),
Box::new(Expression::Bytes(b"fo \" o".to_vec())))
));
assert_parse_eq(atom(make_strspan(r#"b'fo \' o' "#)), Ok((make_strspan(" "),
Box::new(Expression::Bytes(b"fo ' o".to_vec())))
));
assert_parse_eq(atom(make_strspan(r#"br'fo \' o' "#)), Ok((make_strspan(" "),
Box::new(Expression::Bytes(b"fo \\' o".to_vec())))
));
}
#[test]
fn test_ternary() {
let test = ExpressionParser::<NewlinesAreNotSpaces>::test;
assert_parse_eq(test(make_strspan("foo if bar else baz")), Ok((make_strspan(""),
Box::new(Expression::Ternary(
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Name("bar".to_string())),
Box::new(Expression::Name("baz".to_string())),
))
)));
}
#[test]
fn test_bool_ops() {
let expr = ExpressionParser::<NewlinesAreNotSpaces>::expr;
assert_parse_eq(expr(make_strspan("foo & bar | baz ^ qux")), Ok((make_strspan(""),
Box::new(Expression::Bop(Bop::BitOr,
Box::new(Expression::Bop(Bop::BitAnd,
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Name("bar".to_string())),
)),
Box::new(Expression::Bop(Bop::BitXor,
Box::new(Expression::Name("baz".to_string())),
Box::new(Expression::Name("qux".to_string())),
)),
))
)));
assert_parse_eq(expr(make_strspan("foo | bar & baz ^ qux")), Ok((make_strspan(""),
Box::new(Expression::Bop(Bop::BitOr,
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Bop(Bop::BitXor,
Box::new(Expression::Bop(Bop::BitAnd,
Box::new(Expression::Name("bar".to_string())),
Box::new(Expression::Name("baz".to_string())),
)),
Box::new(Expression::Name("qux".to_string())),
)),
))
)));
}
#[test]
fn test_shift_expr() {
let shift_expr = ExpressionParser::<NewlinesAreNotSpaces>::shift_expr;
assert_parse_eq(shift_expr(make_strspan("foo << bar")), Ok((make_strspan(""),
Box::new(Expression::Bop(Bop::Lshift,
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Name("bar".to_string())),
))
)));
assert_parse_eq(shift_expr(make_strspan("foo >> bar")), Ok((make_strspan(""),
Box::new(Expression::Bop(Bop::Rshift,
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Name("bar".to_string())),
))
)));
}
#[test]
fn test_arith_expr() {
let arith_expr = ExpressionParser::<NewlinesAreNotSpaces>::arith_expr;
assert_parse_eq(arith_expr(make_strspan("foo + bar")), Ok((make_strspan(""),
Box::new(Expression::Bop(Bop::Add,
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Name("bar".to_string())),
))
)));
assert_parse_eq(arith_expr(make_strspan("foo * bar + baz")), Ok((make_strspan(""),
Box::new(Expression::Bop(Bop::Add,
Box::new(Expression::Bop(Bop::Mult,
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Name("bar".to_string())),
)),
Box::new(Expression::Name("baz".to_string())),
))
)));
assert_parse_eq(arith_expr(make_strspan("foo + bar * baz")), Ok((make_strspan(""),
Box::new(Expression::Bop(Bop::Add,
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Bop(Bop::Mult,
Box::new(Expression::Name("bar".to_string())),
Box::new(Expression::Name("baz".to_string())),
)),
))
)));
}
#[test]
fn test_term() {
let term = ExpressionParser::<NewlinesAreNotSpaces>::term;
assert_parse_eq(term(make_strspan("foo * bar")), Ok((make_strspan(""),
Box::new(Expression::Bop(Bop::Mult,
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Name("bar".to_string())),
))
)));
assert_parse_eq(term(make_strspan("foo ** bar * baz")), Ok((make_strspan(""),
Box::new(Expression::Bop(Bop::Mult,
Box::new(Expression::Bop(Bop::Power,
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Name("bar".to_string())),
)),
Box::new(Expression::Name("baz".to_string())),
))
)));
assert_parse_eq(term(make_strspan("foo * bar ** baz")), Ok((make_strspan(""),
Box::new(Expression::Bop(Bop::Mult,
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Bop(Bop::Power,
Box::new(Expression::Name("bar".to_string())),
Box::new(Expression::Name("baz".to_string())),
)),
))
)));
}
#[test]
fn test_power() {
let factor = ExpressionParser::<NewlinesAreNotSpaces>::factor;
assert_parse_eq(factor(make_strspan("foo ** bar")), Ok((make_strspan(""),
Box::new(Expression::Bop(Bop::Power,
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Name("bar".to_string())),
))
)));
assert_parse_eq(factor(make_strspan("foo ** + bar")), Ok((make_strspan(""),
Box::new(Expression::Bop(Bop::Power,
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Uop(Uop::Plus,
Box::new(Expression::Name("bar".to_string())),
)),
))
)));
}
#[test]
fn test_bool() {
let test = ExpressionParser::<NewlinesAreNotSpaces>::test;
assert_parse_eq(test(make_strspan("foo and bar")), Ok((make_strspan(""),
Box::new(Expression::Bop(Bop::And,
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Name("bar".to_string())),
))
)));
assert_parse_eq(test(make_strspan("foo and + bar")), Ok((make_strspan(""),
Box::new(Expression::Bop(Bop::And,
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Uop(Uop::Plus,
Box::new(Expression::Name("bar".to_string())),
)),
))
)));
}
#[test]
fn test_not() {
let test = ExpressionParser::<NewlinesAreNotSpaces>::test;
assert_parse_eq(test(make_strspan("not foo")), Ok((make_strspan(""),
Box::new(Expression::Uop(Uop::Not,
Box::new(Expression::Name("foo".to_string())),
))
)));
assert_parse_eq(test(make_strspan("not not foo")), Ok((make_strspan(""),
Box::new(Expression::Uop(Uop::Not,
Box::new(Expression::Uop(Uop::Not,
Box::new(Expression::Name("foo".to_string())),
))
))
)));
}
#[test]
fn test_parentheses1() {
let test = ExpressionParser::<NewlinesAreNotSpaces>::test;
assert_parse_eq(test(make_strspan("(foo)")), Ok((make_strspan(""),
Box::new(Expression::Name("foo".to_string())),
)));
}
#[test]
fn test_parentheses2() {
let test = ExpressionParser::<NewlinesAreNotSpaces>::test;
assert_parse_eq(test(make_strspan("(foo and bar)")), Ok((make_strspan(""),
Box::new(Expression::Bop(Bop::And,
Box::new(Expression::Name("foo".to_string())),
Box::new(Expression::Name("bar".to_string())),
))
)));
}
#[test]
fn test_call_noarg() {
let atom_expr = ExpressionParser::<NewlinesAreNotSpaces>::atom_expr;
assert_parse_eq(atom_expr(make_strspan("foo()")), Ok((make_strspan(""),
Box::new(Expression::Call(
Box::new(Expression::Name("foo".to_string())),
vec![],
))
)));
}
#[test]
fn test_call_positional_expr1() {
let atom_expr = ExpressionParser::<NewlinesAreNotSpaces>::atom_expr;
assert_parse_eq(atom_expr(make_strspan("foo(bar and baz)")), Ok((make_strspan(""),
Box::new(Expression::Call(
Box::new(Expression::Name("foo".to_string())),
vec![
Argument::Positional(
Expression::Bop(Bop::And,
Box::new(Expression::Name("bar".to_string())),
Box::new(Expression::Name("baz".to_string())),
)
),
],
))
)));
}
#[test]
fn test_call_positional_expr2() {
let atom_expr = ExpressionParser::<NewlinesAreNotSpaces>::atom_expr;
assert_parse_eq(atom_expr(make_strspan("foo(bar*baz)")), Ok((make_strspan(""),
Box::new(Expression::Call(
Box::new(Expression::Name("foo".to_string())),
vec![
Argument::Positional(
Expression::Bop(Bop::Mult,
Box::new(Expression::Name("bar".to_string())),
Box::new(Expression::Name("baz".to_string())),
)
),
],
))
)));
}
#[test]
fn test_call_positional() {
let atom_expr = ExpressionParser::<NewlinesAreNotSpaces>::atom_expr;
assert_parse_eq(atom_expr(make_strspan("foo(bar)")), Ok((make_strspan(""),
Box::new(Expression::Call(
Box::new(Expression::Name("foo".to_string())),
vec![
Argument::Positional(
Expression::Name("bar".to_string())
),
],
))
)));
assert_parse_eq(atom_expr(make_strspan("foo(bar, baz)")), Ok((make_strspan(""),
Box::new(Expression::Call(
Box::new(Expression::Name("foo".to_string())),
vec![
Argument::Positional(
Expression::Name("bar".to_string())
),
Argument::Positional(
Expression::Name("baz".to_string())
),
],
))
)));
assert_parse_eq(atom_expr(make_strspan("foo(bar, baz, *qux)")), Ok((make_strspan(""),
Box::new(Expression::Call(
Box::new(Expression::Name("foo".to_string())),
vec![
Argument::Positional(
Expression::Name("bar".to_string())
),
Argument::Positional(
Expression::Name("baz".to_string())
),
Argument::Starargs(
Expression::Name("qux".to_string())
),
],
))
)));
assert_parse_eq(atom_expr(make_strspan("foo(bar, *baz, qux)")), Ok((make_strspan(""),
Box::new(Expression::Call(
Box::new(Expression::Name("foo".to_string())),
vec![
Argument::Positional(
Expression::Name("bar".to_string())
),
Argument::Starargs(
Expression::Name("baz".to_string())
),
Argument::Positional(
Expression::Name("qux".to_string())
),
],
))
)));
assert_parse_eq(atom_expr(make_strspan("foo(bar, *baz, *qux)")), Ok((make_strspan(""),
Box::new(Expression::Call(
Box::new(Expression::Name("foo".to_string())),
vec![
Argument::Positional(
Expression::Name("bar".to_string())
),
Argument::Starargs(
Expression::Name("baz".to_string())
),
Argument::Starargs(
Expression::Name("qux".to_string())
),
],
))
)));
}
#[test]
fn test_call_keyword() {
let atom_expr = ExpressionParser::<NewlinesAreNotSpaces>::atom_expr;
assert_parse_eq(atom_expr(make_strspan("foo(bar1=bar2)")), Ok((make_strspan(""),
Box::new(Expression::Call(
Box::new(Expression::Name("foo".to_string())),
vec![
Argument::Keyword(
"bar1".to_string(), Expression::Name("bar2".to_string()),
),
],
))
)));
assert_parse_eq(atom_expr(make_strspan("foo(bar1=bar2, baz1=baz2)")), Ok((make_strspan(""),
Box::new(Expression::Call(
Box::new(Expression::Name("foo".to_string())),
vec![
Argument::Keyword(
"bar1".to_string(), Expression::Name("bar2".to_string()),
),
Argument::Keyword(
"baz1".to_string(), Expression::Name("baz2".to_string()),
),
],
))
)));
assert_parse_eq(atom_expr(make_strspan("foo(bar1=bar2, baz1=baz2, qux1=qux2)")), Ok((make_strspan(""),
Box::new(Expression::Call(
Box::new(Expression::Name("foo".to_string())),
vec![
Argument::Keyword(
"bar1".to_string(), Expression::Name("bar2".to_string()),
),
Argument::Keyword(
"baz1".to_string(), Expression::Name("baz2".to_string()),
),
Argument::Keyword(
"qux1".to_string(), Expression::Name("qux2".to_string()),
),
],
))
)));
assert_parse_eq(atom_expr(make_strspan("foo(bar1=bar2, baz1=baz2, **qux)")), Ok((make_strspan(""),
Box::new(Expression::Call(
Box::new(Expression::Name("foo".to_string())),
vec![
Argument::Keyword(
"bar1".to_string(), Expression::Name("bar2".to_string()),
),
Argument::Keyword(
"baz1".to_string(), Expression::Name("baz2".to_string()),
),
Argument::Kwargs(
Expression::Name("qux".to_string()),
),
],
))
)));
assert_parse_eq(atom_expr(make_strspan("foo(bar1=bar2, **baz, **qux)")), Ok((make_strspan(""),
Box::new(Expression::Call(
Box::new(Expression::Name("foo".to_string())),
vec![
Argument::Keyword(
"bar1".to_string(), Expression::Name("bar2".to_string()),
),
Argument::Kwargs(
Expression::Name("baz".to_string()),
),
Argument::Kwargs(
Expression::Name("qux".to_string()),
),
],
))
)));
assert_parse_eq(atom_expr(make_strspan("foo(bar1=bar2, **baz, qux1=qux2)")), Ok((make_strspan(""),
Box::new(Expression::Call(
Box::new(Expression::Name("foo".to_string())),
vec![
Argument::Keyword(
"bar1".to_string(), Expression::Name("bar2".to_string()),
),
Argument::Kwargs(
Expression::Name("baz".to_string()),
),
Argument::Keyword(
"qux1".to_string(), Expression::Name("qux2".to_string()),
),
],
))
)));
}
#[test]
fn test_subscript_simple() {
let atom_expr = ExpressionParser::<NewlinesAreNotSpaces>::atom_expr;
assert_parse_eq(atom_expr(make_strspan("foo[bar]")), Ok((make_strspan(""),
Box::new(Expression::Subscript(
Box::new(Expression::Name("foo".to_string())),
vec![
Subscript::Simple(
Expression::Name("bar".to_string()),
)
],
))
)));
}
#[test]
fn test_subscript_double() {
let atom_expr = ExpressionParser::<NewlinesAreNotSpaces>::atom_expr;
assert_parse_eq(atom_expr(make_strspan("foo[bar:baz]")), Ok((make_strspan(""),
Box::new(Expression::Subscript(
Box::new(Expression::Name("foo".to_string())),
vec![
Subscript::Double(
Some(Expression::Name("bar".to_string())),
Some(Expression::Name("baz".to_string())),
)
],
))
)));
assert_parse_eq(atom_expr(make_strspan("foo[bar:]")), Ok((make_strspan(""),
Box::new(Expression::Subscript(
Box::new(Expression::Name("foo".to_string())),
vec![
Subscript::Double(
Some(Expression::Name("bar".to_string())),
None,
)
],
))
)));
assert_parse_eq(atom_expr(make_strspan("foo[:baz]")), Ok((make_strspan(""),
Box::new(Expression::Subscript(
Box::new(Expression::Name("foo".to_string())),
vec![
Subscript::Double(
None,
Some(Expression::Name("baz".to_string())),
)
],
))
)));
assert_parse_eq(atom_expr(make_strspan("foo[:]")), Ok((make_strspan(""),
Box::new(Expression::Subscript(
Box::new(Expression::Name("foo".to_string())),
vec![
Subscript::Double(
None,
None,
)
],
))
)));
}
#[test]
fn test_subscript_triple() {
let atom_expr = ExpressionParser::<NewlinesAreNotSpaces>::atom_expr;
assert_parse_eq(atom_expr(make_strspan("foo[bar:baz:qux]")), Ok((make_strspan(""),
Box::new(Expression::Subscript(
Box::new(Expression::Name("foo".to_string())),
vec![
Subscript::Triple(
Some(Expression::Name("bar".to_string())),
Some(Expression::Name("baz".to_string())),
Some(Expression::Name("qux".to_string())),
)
],
))
)));
assert_parse_eq(atom_expr(make_strspan("foo[bar::qux]")), Ok((make_strspan(""),
Box::new(Expression::Subscript(
Box::new(Expression::Name("foo".to_string())),
vec![
Subscript::Triple(
Some(Expression::Name("bar".to_string())),
None,
Some(Expression::Name("qux".to_string())),
)
],
))
)));
assert_parse_eq(atom_expr(make_strspan("foo[bar::]")), Ok((make_strspan(""),
Box::new(Expression::Subscript(
Box::new(Expression::Name("foo".to_string())),
vec![
Subscript::Triple(
Some(Expression::Name("bar".to_string())),
None,
None,
)
],
))
)));
assert_parse_eq(atom_expr(make_strspan("foo[:baz:qux]")), Ok((make_strspan(""),
Box::new(Expression::Subscript(
Box::new(Expression::Name("foo".to_string())),
vec![
Subscript::Triple(
None,
Some(Expression::Name("baz".to_string())),
Some(Expression::Name("qux".to_string())),
)
],
))
)));
assert_parse_eq(atom_expr(make_strspan("foo[:baz:]")), Ok((make_strspan(""),
Box::new(Expression::Subscript(
Box::new(Expression::Name("foo".to_string())),
vec![
Subscript::Triple(
None,
Some(Expression::Name("baz".to_string())),
None,
)
],
))
)));
assert_parse_eq(atom_expr(make_strspan("foo[::]")), Ok((make_strspan(""),
Box::new(Expression::Subscript(
Box::new(Expression::Name("foo".to_string())),
vec![
Subscript::Triple(
None,
None,
None,
)
],
))
)));
}
#[test]
fn test_attribute() {
let atom_expr = ExpressionParser::<NewlinesAreNotSpaces>::atom_expr;
assert_parse_eq(atom_expr(make_strspan("foo.bar")), Ok((make_strspan(""),
Box::new(Expression::Attribute(
Box::new(Expression::Name("foo".to_string())),
"bar".to_string(),
))
)));
}
#[test]
fn test_call_and_attribute() {
let atom_expr = ExpressionParser::<NewlinesAreNotSpaces>::atom_expr;
assert_parse_eq(atom_expr(make_strspan("foo.bar().baz")), Ok((make_strspan(""),
Box::new(Expression::Attribute(
Box::new(Expression::Call(
Box::new(Expression::Attribute(
Box::new(Expression::Name("foo".to_string())),
"bar".to_string(),
)),
Vec::new()
)),
"baz".to_string(),
))
)));
}
#[test]
fn test_atom_expr() {
let atom_expr = ExpressionParser::<NewlinesAreNotSpaces>::atom_expr;
assert_parse_eq(atom_expr(make_strspan("foo.bar[baz]")), Ok((make_strspan(""),
Box::new(Expression::Subscript(
Box::new(Expression::Attribute(
Box::new(Expression::Name("foo".to_string())),
"bar".to_string(),
)),
vec![
Subscript::Simple(
Expression::Name("baz".to_string()),
)
],
))
)));
}
#[test]
fn test_call_newline() {
let atom_expr = ExpressionParser::<NewlinesAreNotSpaces>::atom_expr;
let ast =
Box::new(Expression::Call(
Box::new(Expression::Name("foo".to_string())),
vec![
Argument::Positional(
Expression::Name("bar".to_string())
),
Argument::Positional(
Expression::Bop(Bop::Add,
Box::new(Expression::Name("baz".to_string())),
Box::new(Expression::Name("qux".to_string())),
),
),
],
));
assert_parse_eq(atom_expr(make_strspan("foo(bar, baz + qux)")), Ok((make_strspan(""),
ast.clone()
)));
assert_parse_eq(atom_expr(make_strspan("foo(bar, baz +\nqux)")), Ok((make_strspan(""),
ast.clone()
)));
assert_parse_eq(atom_expr(make_strspan("foo(bar, baz +\n # foobar\nqux)")), Ok((make_strspan(""),
ast
)));
}
#[test]
fn test_setlit() {
let atom = ExpressionParser::<NewlinesAreNotSpaces>::atom;
assert_parse_eq(atom(make_strspan("{foo}")), Ok((make_strspan(""),
Box::new(Expression::SetLiteral(vec![
SetItem::Unique(Expression::Name("foo".to_string())),
]))
)));
assert_parse_eq(atom(make_strspan("{foo, bar, baz}")), Ok((make_strspan(""),
Box::new(Expression::SetLiteral(vec![
SetItem::Unique(Expression::Name("foo".to_string())),
SetItem::Unique(Expression::Name("bar".to_string())),
SetItem::Unique(Expression::Name("baz".to_string())),
]))
)));
assert_parse_eq(atom(make_strspan("{foo, *bar, baz}")), Ok((make_strspan(""),
Box::new(Expression::SetLiteral(vec![
SetItem::Unique(Expression::Name("foo".to_string())),
SetItem::Star(Expression::Name("bar".to_string())),
SetItem::Unique(Expression::Name("baz".to_string())),
]))
)));
}
#[test]
fn test_setlit_comment() {
let atom = ExpressionParser::<NewlinesAreNotSpaces>::atom;
assert_parse_eq(atom(make_strspan("{foo, \n #bar\n\n\n baz}")), Ok((make_strspan(""),
Box::new(Expression::SetLiteral(vec![
SetItem::Unique(Expression::Name("foo".to_string())),
SetItem::Unique(Expression::Name("baz".to_string())),
]))
)));
assert_parse_eq(atom(make_strspan("{\n #foo\n\n bar, baz}")), Ok((make_strspan(""),
Box::new(Expression::SetLiteral(vec![
SetItem::Unique(Expression::Name("bar".to_string())),
SetItem::Unique(Expression::Name("baz".to_string())),
]))
)));
assert_parse_eq(atom(make_strspan("{ bar, baz \n}")), Ok((make_strspan(""),
Box::new(Expression::SetLiteral(vec![
SetItem::Unique(Expression::Name("bar".to_string())),
SetItem::Unique(Expression::Name("baz".to_string())),
]))
)));
}
#[test]
fn test_dictlit() {
let atom = ExpressionParser::<NewlinesAreNotSpaces>::atom;
assert_parse_eq(atom(make_strspan("{}")), Ok((make_strspan(""), Box::new(
Expression::DictLiteral(vec![
])
))));
assert_parse_eq(atom(make_strspan("{foo1:foo2}")), Ok((make_strspan(""), Box::new(
Expression::DictLiteral(vec![
DictItem::Unique(
Expression::Name("foo1".to_string()),
Expression::Name("foo2".to_string()),
),
])
))));
assert_parse_eq(atom(make_strspan("{foo1:foo2, bar1:bar2, baz1:baz2}")), Ok((make_strspan(""), Box::new(
Expression::DictLiteral(vec![
DictItem::Unique(
Expression::Name("foo1".to_string()),
Expression::Name("foo2".to_string()),
),
DictItem::Unique(
Expression::Name("bar1".to_string()),
Expression::Name("bar2".to_string()),
),
DictItem::Unique(
Expression::Name("baz1".to_string()),
Expression::Name("baz2".to_string()),
),
])
))));
assert_parse_eq(atom(make_strspan("{foo1:foo2, **bar, baz1:baz2}")), Ok((make_strspan(""), Box::new(
Expression::DictLiteral(vec![
DictItem::Unique(
Expression::Name("foo1".to_string()),
Expression::Name("foo2".to_string()),
),
DictItem::Star(Expression::Name("bar".to_string())),
DictItem::Unique(
Expression::Name("baz1".to_string()),
Expression::Name("baz2".to_string()),
),
])
))));
}
#[test]
fn test_comp_for() {
let comp_for = ExpressionParser::<NewlinesAreNotSpaces>::comp_for;
assert_parse_eq(comp_for(make_strspan("for bar in baz")), Ok((make_strspan(""), vec![
ComprehensionChunk::For {
async: false,
item: vec![
Expression::Name("bar".to_string()),
],
iterator: Expression::Name("baz".to_string()),
},
])));
}
#[test]
fn test_listcomp() {
let atom = ExpressionParser::<NewlinesAreNotSpaces>::atom;
assert_parse_eq(atom(make_strspan("[foo for bar in baz]")), Ok((make_strspan(""),
Box::new(Expression::ListComp(
Box::new(SetItem::Unique(Expression::Name("foo".to_string()))),
vec![
ComprehensionChunk::For {
async: false,
item: vec![
Expression::Name("bar".to_string()),
],
iterator: Expression::Name("baz".to_string()),
},
],
))
)));
}
#[test]
fn test_listcomp2() {
let testlist_comp = ExpressionParser::<NewlinesAreNotSpaces>::testlist_comp;
assert_parse_eq(testlist_comp(make_strspan("foo for bar in baz")), Ok((make_strspan(""),
TestlistCompReturn::Comp(
Box::new(SetItem::Unique(Expression::Name("foo".to_string()))),
vec![
ComprehensionChunk::For {
async: false,
item: vec![
Expression::Name("bar".to_string()),
],
iterator: Expression::Name("baz".to_string()),
},
],
)
)));
}
#[test]
fn test_listcomp2_chain_for() {
let testlist_comp = ExpressionParser::<NewlinesAreNotSpaces>::testlist_comp;
assert_parse_eq(testlist_comp(make_strspan("foo for bar in baz for qux in quux")), Ok((make_strspan(""),
TestlistCompReturn::Comp(
Box::new(SetItem::Unique(Expression::Name("foo".to_string()))),
vec![
ComprehensionChunk::For {
async: false,
item: vec![
Expression::Name("bar".to_string()),
],
iterator: Expression::Name("baz".to_string()),
},
ComprehensionChunk::For {
async: false,
item: vec![
Expression::Name("qux".to_string()),
],
iterator: Expression::Name("quux".to_string()),
},
],
)
)));
}
#[test]
fn test_listcomp2_chain_if() {
let testlist_comp = ExpressionParser::<NewlinesAreNotSpaces>::testlist_comp;
assert_parse_eq(testlist_comp(make_strspan("foo for bar in baz if qux")), Ok((make_strspan(""),
TestlistCompReturn::Comp(
Box::new(SetItem::Unique(Expression::Name("foo".to_string()))),
vec![
ComprehensionChunk::For {
async: false,
item: vec![
Expression::Name("bar".to_string()),
],
iterator: Expression::Name("baz".to_string()),
},
ComprehensionChunk::If {
cond: Expression::Name("qux".to_string()),
},
],
)
)));
}
#[test]
fn test_listcomp3() {
let testlist_comp = ExpressionParser::<NewlinesAreNotSpaces>::testlist_comp;
assert_parse_eq(testlist_comp(make_strspan("foo for (bar, baz) in qux")), Ok((make_strspan(""),
TestlistCompReturn::Comp(
Box::new(SetItem::Unique(Expression::Name("foo".to_string()))),
vec![
ComprehensionChunk::For {
async: false,
item: vec![
Expression::TupleLiteral(vec![
SetItem::Unique(Expression::Name("bar".to_string())),
SetItem::Unique(Expression::Name("baz".to_string())),
]),
],
iterator: Expression::Name("qux".to_string()),
},
],
)
)));
}
#[test]
fn test_setcomp() {
let atom = ExpressionParser::<NewlinesAreNotSpaces>::atom;
assert_parse_eq(atom(make_strspan("{foo for bar in baz}")), Ok((make_strspan(""), Box::new(
Expression::SetComp(
Box::new(SetItem::Unique(Expression::Name("foo".to_string()))),
vec![
ComprehensionChunk::For {
async: false,
item: vec![
Expression::Name("bar".to_string()),
],
iterator: Expression::Name("baz".to_string()),
},
]
)
))));
}
#[test]
fn test_op() {
let test = ExpressionParser::<NewlinesAreNotSpaces>::test;
assert_parse_eq(test(make_strspan("n >= 0")), Ok((make_strspan(""),
Box::new(Expression::Bop(Bop::Geq,
Box::new(Expression::Name("n".to_string())),
Box::new(Expression::Int(0u32.into()))
))
)));
}
#[test]
fn test_lambda() {
let test = ExpressionParser::<NewlinesAreNotSpaces>::test;
assert_parse_eq(test(make_strspan("lambda: foo")), Ok((make_strspan(""),
Box::new(Expression::Lambdef(
Default::default(),
Box::new(Expression::Name("foo".to_string())),
))
)));
assert_parse_eq(test(make_strspan("lambda : foo")), Ok((make_strspan(""),
Box::new(Expression::Lambdef(
Default::default(),
Box::new(Expression::Name("foo".to_string())),
))
)));
assert_parse_eq(test(make_strspan("lambda :foo")), Ok((make_strspan(""),
Box::new(Expression::Lambdef(
Default::default(),
Box::new(Expression::Name("foo".to_string())),
))
)));
}
#[test]
fn test_multibop() {
let test = ExpressionParser::<NewlinesAreNotSpaces>::test;
assert_parse_eq(test(make_strspan("a <= b < c")), Ok((make_strspan(""),
Box::new(Expression::MultiBop(
Box::new(Expression::Name("a".to_string())),
vec![
(Bop::Leq, Expression::Name("b".to_string())),
(Bop::Lt, Expression::Name("c".to_string())),
]
))
)));
}
#[test]
fn test_escaped_newline() {
let test = ExpressionParser::<NewlinesAreNotSpaces>::test;
assert_parse_eq(test(make_strspan("a <= \\\nb")), Ok((make_strspan(""),
Box::new(Expression::Bop(Bop::Leq,
Box::new(Expression::Name("a".to_string())),
Box::new(Expression::Name("b".to_string())),
))
)));
}
#[test]
fn test_yield() {
let test = ExpressionParser::<NewlinesAreNotSpaces>::test;
assert_parse_eq(test(make_strspan("lambda: (yield)")), Ok((make_strspan(""),
Box::new(Expression::Lambdef(
Default::default(),
Box::new(Expression::Yield(Vec::new())),
))
)));
}
}