205 lines
7.7 KiB
Rust
205 lines
7.7 KiB
Rust
//! The main parser interface
|
|
import dvec::extensions;
|
|
|
|
export parse_sess;
|
|
export new_parse_sess, new_parse_sess_special_handler;
|
|
export next_node_id;
|
|
export new_parser_from_file, new_parser_etc_from_file;
|
|
export new_parser_from_source_str;
|
|
export new_parser_from_tt;
|
|
export parse_crate_from_file, parse_crate_from_crate_file;
|
|
export parse_crate_from_source_str;
|
|
export parse_expr_from_source_str, parse_item_from_source_str;
|
|
export parse_from_source_str;
|
|
|
|
import parser::parser;
|
|
import attr::parser_attr;
|
|
import common::parser_common;
|
|
import ast::node_id;
|
|
import util::interner;
|
|
// FIXME (#1935): resolve badness
|
|
import lexer::{string_reader_as_reader, tt_reader_as_reader, reader,
|
|
string_reader, tt_reader};
|
|
import diagnostic::{span_handler, mk_span_handler, mk_handler, emitter};
|
|
|
|
type parse_sess = @{
|
|
cm: codemap::codemap,
|
|
mut next_id: node_id,
|
|
span_diagnostic: span_handler,
|
|
interner: @interner::interner<@str>,
|
|
// these two must be kept up to date
|
|
mut chpos: uint,
|
|
mut byte_pos: uint
|
|
};
|
|
|
|
fn new_parse_sess(demitter: option<emitter>) -> parse_sess {
|
|
let cm = codemap::new_codemap();
|
|
ret @{cm: cm,
|
|
mut next_id: 1,
|
|
span_diagnostic: mk_span_handler(mk_handler(demitter), cm),
|
|
interner: @interner::mk::<@str>(|x| str::hash(*x),
|
|
|x,y| str::eq(*x, *y)),
|
|
mut chpos: 0u, mut byte_pos: 0u};
|
|
}
|
|
|
|
fn new_parse_sess_special_handler(sh: span_handler, cm: codemap::codemap)
|
|
-> parse_sess {
|
|
ret @{cm: cm,
|
|
mut next_id: 1,
|
|
span_diagnostic: sh,
|
|
interner: @interner::mk::<@str>(|x| str::hash(*x),
|
|
|x,y| str::eq(*x, *y)),
|
|
mut chpos: 0u, mut byte_pos: 0u};
|
|
}
|
|
|
|
fn parse_crate_from_file(input: str, cfg: ast::crate_cfg, sess: parse_sess) ->
|
|
@ast::crate {
|
|
if str::ends_with(input, ".rc") {
|
|
parse_crate_from_crate_file(input, cfg, sess)
|
|
} else if str::ends_with(input, ".rs") {
|
|
parse_crate_from_source_file(input, cfg, sess)
|
|
} else {
|
|
sess.span_diagnostic.handler().fatal("unknown input file type: " +
|
|
input)
|
|
}
|
|
}
|
|
|
|
fn parse_crate_from_crate_file(input: str, cfg: ast::crate_cfg,
|
|
sess: parse_sess) -> @ast::crate {
|
|
let (p, rdr) = new_parser_etc_from_file(sess, cfg, input,
|
|
parser::CRATE_FILE);
|
|
let lo = p.span.lo;
|
|
let prefix = path::dirname(input);
|
|
let leading_attrs = p.parse_inner_attrs_and_next();
|
|
let { inner: crate_attrs, next: first_cdir_attr } = leading_attrs;
|
|
let cdirs = p.parse_crate_directives(token::EOF, first_cdir_attr);
|
|
sess.chpos = rdr.chpos;
|
|
sess.byte_pos = sess.byte_pos + rdr.pos;
|
|
let cx = @{sess: sess, cfg: /* FIXME (#2543) */ copy p.cfg};
|
|
let (companionmod, _) = path::splitext(path::basename(input));
|
|
let (m, attrs) = eval::eval_crate_directives_to_mod(
|
|
cx, cdirs, prefix, option::some(companionmod));
|
|
let mut hi = p.span.hi;
|
|
p.expect(token::EOF);
|
|
ret @ast_util::respan(ast_util::mk_sp(lo, hi),
|
|
{directives: cdirs,
|
|
module: m,
|
|
attrs: vec::append(crate_attrs, attrs),
|
|
config: /* FIXME (#2543) */ copy p.cfg});
|
|
}
|
|
|
|
fn parse_crate_from_source_file(input: str, cfg: ast::crate_cfg,
|
|
sess: parse_sess) -> @ast::crate {
|
|
let (p, rdr) = new_parser_etc_from_file(sess, cfg, input,
|
|
parser::SOURCE_FILE);
|
|
let r = p.parse_crate_mod(cfg);
|
|
sess.chpos = rdr.chpos;
|
|
sess.byte_pos = sess.byte_pos + rdr.pos;
|
|
ret r;
|
|
}
|
|
|
|
fn parse_crate_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,
|
|
sess: parse_sess) -> @ast::crate {
|
|
let (p, rdr) = new_parser_etc_from_source_str(sess, cfg, name,
|
|
codemap::fss_none, source);
|
|
let r = p.parse_crate_mod(cfg);
|
|
sess.chpos = rdr.chpos;
|
|
sess.byte_pos = sess.byte_pos + rdr.pos;
|
|
ret r;
|
|
}
|
|
|
|
fn parse_expr_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,
|
|
sess: parse_sess) -> @ast::expr {
|
|
let (p, rdr) = new_parser_etc_from_source_str(sess, cfg, name,
|
|
codemap::fss_none, source);
|
|
let r = p.parse_expr();
|
|
sess.chpos = rdr.chpos;
|
|
sess.byte_pos = sess.byte_pos + rdr.pos;
|
|
ret r;
|
|
}
|
|
|
|
fn parse_item_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,
|
|
+attrs: ~[ast::attribute],
|
|
vis: ast::visibility,
|
|
sess: parse_sess) -> option<@ast::item> {
|
|
let (p, rdr) = new_parser_etc_from_source_str(sess, cfg, name,
|
|
codemap::fss_none, source);
|
|
let r = p.parse_item(attrs, vis);
|
|
sess.chpos = rdr.chpos;
|
|
sess.byte_pos = sess.byte_pos + rdr.pos;
|
|
ret r;
|
|
}
|
|
|
|
fn parse_from_source_str<T>(f: fn (p: parser) -> T,
|
|
name: str, ss: codemap::file_substr,
|
|
source: @str, cfg: ast::crate_cfg,
|
|
sess: parse_sess)
|
|
-> T
|
|
{
|
|
let (p, rdr) = new_parser_etc_from_source_str(sess, cfg, name, ss,
|
|
source);
|
|
let r = f(p);
|
|
if !p.reader.is_eof() {
|
|
p.reader.fatal("expected end-of-string");
|
|
}
|
|
sess.chpos = rdr.chpos;
|
|
sess.byte_pos = sess.byte_pos + rdr.pos;
|
|
ret r;
|
|
}
|
|
|
|
fn next_node_id(sess: parse_sess) -> node_id {
|
|
let rv = sess.next_id;
|
|
sess.next_id += 1;
|
|
// ID 0 is reserved for the crate and doesn't actually exist in the AST
|
|
assert rv != 0;
|
|
ret rv;
|
|
}
|
|
|
|
fn new_parser_etc_from_source_str(sess: parse_sess, cfg: ast::crate_cfg,
|
|
+name: str, +ss: codemap::file_substr,
|
|
source: @str) -> (parser, string_reader) {
|
|
let ftype = parser::SOURCE_FILE;
|
|
let filemap = codemap::new_filemap_w_substr
|
|
(name, ss, source, sess.chpos, sess.byte_pos);
|
|
sess.cm.files.push(filemap);
|
|
let srdr = lexer::new_string_reader(sess.span_diagnostic, filemap,
|
|
sess.interner);
|
|
ret (parser(sess, cfg, srdr as reader, ftype), srdr);
|
|
}
|
|
|
|
fn new_parser_from_source_str(sess: parse_sess, cfg: ast::crate_cfg,
|
|
+name: str, +ss: codemap::file_substr,
|
|
source: @str) -> parser {
|
|
let (p, _) = new_parser_etc_from_source_str(sess, cfg, name, ss, source);
|
|
ret p;
|
|
}
|
|
|
|
|
|
fn new_parser_etc_from_file(sess: parse_sess, cfg: ast::crate_cfg, +path: str,
|
|
ftype: parser::file_type) ->
|
|
(parser, string_reader) {
|
|
let res = io::read_whole_file_str(path);
|
|
alt res {
|
|
result::ok(_) { /* Continue. */ }
|
|
result::err(e) { sess.span_diagnostic.handler().fatal(e); }
|
|
}
|
|
let src = @result::unwrap(res);
|
|
let filemap = codemap::new_filemap(path, src, sess.chpos, sess.byte_pos);
|
|
sess.cm.files.push(filemap);
|
|
let srdr = lexer::new_string_reader(sess.span_diagnostic, filemap,
|
|
sess.interner);
|
|
ret (parser(sess, cfg, srdr as reader, ftype), srdr);
|
|
}
|
|
|
|
fn new_parser_from_file(sess: parse_sess, cfg: ast::crate_cfg, +path: str,
|
|
ftype: parser::file_type) -> parser {
|
|
let (p, _) = new_parser_etc_from_file(sess, cfg, path, ftype);
|
|
ret p;
|
|
}
|
|
|
|
fn new_parser_from_tt(sess: parse_sess, cfg: ast::crate_cfg,
|
|
tt: ~[ast::token_tree]) -> parser {
|
|
let trdr = lexer::new_tt_reader(sess.span_diagnostic, sess.interner, tt);
|
|
ret parser(sess, cfg, trdr as reader, parser::SOURCE_FILE)
|
|
}
|