astsrv.rs 5.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// 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.

11 12 13 14 15 16 17 18
/*!
Provides all access to AST-related, non-sendable info

Rustdoc is intended to be parallel, and the rustc AST is filled with
shared boxes. The AST service attempts to provide a single place to
query AST-related information, shielding the rest of Rustdoc from its
non-sendableness.
*/
19

20 21
use core::prelude::*;

22 23 24 25
use parse;
use util;

use core::oldcomm;
26
use core::vec;
27
use rustc::back::link;
P
Patrick Walton 已提交
28
use rustc::driver::driver;
29 30 31 32 33 34
use rustc::driver::session::Session;
use rustc::driver::session::{basic_options, options};
use rustc::driver::session;
use rustc::front;
use rustc::metadata::filesearch;
use std::map::HashMap;
P
Patrick Walton 已提交
35 36
use syntax::ast;
use syntax::ast_map;
37 38 39
use syntax::codemap;
use syntax::diagnostic::handler;
use syntax::diagnostic;
40
use syntax;
41

B
Brian Anderson 已提交
42
pub type Ctxt = {
43
    ast: @ast::crate,
44
    ast_map: ast_map::map
45 46
};

B
Brian Anderson 已提交
47
type SrvOwner<T> = fn(srv: Srv) -> T;
B
Brian Anderson 已提交
48
pub type CtxtHandler<T> = fn~(ctxt: Ctxt) -> T;
49
type Parser = fn~(Session, +s: ~str) -> @ast::crate;
50

B
Brian Anderson 已提交
51 52 53
enum Msg {
    HandleRequest(fn~(Ctxt)),
    Exit
54 55
}

B
Brian Anderson 已提交
56
pub enum Srv = {
57
    ch: oldcomm::Chan<Msg>
58
};
59

60 61 62 63
impl Srv: Clone {
    fn clone(&self) -> Srv { copy *self }
}

B
Brian Anderson 已提交
64
pub fn from_str<T>(source: ~str, owner: SrvOwner<T>) -> T {
65
    run(owner, source, parse::from_str_sess)
66
}
67

B
Brian Anderson 已提交
68
pub fn from_file<T>(file: ~str, owner: SrvOwner<T>) -> T {
69
    run(owner, file, |sess, f| parse::from_file_sess(sess, &Path(f)))
70 71
}

B
Brian Anderson 已提交
72
fn run<T>(owner: SrvOwner<T>, source: ~str, +parse: Parser) -> T {
73

B
Brian Anderson 已提交
74
    let srv_ = Srv({
75
        ch: do util::spawn_listener |move parse, po| {
76 77 78
            act(po, source, parse);
        }
    });
79

80
    let res = owner(srv_);
81
    oldcomm::send(srv_.ch, Exit);
T
Tim Chevalier 已提交
82
    move res
83 84
}

85
fn act(po: oldcomm::Port<Msg>, source: ~str, parse: Parser) {
86
    let sess = build_session();
87

88 89
    let ctxt = build_ctxt(
        sess,
90
        parse(sess, source)
91 92
    );

93
    let mut keep_going = true;
94
    while keep_going {
95
        match oldcomm::recv(po) {
B
Brian Anderson 已提交
96
          HandleRequest(f) => {
97 98
            f(ctxt);
          }
B
Brian Anderson 已提交
99
          Exit => {
100 101 102 103 104
            keep_going = false;
          }
        }
    }
}
105

B
Brian Anderson 已提交
106
pub fn exec<T:Owned>(
B
Brian Anderson 已提交
107 108
    srv: Srv,
    +f: fn~(ctxt: Ctxt) -> T
109
) -> T {
110 111
    let po = oldcomm::Port();
    let ch = oldcomm::Chan(&po);
B
Brian Anderson 已提交
112
    let msg = HandleRequest(fn~(move f, ctxt: Ctxt) {
113
        oldcomm::send(ch, f(ctxt))
114
    });
115 116
    oldcomm::send(srv.ch, move msg);
    oldcomm::recv(po)
117 118
}

