]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/check_loop.rs
doc: remove incomplete sentence
[rust.git] / src / librustc / middle / check_loop.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10 use self::Context::*;
11
12 use session::Session;
13
14 use syntax::ast;
15 use syntax::codemap::Span;
16 use syntax::visit::Visitor;
17 use syntax::visit;
18
19 #[deriving(Clone, Copy, PartialEq)]
20 enum Context {
21     Normal, Loop, Closure
22 }
23
24 #[deriving(Copy)]
25 struct CheckLoopVisitor<'a> {
26     sess: &'a Session,
27     cx: Context
28 }
29
30 pub fn check_crate(sess: &Session, krate: &ast::Crate) {
31     visit::walk_crate(&mut CheckLoopVisitor { sess: sess, cx: Normal }, krate)
32 }
33
34 impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
35     fn visit_item(&mut self, i: &ast::Item) {
36         self.with_context(Normal, |v| visit::walk_item(v, i));
37     }
38
39     fn visit_expr(&mut self, e: &ast::Expr) {
40         match e.node {
41             ast::ExprWhile(ref e, ref b, _) => {
42                 self.visit_expr(&**e);
43                 self.with_context(Loop, |v| v.visit_block(&**b));
44             }
45             ast::ExprLoop(ref b, _) => {
46                 self.with_context(Loop, |v| v.visit_block(&**b));
47             }
48             ast::ExprForLoop(_, ref e, ref b, _) => {
49                 self.visit_expr(&**e);
50                 self.with_context(Loop, |v| v.visit_block(&**b));
51             }
52             ast::ExprClosure(_, _, _, ref b) => {
53                 self.with_context(Closure, |v| v.visit_block(&**b));
54             }
55             ast::ExprBreak(_) => self.require_loop("break", e.span),
56             ast::ExprAgain(_) => self.require_loop("continue", e.span),
57             _ => visit::walk_expr(self, e)
58         }
59     }
60 }
61
62 impl<'a> CheckLoopVisitor<'a> {
63     fn with_context<F>(&mut self, cx: Context, f: F) where
64         F: FnOnce(&mut CheckLoopVisitor<'a>),
65     {
66         let old_cx = self.cx;
67         self.cx = cx;
68         f(self);
69         self.cx = old_cx;
70     }
71
72     fn require_loop(&self, name: &str, span: Span) {
73         match self.cx {
74             Loop => {}
75             Closure => {
76                 self.sess.span_err(span,
77                                    format!("`{}` inside of a closure", name)[]);
78             }
79             Normal => {
80                 self.sess.span_err(span,
81                                    format!("`{}` outside of loop", name)[]);
82             }
83         }
84     }
85 }