rust/src/libsyntax/parse.rs

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)
}