//! 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; import diagnostic::{span_handler, mk_span_handler, mk_handler, emitter}; import lexer::{reader, string_reader, string_reader_as_reader}; import lexer::{tt_reader_as_reader}; 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) -> 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(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, none, tt); ret parser(sess, cfg, trdr as reader, parser::SOURCE_FILE) }