librustc: Change labels to use the lifetime notation '
.
This commit is contained in:
parent
876483dcf4
commit
670ab8ac36
6 changed files with 79 additions and 40 deletions
|
@ -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`.
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
|
@ -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(© *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)
|
||||||
};
|
};
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -12,9 +12,9 @@
|
||||||
// xfail-test
|
// xfail-test
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
loop foo: {
|
'foo: loop {
|
||||||
loop {
|
loop {
|
||||||
break foo;
|
break 'foo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue