1
Fork 0

Teach libsyntax about while let

This commit is contained in:
John Gallagher 2014-10-02 22:45:46 -04:00
parent 78a7676898
commit 0c2c8116a3
7 changed files with 80 additions and 1 deletions

View file

@ -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.

View file

@ -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) => {

View file

@ -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),

View file

@ -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

View file

@ -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();

View file

@ -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));

View file

@ -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);