Teach libsyntax about while let
This commit is contained in:
parent
78a7676898
commit
0c2c8116a3
7 changed files with 80 additions and 1 deletions
|
@ -524,6 +524,8 @@ pub enum Expr_ {
|
||||||
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
|
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
|
||||||
ExprWhile(P<Expr>, P<Block>, Option<Ident>),
|
ExprWhile(P<Expr>, P<Block>, Option<Ident>),
|
||||||
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
|
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
|
||||||
|
ExprWhileLet(P<Pat>, P<Expr>, P<Block>, Option<Ident>),
|
||||||
|
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
|
||||||
ExprForLoop(P<Pat>, P<Expr>, P<Block>, Option<Ident>),
|
ExprForLoop(P<Pat>, P<Expr>, P<Block>, Option<Ident>),
|
||||||
// Conditionless loop (can be exited with break, cont, or ret)
|
// Conditionless loop (can be exited with break, cont, or ret)
|
||||||
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
|
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
|
||||||
|
|
|
@ -67,6 +67,42 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
|
||||||
fld.cx.expr(span, ast::ExprWhile(cond, body, opt_ident))
|
fld.cx.expr(span, ast::ExprWhile(cond, body, opt_ident))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Desugar ExprWhileLet
|
||||||
|
// From: `[opt_ident]: while let <pat> = <expr> <body>`
|
||||||
|
ast::ExprWhileLet(pat, expr, body, opt_ident) => {
|
||||||
|
// to:
|
||||||
|
//
|
||||||
|
// [opt_ident]: loop {
|
||||||
|
// match <expr> {
|
||||||
|
// <pat> => <body>,
|
||||||
|
// _ => break
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// `<pat> => <body>`
|
||||||
|
let pat_arm = {
|
||||||
|
let body_expr = fld.cx.expr_block(body);
|
||||||
|
fld.cx.arm(pat.span, vec![pat], body_expr)
|
||||||
|
};
|
||||||
|
|
||||||
|
// `_ => break`
|
||||||
|
let break_arm = {
|
||||||
|
let pat_under = fld.cx.pat_wild(span);
|
||||||
|
let break_expr = fld.cx.expr_break(span);
|
||||||
|
fld.cx.arm(span, vec![pat_under], break_expr)
|
||||||
|
};
|
||||||
|
|
||||||
|
// `match <expr> { ... }`
|
||||||
|
let arms = vec![pat_arm, break_arm];
|
||||||
|
let match_expr = fld.cx.expr(span,
|
||||||
|
ast::ExprMatch(expr, arms, ast::MatchWhileLetDesugar));
|
||||||
|
|
||||||
|
// `[opt_ident]: loop { ... }`
|
||||||
|
let loop_block = fld.cx.block_expr(match_expr);
|
||||||
|
let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
|
||||||
|
fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident))
|
||||||
|
}
|
||||||
|
|
||||||
// Desugar ExprIfLet
|
// Desugar ExprIfLet
|
||||||
// From: `if let <pat> = <expr> <body> [<elseopt>]`
|
// From: `if let <pat> = <expr> <body> [<elseopt>]`
|
||||||
ast::ExprIfLet(pat, expr, body, mut elseopt) => {
|
ast::ExprIfLet(pat, expr, body, mut elseopt) => {
|
||||||
|
|
|
@ -1218,6 +1218,12 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
|
||||||
folder.fold_block(body),
|
folder.fold_block(body),
|
||||||
opt_ident.map(|i| folder.fold_ident(i)))
|
opt_ident.map(|i| folder.fold_ident(i)))
|
||||||
}
|
}
|
||||||
|
ExprWhileLet(pat, expr, body, opt_ident) => {
|
||||||
|
ExprWhileLet(folder.fold_pat(pat),
|
||||||
|
folder.fold_expr(expr),
|
||||||
|
folder.fold_block(body),
|
||||||
|
opt_ident.map(|i| folder.fold_ident(i)))
|
||||||
|
}
|
||||||
ExprForLoop(pat, iter, body, opt_ident) => {
|
ExprForLoop(pat, iter, body, opt_ident) => {
|
||||||
ExprForLoop(folder.fold_pat(pat),
|
ExprForLoop(folder.fold_pat(pat),
|
||||||
folder.fold_expr(iter),
|
folder.fold_expr(iter),
|
||||||
|
|
|
@ -28,6 +28,7 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
|
||||||
| ast::ExprMatch(..)
|
| ast::ExprMatch(..)
|
||||||
| ast::ExprBlock(_)
|
| ast::ExprBlock(_)
|
||||||
| ast::ExprWhile(..)
|
| ast::ExprWhile(..)
|
||||||
|
| ast::ExprWhileLet(..)
|
||||||
| ast::ExprLoop(..)
|
| ast::ExprLoop(..)
|
||||||
| ast::ExprForLoop(..) => false,
|
| ast::ExprForLoop(..) => false,
|
||||||
_ => true
|
_ => true
|
||||||
|
|
|
@ -26,7 +26,7 @@ use ast::{ExprField, ExprTupField, ExprFnBlock, ExprIf, ExprIfLet, ExprIndex, Ex
|
||||||
use ast::{ExprLit, ExprLoop, ExprMac};
|
use ast::{ExprLit, ExprLoop, ExprMac};
|
||||||
use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
|
use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
|
||||||
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn};
|
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn};
|
||||||
use ast::{ExprVec, ExprWhile, ExprForLoop, Field, FnDecl};
|
use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl};
|
||||||
use ast::{Once, Many};
|
use ast::{Once, Many};
|
||||||
use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind};
|
use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind};
|
||||||
use ast::{FnOnceUnboxedClosureKind};
|
use ast::{FnOnceUnboxedClosureKind};
|
||||||
|
@ -2935,7 +2935,11 @@ impl<'a> Parser<'a> {
|
||||||
self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident))
|
self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse a 'while' or 'while let' expression ('while' token already eaten)
|
||||||
pub fn parse_while_expr(&mut self, opt_ident: Option<ast::Ident>) -> P<Expr> {
|
pub fn parse_while_expr(&mut self, opt_ident: Option<ast::Ident>) -> P<Expr> {
|
||||||
|
if self.is_keyword(keywords::Let) {
|
||||||
|
return self.parse_while_let_expr(opt_ident);
|
||||||
|
}
|
||||||
let lo = self.last_span.lo;
|
let lo = self.last_span.lo;
|
||||||
let cond = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL);
|
let cond = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL);
|
||||||
let body = self.parse_block();
|
let body = self.parse_block();
|
||||||
|
@ -2943,6 +2947,18 @@ impl<'a> Parser<'a> {
|
||||||
return self.mk_expr(lo, hi, ExprWhile(cond, body, opt_ident));
|
return self.mk_expr(lo, hi, ExprWhile(cond, body, opt_ident));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse a 'while let' expression ('while' token already eaten)
|
||||||
|
pub fn parse_while_let_expr(&mut self, opt_ident: Option<ast::Ident>) -> P<Expr> {
|
||||||
|
let lo = self.last_span.lo;
|
||||||
|
self.expect_keyword(keywords::Let);
|
||||||
|
let pat = self.parse_pat();
|
||||||
|
self.expect(&token::EQ);
|
||||||
|
let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL);
|
||||||
|
let body = self.parse_block();
|
||||||
|
let hi = body.span.hi;
|
||||||
|
return self.mk_expr(lo, hi, ExprWhileLet(pat, expr, body, opt_ident));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::Ident>) -> P<Expr> {
|
pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::Ident>) -> P<Expr> {
|
||||||
let lo = self.last_span.lo;
|
let lo = self.last_span.lo;
|
||||||
let body = self.parse_block();
|
let body = self.parse_block();
|
||||||
|
|
|
@ -1525,6 +1525,19 @@ impl<'a> State<'a> {
|
||||||
try!(space(&mut self.s));
|
try!(space(&mut self.s));
|
||||||
try!(self.print_block(&**blk));
|
try!(self.print_block(&**blk));
|
||||||
}
|
}
|
||||||
|
ast::ExprWhileLet(ref pat, ref expr, ref blk, opt_ident) => {
|
||||||
|
for ident in opt_ident.iter() {
|
||||||
|
try!(self.print_ident(*ident));
|
||||||
|
try!(self.word_space(":"));
|
||||||
|
}
|
||||||
|
try!(self.head("while let"));
|
||||||
|
try!(self.print_pat(&**pat));
|
||||||
|
try!(space(&mut self.s));
|
||||||
|
try!(self.word_space("="));
|
||||||
|
try!(self.print_expr(&**expr));
|
||||||
|
try!(space(&mut self.s));
|
||||||
|
try!(self.print_block(&**blk));
|
||||||
|
}
|
||||||
ast::ExprForLoop(ref pat, ref iter, ref blk, opt_ident) => {
|
ast::ExprForLoop(ref pat, ref iter, ref blk, opt_ident) => {
|
||||||
for ident in opt_ident.iter() {
|
for ident in opt_ident.iter() {
|
||||||
try!(self.print_ident(*ident));
|
try!(self.print_ident(*ident));
|
||||||
|
|
|
@ -737,6 +737,11 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
|
||||||
visitor.visit_block(&**if_block);
|
visitor.visit_block(&**if_block);
|
||||||
walk_expr_opt(visitor, optional_else);
|
walk_expr_opt(visitor, optional_else);
|
||||||
}
|
}
|
||||||
|
ExprWhileLet(ref pattern, ref subexpression, ref block, _) => {
|
||||||
|
visitor.visit_pat(&**pattern);
|
||||||
|
visitor.visit_expr(&**subexpression);
|
||||||
|
visitor.visit_block(&**block);
|
||||||
|
}
|
||||||
ExprForLoop(ref pattern, ref subexpression, ref block, _) => {
|
ExprForLoop(ref pattern, ref subexpression, ref block, _) => {
|
||||||
visitor.visit_pat(&**pattern);
|
visitor.visit_pat(&**pattern);
|
||||||
visitor.visit_expr(&**subexpression);
|
visitor.visit_expr(&**subexpression);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue