librustc: Change labels to use the lifetime notation '.

This commit is contained in:
Patrick Walton 2013-04-26 16:19:26 -07:00
parent 876483dcf4
commit 670ab8ac36
6 changed files with 79 additions and 40 deletions

View file

@ -2187,7 +2187,7 @@ A loop expression denotes an infinite loop;
see [Continue expressions](#continue-expressions) for continue expressions. see [Continue expressions](#continue-expressions) for continue expressions.
~~~~~~~~{.ebnf .gram} ~~~~~~~~{.ebnf .gram}
loop_expr : "loop" [ ident ':' ] '{' block '}'; loop_expr : [ lifetime ':' ] "loop" '{' block '}';
~~~~~~~~ ~~~~~~~~
A `loop` expression may optionally have a _label_. A `loop` expression may optionally have a _label_.
@ -2198,7 +2198,7 @@ See [Break expressions](#break-expressions).
### Break expressions ### Break expressions
~~~~~~~~{.ebnf .gram} ~~~~~~~~{.ebnf .gram}
break_expr : "break" [ ident ]; break_expr : "break" [ lifetime ];
~~~~~~~~ ~~~~~~~~
A `break` expression has an optional `label`. A `break` expression has an optional `label`.
@ -2211,7 +2211,7 @@ but must enclose it.
### Continue expressions ### Continue expressions
~~~~~~~~{.ebnf .gram} ~~~~~~~~{.ebnf .gram}
continue_expr : "loop" [ ident ]; continue_expr : "loop" [ lifetime ];
~~~~~~~~ ~~~~~~~~
A continue expression, written `loop`, also has an optional `label`. A continue expression, written `loop`, also has an optional `label`.

View file

@ -52,7 +52,10 @@ pub fn expand_asm(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
let mut dialect = ast::asm_att; let mut dialect = ast::asm_att;
let mut state = Asm; let mut state = Asm;
loop outer: {
// Not using labeled break to get us through one round of bootstrapping.
let mut continue = true;
while continue {
match state { match state {
Asm => { Asm => {
asm = expr_to_str(cx, p.parse_expr(), asm = expr_to_str(cx, p.parse_expr(),
@ -139,20 +142,30 @@ pub fn expand_asm(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
p.bump(); p.bump();
match next_state(state) { match next_state(state) {
Some(x) => x, Some(x) => x,
None => break outer None => {
continue = false;
break
}
} }
} else if *p.token == token::MOD_SEP { } else if *p.token == token::MOD_SEP {
p.bump(); p.bump();
let s = match next_state(state) { let s = match next_state(state) {
Some(x) => x, Some(x) => x,
None => break outer None => {
continue = false;
break
}
}; };
match next_state(s) { match next_state(s) {
Some(x) => x, Some(x) => x,
None => break outer None => {
continue = false;
break
}
} }
} else if *p.token == token::EOF { } else if *p.token == token::EOF {
break outer; continue = false;
break;
} else { } else {
state state
}; };

View file

@ -348,6 +348,20 @@ pub impl Parser {
self.token_is_keyword(&~"fn", tok) self.token_is_keyword(&~"fn", tok)
} }
fn token_is_lifetime(&self, tok: &token::Token) -> bool {
match *tok {
token::LIFETIME(*) => true,
_ => false,
}
}
fn get_lifetime(&self, tok: &token::Token) -> ast::ident {
match *tok {
token::LIFETIME(ref ident) => copy *ident,
_ => self.bug(~"not a lifetime"),
}
}
// parse a ty_bare_fun type: // parse a ty_bare_fun type:
fn parse_ty_bare_fn(&self) -> ty_ fn parse_ty_bare_fn(&self) -> ty_
{ {
@ -1228,8 +1242,14 @@ pub impl Parser {
expr_do_body); expr_do_body);
} else if self.eat_keyword(&~"while") { } else if self.eat_keyword(&~"while") {
return self.parse_while_expr(); return self.parse_while_expr();
} else if self.token_is_lifetime(&*self.token) {
let lifetime = self.get_lifetime(&*self.token);
self.bump();
self.expect(&token::COLON);
self.expect_keyword(&~"loop");
return self.parse_loop_expr(Some(lifetime));
} else if self.eat_keyword(&~"loop") { } else if self.eat_keyword(&~"loop") {
return self.parse_loop_expr(); return self.parse_loop_expr(None);
} else if self.eat_keyword(&~"match") { } else if self.eat_keyword(&~"match") {
return self.parse_match_expr(); return self.parse_match_expr();
} else if self.eat_keyword(&~"unsafe") { } else if self.eat_keyword(&~"unsafe") {
@ -1290,8 +1310,10 @@ pub impl Parser {
} else { ex = expr_ret(None); } } else { ex = expr_ret(None); }
} else if self.eat_keyword(&~"break") { } else if self.eat_keyword(&~"break") {
// BREAK expression // BREAK expression
if is_ident(&*self.token) { if self.token_is_lifetime(&*self.token) {
ex = expr_break(Some(self.parse_ident())); let lifetime = self.get_lifetime(&*self.token);
self.bump();
ex = expr_break(Some(lifetime));
} else { } else {
ex = expr_break(None); ex = expr_break(None);
} }
@ -1995,37 +2017,32 @@ pub impl Parser {
return self.mk_expr(lo, hi, expr_while(cond, body)); return self.mk_expr(lo, hi, expr_while(cond, body));
} }
fn parse_loop_expr(&self) -> @expr { fn parse_loop_expr(&self, opt_ident: Option<ast::ident>) -> @expr {
// loop headers look like 'loop {' or 'loop unsafe {' // loop headers look like 'loop {' or 'loop unsafe {'
let is_loop_header = let is_loop_header =
*self.token == token::LBRACE *self.token == token::LBRACE
|| (is_ident(&*self.token) || (is_ident(&*self.token)
&& self.look_ahead(1) == token::LBRACE); && self.look_ahead(1) == token::LBRACE);
// labeled loop headers look like 'loop foo: {'
let is_labeled_loop_header =
is_ident(&*self.token)
&& !self.is_any_keyword(&copy *self.token)
&& self.look_ahead(1) == token::COLON;
if is_loop_header || is_labeled_loop_header { if is_loop_header {
// This is a loop body // This is a loop body
let opt_ident;
if is_labeled_loop_header {
opt_ident = Some(self.parse_ident());
self.expect(&token::COLON);
} else {
opt_ident = None;
}
let lo = self.last_span.lo; let lo = self.last_span.lo;
let body = self.parse_block(); let body = self.parse_block();
let hi = body.span.hi; let hi = body.span.hi;
return self.mk_expr(lo, hi, expr_loop(body, opt_ident)); return self.mk_expr(lo, hi, expr_loop(body, opt_ident));
} else { } else {
// This is a 'continue' expression // This is a 'continue' expression
if opt_ident.is_some() {
self.span_err(*self.last_span,
~"a label may not be used with a `loop` \
expression");
}
let lo = self.span.lo; let lo = self.span.lo;
let ex = if is_ident(&*self.token) { let ex = if self.token_is_lifetime(&*self.token) {
expr_again(Some(self.parse_ident())) let lifetime = self.get_lifetime(&*self.token);
self.bump();
expr_again(Some(lifetime))
} else { } else {
expr_again(None) expr_again(None)
}; };

View file

@ -1210,12 +1210,13 @@ pub fn print_expr(s: @ps, expr: @ast::expr) {
print_block(s, blk); print_block(s, blk);
} }
ast::expr_loop(ref blk, opt_ident) => { ast::expr_loop(ref blk, opt_ident) => {
head(s, ~"loop");
space(s.s);
for opt_ident.each |ident| { for opt_ident.each |ident| {
word(s.s, ~"'");
print_ident(s, *ident); print_ident(s, *ident);
word_space(s, ~":"); word_space(s, ~":");
} }
head(s, ~"loop");
space(s.s);
print_block(s, blk); print_block(s, blk);
} }
ast::expr_match(expr, ref arms) => { ast::expr_match(expr, ref arms) => {
@ -1363,12 +1364,20 @@ pub fn print_expr(s: @ps, expr: @ast::expr) {
ast::expr_break(opt_ident) => { ast::expr_break(opt_ident) => {
word(s.s, ~"break"); word(s.s, ~"break");
space(s.s); space(s.s);
for opt_ident.each |ident| { print_ident(s, *ident); space(s.s) } for opt_ident.each |ident| {
word(s.s, ~"'");
print_ident(s, *ident);
space(s.s);
}
} }
ast::expr_again(opt_ident) => { ast::expr_again(opt_ident) => {
word(s.s, ~"loop"); word(s.s, ~"loop");
space(s.s); space(s.s);
for opt_ident.each |ident| { print_ident(s, *ident); space(s.s) } for opt_ident.each |ident| {
word(s.s, ~"'");
print_ident(s, *ident);
space(s.s)
}
} }
ast::expr_ret(result) => { ast::expr_ret(result) => {
word(s.s, ~"return"); word(s.s, ~"return");

View file

@ -11,17 +11,17 @@
pub fn main() { pub fn main() {
let mut x = 0; let mut x = 0;
loop foo: { 'foo: loop {
loop bar: { 'bar: loop {
loop quux: { 'quux: loop {
if 1 == 2 { if 1 == 2 {
break foo; break 'foo;
} }
else { else {
break bar; break 'bar;
} }
} }
loop foo; loop 'foo;
} }
x = 42; x = 42;
break; break;

View file

@ -12,9 +12,9 @@
// xfail-test // xfail-test
pub fn main() { pub fn main() {
loop foo: { 'foo: loop {
loop { loop {
break foo; break 'foo;
} }
} }
} }