| // Copyright 2012 The Rust Project Developers. See the COPYRIGHT |
| // file at the top-level directory of this distribution and at |
| // http://rust-lang.org/COPYRIGHT. |
| // |
| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| // option. This file may not be copied, modified, or distributed |
| // except according to those terms. |
| |
| use parser::Parser; |
| use attr::parser_attr; |
| use codemap::{span, mk_sp}; |
| |
| type ctx = |
| @{sess: parse::parse_sess, |
| cfg: ast::crate_cfg}; |
| |
| fn eval_crate_directives(cx: ctx, |
| cdirs: ~[@ast::crate_directive], |
| prefix: &Path, |
| view_items: &mut~[@ast::view_item], |
| items: &mut~[@ast::item]) { |
| for cdirs.each |sub_cdir| { |
| eval_crate_directive(cx, *sub_cdir, prefix, view_items, items); |
| } |
| } |
| |
| pub fn eval_crate_directives_to_mod(cx: ctx, cdirs: ~[@ast::crate_directive], |
| prefix: &Path, suffix: &Option<Path>) |
| -> (ast::_mod, ~[ast::attribute]) { |
| let (cview_items, citems, cattrs) |
| = parse_companion_mod(cx, prefix, suffix); |
| let mut view_items: ~[@ast::view_item] = ~[]; |
| let mut items: ~[@ast::item] = ~[]; |
| eval_crate_directives(cx, cdirs, prefix, &mut view_items, &mut items); |
| return ({view_items: vec::append(view_items, cview_items), |
| items: vec::append(items, citems)}, |
| cattrs); |
| } |
| |
| /* |
| The 'companion mod'. So .rc crates and directory mod crate directives define |
| modules but not a .rs file to fill those mods with stuff. The companion mod is |
| a convention for location a .rs file to go with them. For .rc files the |
| companion mod is a .rs file with the same name; for directory mods the |
| companion mod is a .rs file with the same name as the directory. |
| |
| We build the path to the companion mod by combining the prefix and the |
| optional suffix then adding the .rs extension. |
| */ |
| fn parse_companion_mod(cx: ctx, prefix: &Path, suffix: &Option<Path>) |
| -> (~[@ast::view_item], ~[@ast::item], ~[ast::attribute]) { |
| |
| fn companion_file(prefix: &Path, suffix: &Option<Path>) -> Path { |
| return match *suffix { |
| option::Some(s) => prefix.push_many(s.components), |
| option::None => copy *prefix |
| }.with_filetype("rs"); |
| } |
| |
| fn file_exists(path: &Path) -> bool { |
| // Crude, but there's no lib function for this and I'm not |
| // up to writing it just now |
| match io::file_reader(path) { |
| result::Ok(_) => true, |
| result::Err(_) => false |
| } |
| } |
| |
| let modpath = &companion_file(prefix, suffix); |
| if file_exists(modpath) { |
| debug!("found companion mod"); |
| // XXX: Using a dummy span, but this code will go away soon |
| let p0 = new_sub_parser_from_file(cx.sess, cx.cfg, |
| modpath, |
| codemap::dummy_sp()); |
| let (inner, next) = p0.parse_inner_attrs_and_next(); |
| let m0 = p0.parse_mod_items(token::EOF, next); |
| return (m0.view_items, m0.items, inner); |
| } else { |
| return (~[], ~[], ~[]); |
| } |
| } |
| |
| fn cdir_path_opt(default: ~str, attrs: ~[ast::attribute]) -> ~str { |
| match ::attr::first_attr_value_str_by_name(attrs, ~"path") { |
| Some(d) => d, |
| None => default |
| } |
| } |
| |
| pub fn eval_src_mod(cx: ctx, prefix: &Path, |
| outer_attrs: ~[ast::attribute], |
| id: ast::ident, sp: span) |
| -> (ast::item_, ~[ast::attribute]) { |
| let file_path = Path(cdir_path_opt( |
| cx.sess.interner.get(id) + ~".rs", outer_attrs)); |
| eval_src_mod_from_path(cx, prefix, &file_path, outer_attrs, sp) |
| } |
| |
| pub fn eval_src_mod_from_path(cx: ctx, prefix: &Path, path: &Path, |
| outer_attrs: ~[ast::attribute], |
| sp: span) |
| -> (ast::item_, ~[ast::attribute]) { |
| let full_path = if path.is_absolute { |
| copy *path |
| } else { |
| prefix.push_many(path.components) |
| }; |
| let p0 = |
| new_sub_parser_from_file(cx.sess, cx.cfg, |
| &full_path, sp); |
| let (inner, next) = p0.parse_inner_attrs_and_next(); |
| let mod_attrs = vec::append(outer_attrs, inner); |
| let first_item_outer_attrs = next; |
| let m0 = p0.parse_mod_items(token::EOF, first_item_outer_attrs); |
| return (ast::item_mod(m0), mod_attrs); |
| } |
| |
| // XXX: Duplicated from parser.rs |
| fn mk_item(ctx: ctx, lo: BytePos, hi: BytePos, +ident: ast::ident, |
| +node: ast::item_, vis: ast::visibility, |
| +attrs: ~[ast::attribute]) -> @ast::item { |
| return @{ident: ident, |
| attrs: attrs, |
| id: next_node_id(ctx.sess), |
| node: node, |
| vis: vis, |
| span: mk_sp(lo, hi)}; |
| } |
| |
| fn eval_crate_directive(cx: ctx, cdir: @ast::crate_directive, prefix: &Path, |
| view_items: &mut ~[@ast::view_item], |
| items: &mut ~[@ast::item]) { |
| match cdir.node { |
| ast::cdir_src_mod(vis, id, attrs) => { |
| let (m, mod_attrs) = eval_src_mod(cx, prefix, attrs, id, cdir.span); |
| let i = mk_item(cx, cdir.span.lo, cdir.span.hi, |
| /* FIXME (#2543) */ copy id, |
| m, vis, mod_attrs); |
| items.push(i); |
| } |
| ast::cdir_dir_mod(vis, id, cdirs, attrs) => { |
| let path = Path(cdir_path_opt(*cx.sess.interner.get(id), attrs)); |
| let full_path = if path.is_absolute { |
| copy path |
| } else { |
| prefix.push_many(path.components) |
| }; |
| let (m0, a0) = eval_crate_directives_to_mod( |
| cx, cdirs, &full_path, &None); |
| let i = |
| @{ident: /* FIXME (#2543) */ copy id, |
| attrs: vec::append(attrs, a0), |
| id: cx.sess.next_id, |
| node: ast::item_mod(m0), |
| vis: vis, |
| span: cdir.span}; |
| cx.sess.next_id += 1; |
| items.push(i); |
| } |
| ast::cdir_view_item(vi) => view_items.push(vi), |
| } |
| } |
| // |
| // Local Variables: |
| // mode: rust |
| // fill-column: 78; |
| // indent-tabs-mode: nil |
| // c-basic-offset: 4 |
| // buffer-file-coding-system: utf-8-unix |
| // End: |
| // |