Teach libsyntax about if let
This commit is contained in:
parent
38015eeb70
commit
5d8cfd53b5
6 changed files with 71 additions and 13 deletions
|
@ -521,6 +521,7 @@ pub enum Expr_ {
|
||||||
ExprLit(P<Lit>),
|
ExprLit(P<Lit>),
|
||||||
ExprCast(P<Expr>, P<Ty>),
|
ExprCast(P<Expr>, P<Ty>),
|
||||||
ExprIf(P<Expr>, P<Block>, Option<P<Expr>>),
|
ExprIf(P<Expr>, P<Block>, Option<P<Expr>>),
|
||||||
|
ExprIfLet(P<Pat>, P<Expr>, P<Block>, Option<P<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.
|
||||||
|
|
|
@ -1205,6 +1205,12 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
|
||||||
folder.fold_block(tr),
|
folder.fold_block(tr),
|
||||||
fl.map(|x| folder.fold_expr(x)))
|
fl.map(|x| folder.fold_expr(x)))
|
||||||
}
|
}
|
||||||
|
ExprIfLet(pat, expr, tr, fl) => {
|
||||||
|
ExprIfLet(folder.fold_pat(pat),
|
||||||
|
folder.fold_expr(expr),
|
||||||
|
folder.fold_block(tr),
|
||||||
|
fl.map(|x| folder.fold_expr(x)))
|
||||||
|
}
|
||||||
ExprWhile(cond, body, opt_ident) => {
|
ExprWhile(cond, body, opt_ident) => {
|
||||||
ExprWhile(folder.fold_expr(cond),
|
ExprWhile(folder.fold_expr(cond),
|
||||||
folder.fold_block(body),
|
folder.fold_block(body),
|
||||||
|
|
|
@ -24,6 +24,7 @@ use ast;
|
||||||
pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
|
pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
|
||||||
match e.node {
|
match e.node {
|
||||||
ast::ExprIf(..)
|
ast::ExprIf(..)
|
||||||
|
| ast::ExprIfLet(..)
|
||||||
| ast::ExprMatch(..)
|
| ast::ExprMatch(..)
|
||||||
| ast::ExprBlock(_)
|
| ast::ExprBlock(_)
|
||||||
| ast::ExprWhile(..)
|
| ast::ExprWhile(..)
|
||||||
|
|
|
@ -23,7 +23,7 @@ use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, EMPTY_CTXT, EnumDef, Explicit
|
||||||
use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
|
use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
|
||||||
use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
|
use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
|
||||||
use ast::{ExprBreak, ExprCall, ExprCast};
|
use ast::{ExprBreak, ExprCall, ExprCast};
|
||||||
use ast::{ExprField, ExprTupField, ExprFnBlock, ExprIf, ExprIndex, ExprSlice};
|
use ast::{ExprField, ExprTupField, ExprFnBlock, ExprIf, ExprIfLet, ExprIndex, ExprSlice};
|
||||||
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};
|
||||||
|
@ -576,13 +576,10 @@ impl<'a> Parser<'a> {
|
||||||
/// If the next token is the given keyword, eat it and return
|
/// If the next token is the given keyword, eat it and return
|
||||||
/// true. Otherwise, return false.
|
/// true. Otherwise, return false.
|
||||||
pub fn eat_keyword(&mut self, kw: keywords::Keyword) -> bool {
|
pub fn eat_keyword(&mut self, kw: keywords::Keyword) -> bool {
|
||||||
match self.token {
|
if self.is_keyword(kw) {
|
||||||
token::IDENT(sid, false) if kw.to_name() == sid.name => {
|
self.bump();
|
||||||
self.bump();
|
true
|
||||||
true
|
} else { false }
|
||||||
}
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the given word is not a keyword, signal an error.
|
/// If the given word is not a keyword, signal an error.
|
||||||
|
@ -2860,8 +2857,11 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse an 'if' expression ('if' token already eaten)
|
/// Parse an 'if' or 'if let' expression ('if' token already eaten)
|
||||||
pub fn parse_if_expr(&mut self) -> P<Expr> {
|
pub fn parse_if_expr(&mut self) -> P<Expr> {
|
||||||
|
if self.is_keyword(keywords::Let) {
|
||||||
|
return self.parse_if_let_expr();
|
||||||
|
}
|
||||||
let lo = self.last_span.lo;
|
let lo = self.last_span.lo;
|
||||||
let cond = self.parse_expr_res(RestrictionNoStructLiteral);
|
let cond = self.parse_expr_res(RestrictionNoStructLiteral);
|
||||||
let thn = self.parse_block();
|
let thn = self.parse_block();
|
||||||
|
@ -2875,6 +2875,23 @@ impl<'a> Parser<'a> {
|
||||||
self.mk_expr(lo, hi, ExprIf(cond, thn, els))
|
self.mk_expr(lo, hi, ExprIf(cond, thn, els))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse an 'if let' expression ('if' token already eaten)
|
||||||
|
pub fn parse_if_let_expr(&mut self) -> 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(RestrictionNoStructLiteral);
|
||||||
|
let thn = self.parse_block();
|
||||||
|
let (hi, els) = if self.eat_keyword(keywords::Else) {
|
||||||
|
let expr = self.parse_else_expr();
|
||||||
|
(expr.span.hi, Some(expr))
|
||||||
|
} else {
|
||||||
|
(thn.span.hi, None)
|
||||||
|
};
|
||||||
|
self.mk_expr(lo, hi, ExprIfLet(pat, expr, thn, els))
|
||||||
|
}
|
||||||
|
|
||||||
// `|args| expr`
|
// `|args| expr`
|
||||||
pub fn parse_lambda_expr(&mut self, capture_clause: CaptureClause)
|
pub fn parse_lambda_expr(&mut self, capture_clause: CaptureClause)
|
||||||
-> P<Expr> {
|
-> P<Expr> {
|
||||||
|
|
|
@ -1307,6 +1307,19 @@ impl<'a> State<'a> {
|
||||||
try!(self.print_block(&**then));
|
try!(self.print_block(&**then));
|
||||||
self.print_else(e.as_ref().map(|e| &**e))
|
self.print_else(e.as_ref().map(|e| &**e))
|
||||||
}
|
}
|
||||||
|
// "another else-if-let"
|
||||||
|
ast::ExprIfLet(ref pat, ref expr, ref then, ref e) => {
|
||||||
|
try!(self.cbox(indent_unit - 1u));
|
||||||
|
try!(self.ibox(0u));
|
||||||
|
try!(word(&mut self.s, " else if 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(&**then));
|
||||||
|
self.print_else(e.as_ref().map(|e| &**e))
|
||||||
|
}
|
||||||
// "final else"
|
// "final else"
|
||||||
ast::ExprBlock(ref b) => {
|
ast::ExprBlock(ref b) => {
|
||||||
try!(self.cbox(indent_unit - 1u));
|
try!(self.cbox(indent_unit - 1u));
|
||||||
|
@ -1325,15 +1338,26 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block,
|
pub fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block,
|
||||||
elseopt: Option<&ast::Expr>, chk: bool) -> IoResult<()> {
|
elseopt: Option<&ast::Expr>) -> IoResult<()> {
|
||||||
try!(self.head("if"));
|
try!(self.head("if"));
|
||||||
if chk { try!(self.word_nbsp("check")); }
|
|
||||||
try!(self.print_expr(test));
|
try!(self.print_expr(test));
|
||||||
try!(space(&mut self.s));
|
try!(space(&mut self.s));
|
||||||
try!(self.print_block(blk));
|
try!(self.print_block(blk));
|
||||||
self.print_else(elseopt)
|
self.print_else(elseopt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn print_if_let(&mut self, pat: &ast::Pat, expr: &ast::Expr, blk: &ast::Block,
|
||||||
|
elseopt: Option<&ast::Expr>) -> IoResult<()> {
|
||||||
|
try!(self.head("if 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));
|
||||||
|
self.print_else(elseopt)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn print_mac(&mut self, m: &ast::Mac) -> IoResult<()> {
|
pub fn print_mac(&mut self, m: &ast::Mac) -> IoResult<()> {
|
||||||
match m.node {
|
match m.node {
|
||||||
// I think it's reasonable to hide the ctxt here:
|
// I think it's reasonable to hide the ctxt here:
|
||||||
|
@ -1474,7 +1498,10 @@ impl<'a> State<'a> {
|
||||||
try!(self.print_type(&**ty));
|
try!(self.print_type(&**ty));
|
||||||
}
|
}
|
||||||
ast::ExprIf(ref test, ref blk, ref elseopt) => {
|
ast::ExprIf(ref test, ref blk, ref elseopt) => {
|
||||||
try!(self.print_if(&**test, &**blk, elseopt.as_ref().map(|e| &**e), false));
|
try!(self.print_if(&**test, &**blk, elseopt.as_ref().map(|e| &**e)));
|
||||||
|
}
|
||||||
|
ast::ExprIfLet(ref pat, ref expr, ref blk, ref elseopt) => {
|
||||||
|
try!(self.print_if_let(&**pat, &**expr, &** blk, elseopt.as_ref().map(|e| &**e)));
|
||||||
}
|
}
|
||||||
ast::ExprWhile(ref test, ref blk, opt_ident) => {
|
ast::ExprWhile(ref test, ref blk, opt_ident) => {
|
||||||
for ident in opt_ident.iter() {
|
for ident in opt_ident.iter() {
|
||||||
|
|
|
@ -730,13 +730,19 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
|
||||||
visitor.visit_expr(&**subexpression);
|
visitor.visit_expr(&**subexpression);
|
||||||
visitor.visit_block(&**block)
|
visitor.visit_block(&**block)
|
||||||
}
|
}
|
||||||
|
ExprIfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => {
|
||||||
|
visitor.visit_pat(&**pattern);
|
||||||
|
visitor.visit_expr(&**subexpression);
|
||||||
|
visitor.visit_block(&**if_block);
|
||||||
|
walk_expr_opt(visitor, optional_else);
|
||||||
|
}
|
||||||
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);
|
||||||
visitor.visit_block(&**block)
|
visitor.visit_block(&**block)
|
||||||
}
|
}
|
||||||
ExprLoop(ref block, _) => visitor.visit_block(&**block),
|
ExprLoop(ref block, _) => visitor.visit_block(&**block),
|
||||||
ExprMatch(ref subexpression, ref arms) => {
|
ExprMatch(ref subexpression, ref arms, _) => {
|
||||||
visitor.visit_expr(&**subexpression);
|
visitor.visit_expr(&**subexpression);
|
||||||
for arm in arms.iter() {
|
for arm in arms.iter() {
|
||||||
visitor.visit_arm(arm)
|
visitor.visit_arm(arm)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue