(index<- )        ./librustc/middle/entry.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2012 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  
  11  
  12  use driver::session;
  13  use driver::session::Session;
  14  use syntax::ast::{Crate, Name, NodeId, Item, ItemFn};
  15  use syntax::ast_map;
  16  use syntax::attr;
  17  use syntax::codemap::Span;
  18  use syntax::parse::token;
  19  use syntax::visit;
  20  use syntax::visit::Visitor;
  21  
  22  struct EntryContext<'a> {
  23      session: &'a Session,
  24  
  25      ast_map: &'a ast_map::Map,
  26  
  27      // The interned Name for "main".
  28      main_name: Name,
  29  
  30      // The top-level function called 'main'
  31      main_fn: Option<(NodeId, Span)>,
  32  
  33      // The function that has attribute named 'main'
  34      attr_main_fn: Option<(NodeId, Span)>,
  35  
  36      // The function that has the attribute 'start' on it
  37      start_fn: Option<(NodeId, Span)>,
  38  
  39      // The functions that one might think are 'main' but aren't, e.g.
  40      // main functions not defined at the top level. For diagnostics.
  41      non_main_fns: Vec<(NodeId, Span)> ,
  42  }
  43  
  44  impl<'a> Visitor<()> for EntryContext<'a> {
  45      fn visit_item(&mut self, item&Item, _:()) {
  46          find_item(item, self);
  47      }
  48  }
  49  
  50  pub fn find_entry_point(session: &Session, krate: &Crate, ast_map: &ast_map::Map) {
  51      let any_exe = session.crate_types.borrow().iter().any(|ty| {
  52          *ty == session::CrateTypeExecutable
  53      });
  54      if !any_exe {
  55          // No need to find a main function
  56          return
  57      }
  58  
  59      // If the user wants no main function at all, then stop here.
  60      if attr::contains_name(krate.attrs.as_slice(), "no_main") {
  61          session.entry_type.set(Some(session::EntryNone));
  62          return
  63      }
  64  
  65      let mut ctxt = EntryContext {
  66          session: session,
  67          main_name: token::intern("main"),
  68          ast_map: ast_map,
  69          main_fn: None,
  70          attr_main_fn: None,
  71          start_fn: None,
  72          non_main_fns: Vec::new(),
  73      };
  74  
  75      visit::walk_crate(&mut ctxt, krate, ());
  76  
  77      configure_main(&mut ctxt);
  78  }
  79  
  80  fn find_item(item: &Item, ctxt: &mut EntryContext) {
  81      match item.node {
  82          ItemFn(..) => {
  83              if item.ident.name == ctxt.main_name {
  84                   ctxt.ast_map.with_path(item.id, |mut path| {
  85                          if path.len() == 1 {
  86                              // This is a top-level function so can be 'main'
  87                              if ctxt.main_fn.is_none() {
  88                                  ctxt.main_fn = Some((item.id, item.span));
  89                              } else {
  90                                  ctxt.session.span_err(
  91                                      item.span,
  92                                      "multiple 'main' functions");
  93                              }
  94                          } else {
  95                              // This isn't main
  96                              ctxt.non_main_fns.push((item.id, item.span));
  97                          }
  98                  });
  99              }
 100  
 101              if attr::contains_name(item.attrs.as_slice(), "main") {
 102                  if ctxt.attr_main_fn.is_none() {
 103                      ctxt.attr_main_fn = Some((item.id, item.span));
 104                  } else {
 105                      ctxt.session.span_err(
 106                          item.span,
 107                          "multiple 'main' functions");
 108                  }
 109              }
 110  
 111              if attr::contains_name(item.attrs.as_slice(), "start") {
 112                  if ctxt.start_fn.is_none() {
 113                      ctxt.start_fn = Some((item.id, item.span));
 114                  } else {
 115                      ctxt.session.span_err(
 116                          item.span,
 117                          "multiple 'start' functions");
 118                  }
 119              }
 120          }
 121          _ => ()
 122      }
 123  
 124      visit::walk_item(ctxt, item, ());
 125  }
 126  
 127  fn configure_main(this: &mut EntryContext) {
 128      if this.start_fn.is_some() {
 129          *this.session.entry_fn.borrow_mut() = this.start_fn;
 130          this.session.entry_type.set(Some(session::EntryStart));
 131      } else if this.attr_main_fn.is_some() {
 132          *this.session.entry_fn.borrow_mut() = this.attr_main_fn;
 133          this.session.entry_type.set(Some(session::EntryMain));
 134      } else if this.main_fn.is_some() {
 135          *this.session.entry_fn.borrow_mut() = this.main_fn;
 136          this.session.entry_type.set(Some(session::EntryMain));
 137      } else {
 138          // No main function
 139          this.session.err("main function not found");
 140          if !this.non_main_fns.is_empty() {
 141              // There were some functions named 'main' though. Try to give the user a hint.
 142              this.session.note("the main function must be defined at the crate level \
 143                                 but you have one or more functions named 'main' that are not \
 144                                 defined at the crate level. Either move the definition or \
 145                                 attach the `#[main]` attribute to override this behavior.");
 146              for &(_, span) in this.non_main_fns.iter() {
 147                  this.session.span_note(span, "here is a function named 'main'");
 148              }
 149              this.session.abort_if_errors();
 150          }
 151      }
 152  }