119
fn build_ctxt(sess: Session,
B
Brian Anderson 已提交
120
              ast: @ast::crate) -> Ctxt {
121

122
    use rustc::front::config;
123 124

    let ast = config::strip_unconfigured_items(ast);
125 126
    let ast = syntax::ext::expand::expand_crate(sess.parse_sess,
                                                sess.opts.cfg, ast);
127
    let ast = front::test::modify_for_testing(sess, ast);
128
    let ast_map = ast_map::map_crate(sess.diagnostic(), *ast);
129

130 131
    {
        ast: ast,
132
        ast_map: ast_map,
133 134 135
    }
}

136
fn build_session() -> Session {
137
    let sopts: @options = basic_options();
B
Brian Anderson 已提交
138
    let codemap = @codemap::CodeMap::new();
139
    let error_handlers = build_error_handlers(codemap);
140
    let {emitter, span_handler} = error_handlers;
141

142
    let session = driver::build_session_(sopts, codemap, emitter,
143
                                         span_handler);
144
    session
145 146
}

B
Brian Anderson 已提交
147
type ErrorHandlers = {
148
    emitter: diagnostic::emitter,
149
    span_handler: diagnostic::span_handler
150 151 152 153 154
};

// Build a custom error handler that will allow us to ignore non-fatal
// errors
fn build_error_handlers(
155
    codemap: @codemap::CodeMap
B
Brian Anderson 已提交
156
) -> ErrorHandlers {
157

B
Brian Anderson 已提交
158
    type DiagnosticHandler = {
159 160 161
        inner: diagnostic::handler,
    };

B
Brian Anderson 已提交
162
    impl DiagnosticHandler: diagnostic::handler {
T
Tim Chevalier 已提交
163 164
        fn fatal(msg: &str) -> ! { self.inner.fatal(msg) }
        fn err(msg: &str) { self.inner.err(msg) }
165
        fn bump_err_count() {
166
            self.inner.bump_err_count();
167 168 169
        }
        fn has_errors() -> bool { self.inner.has_errors() }
        fn abort_if_errors() { self.inner.abort_if_errors() }
T
Tim Chevalier 已提交
170 171 172 173
        fn warn(msg: &str) { self.inner.warn(msg) }
        fn note(msg: &str) { self.inner.note(msg) }
        fn bug(msg: &str) -> ! { self.inner.bug(msg) }
        fn unimpl(msg: &str) -> ! { self.inner.unimpl(msg) }
174
        fn emit(cmsp: Option<(@codemap::CodeMap, codemap::span)>,
T
Tim Chevalier 已提交
175
                msg: &str, lvl: diagnostic::level) {
176 177 178 179
            self.inner.emit(cmsp, msg, lvl)
        }
    }

180
    let emitter = fn@(cmsp: Option<(@codemap::CodeMap, codemap::span)>,
T
Tim Chevalier 已提交
181
                       msg: &str, lvl: diagnostic::level) {
182
        diagnostic::emit(cmsp, msg, lvl);
183
    };
B
Brian Anderson 已提交
184
    let inner_handler = diagnostic::mk_handler(Some(emitter));
185 186 187 188 189 190 191 192
    let handler = {
        inner: inner_handler,
    };
    let span_handler = diagnostic::mk_span_handler(
        handler as diagnostic::handler, codemap);

    {
        emitter: emitter,
193
        span_handler: span_handler
194
    }
195 196
}

197 198
#[test]
fn should_prune_unconfigured_items() {
199
    let source = ~"#[cfg(shut_up_and_leave_me_alone)]fn a() { }";
B
Brian Anderson 已提交
200 201
    do from_str(source) |srv| {
        do exec(srv) |ctxt| {
202 203
            assert vec::is_empty(ctxt.ast.node.module.items);
        }
204 205 206
    }
}

207 208
#[test]
fn srv_should_build_ast_map() {
209
    let source = ~"fn a() { }";
B
Brian Anderson 已提交
210 211
    do from_str(source) |srv| {
        do exec(srv) |ctxt| {
212 213 214
            assert ctxt.ast_map.size() != 0u
        };
    }
215 216
}

217 218
#[test]
fn should_ignore_external_import_paths_that_dont_exist() {
219
    let source = ~"use forble; use forble::bippy;";
B
Brian Anderson 已提交
220
    from_str(source, |_srv| { } )
221 222
}

223 224
#[test]
fn srv_should_return_request_result() {
225
    let source = ~"fn a() { }";
B
Brian Anderson 已提交
226 227
    do from_str(source) |srv| {
        let result = exec(srv, |_ctxt| 1000 );
228 229
        assert result == 1000;
    }
230
}