Skip to content

Commit

Permalink
Merge pull request #1542 from dtolnay/exprgroup
Browse files Browse the repository at this point in the history
Support interpolated $:path followed by macro call or struct literal
  • Loading branch information
dtolnay committed Dec 11, 2023
2 parents 9f29f05 + da9495b commit 1c54651
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 16 deletions.
63 changes: 47 additions & 16 deletions src/expr.rs
Expand Up @@ -1577,12 +1577,8 @@ pub(crate) mod parsing {
// interactions, as they are fully contained.
#[cfg(feature = "full")]
fn atom_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
if input.peek(token::Group)
&& !input.peek2(Token![::])
&& !input.peek2(Token![!])
&& !input.peek2(token::Brace)
{
input.call(expr_group).map(Expr::Group)
if input.peek(token::Group) {
expr_group(input, allow_struct)
} else if input.peek(Lit) {
input.parse().map(Expr::Lit)
} else if input.peek(Token![async])
Expand Down Expand Up @@ -1680,12 +1676,8 @@ pub(crate) mod parsing {

#[cfg(not(feature = "full"))]
fn atom_expr(input: ParseStream) -> Result<Expr> {
if input.peek(token::Group)
&& !input.peek2(Token![::])
&& !input.peek2(Token![!])
&& !input.peek2(token::Brace)
{
input.call(expr_group).map(Expr::Group)
if input.peek(token::Group) {
expr_group(input)
} else if input.peek(Lit) {
input.parse().map(Expr::Lit)
} else if input.peek(token::Paren) {
Expand Down Expand Up @@ -1736,7 +1728,21 @@ pub(crate) mod parsing {
#[cfg(feature = "full")] allow_struct: AllowStruct,
) -> Result<Expr> {
let (qself, path) = path::parsing::qpath(input, true)?;
rest_of_path_or_macro_or_struct(
qself,
path,
input,
#[cfg(feature = "full")]
allow_struct,
)
}

fn rest_of_path_or_macro_or_struct(
qself: Option<QSelf>,
path: Path,
input: ParseStream,
#[cfg(feature = "full")] allow_struct: AllowStruct,
) -> Result<Expr> {
if qself.is_none()
&& input.peek(Token![!])
&& !input.peek(Token![!=])
Expand Down Expand Up @@ -1962,13 +1968,38 @@ pub(crate) mod parsing {
}
}

fn expr_group(input: ParseStream) -> Result<ExprGroup> {
fn expr_group(
input: ParseStream,
#[cfg(feature = "full")] allow_struct: AllowStruct,
) -> Result<Expr> {
let group = crate::group::parse_group(input)?;
Ok(ExprGroup {
let mut inner: Expr = group.content.parse()?;

match inner {
Expr::Path(mut expr) if expr.attrs.is_empty() => {
let grouped_len = expr.path.segments.len();
Path::parse_rest(input, &mut expr.path, true)?;
match rest_of_path_or_macro_or_struct(
expr.qself,
expr.path,
input,
#[cfg(feature = "full")]
allow_struct,
)? {
Expr::Path(expr) if expr.path.segments.len() == grouped_len => {
inner = Expr::Path(expr);
}
extended => return Ok(extended),
}
}
_ => {}
}

Ok(Expr::Group(ExprGroup {
attrs: Vec::new(),
group_token: group.token,
expr: group.content.parse()?,
})
expr: Box::new(inner),
}))
}

#[cfg(feature = "full")]
Expand Down
103 changes: 103 additions & 0 deletions tests/test_expr.rs
Expand Up @@ -339,3 +339,106 @@ fn test_ambiguous_label() {
syn::parse2::<Stmt>(stmt).unwrap_err();
}
}

#[test]
fn test_extended_interpolated_path() {
let path = Group::new(Delimiter::None, quote!(a::b));

let tokens = quote!(if #path {});
snapshot!(tokens as Expr, @r###"
Expr::If {
cond: Expr::Group {
expr: Expr::Path {
path: Path {
segments: [
PathSegment {
ident: "a",
},
PathSegment {
ident: "b",
},
],
},
},
},
then_branch: Block {
stmts: [],
},
}
"###);

let tokens = quote!(#path {});
snapshot!(tokens as Expr, @r###"
Expr::Struct {
path: Path {
segments: [
PathSegment {
ident: "a",
},
PathSegment {
ident: "b",
},
],
},
}
"###);

let tokens = quote!(#path :: c);
snapshot!(tokens as Expr, @r###"
Expr::Path {
path: Path {
segments: [
PathSegment {
ident: "a",
},
PathSegment {
ident: "b",
},
PathSegment {
ident: "c",
},
],
},
}
"###);

let nested = Group::new(Delimiter::None, quote!(a::b || true));
let tokens = quote!(if #nested && false {});
snapshot!(tokens as Expr, @r###"
Expr::If {
cond: Expr::Binary {
left: Expr::Group {
expr: Expr::Binary {
left: Expr::Path {
path: Path {
segments: [
PathSegment {
ident: "a",
},
PathSegment {
ident: "b",
},
],
},
},
op: BinOp::Or,
right: Expr::Lit {
lit: Lit::Bool {
value: true,
},
},
},
},
op: BinOp::And,
right: Expr::Lit {
lit: Lit::Bool {
value: false,
},
},
},
then_branch: Block {
stmts: [],
},
}
"###);
}

0 comments on commit 1c54651

Please sign in to comment.