rust/src/libsyntax/parse/mod.rs

379 lines
9.7 KiB
Rust
Raw Normal View History

// 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.
2012-11-28 18:20:41 -06:00
//! The main parser interface
2013-01-30 11:56:33 -06:00
use ast::node_id;
use ast;
2013-03-26 15:38:07 -05:00
use codemap::{span, CodeMap};
use codemap;
use diagnostic::{span_handler, mk_span_handler, mk_handler, Emitter};
use parse::attr::parser_attr;
2013-03-26 15:38:07 -05:00
use parse::lexer::reader;
use parse::parser::Parser;
use parse::token::{ident_interner, mk_ident_interner};
use core::io;
2013-03-26 15:38:07 -05:00
use core::option::{None, Option};
use core::path::Path;
use core::result::{Err, Ok, Result};
pub mod lexer;
pub mod parser;
pub mod token;
pub mod comments;
pub mod attr;
2012-11-18 19:56:50 -06:00
2013-01-30 11:56:33 -06:00
2012-11-18 19:56:50 -06:00
/// Common routines shared by parser mods
pub mod common;
2012-11-18 19:56:50 -06:00
/// Functions dealing with operator precedence
pub mod prec;
2012-11-18 19:56:50 -06:00
/// Routines the parser uses to classify AST nodes
pub mod classify;
2012-11-18 19:56:50 -06:00
/// Reporting obsolete syntax
pub mod obsolete;
2012-11-28 18:20:41 -06:00
2013-03-08 12:19:19 -06:00
// info about a parsing session.
// This structure and the reader both have
// an interner associated with them. If they're
// not the same, bad things can happen.
pub struct ParseSess {
2013-03-08 12:19:19 -06:00
cm: @codemap::CodeMap, // better be the same as the one in the reader!
next_id: node_id,
2013-03-08 12:19:19 -06:00
span_diagnostic: @span_handler, // better be the same as the one in the reader!
2012-11-28 18:20:41 -06:00
interner: @ident_interner,
}
2012-11-28 18:20:41 -06:00
pub fn new_parse_sess(demitter: Option<Emitter>) -> @mut ParseSess {
2012-11-28 18:20:41 -06:00
let cm = @CodeMap::new();
@mut ParseSess {
cm: cm,
next_id: 1,
span_diagnostic: mk_span_handler(mk_handler(demitter), cm),
interner: mk_ident_interner(),
}
2012-11-28 18:20:41 -06:00
}
pub fn new_parse_sess_special_handler(sh: @span_handler,
cm: @codemap::CodeMap)
-> @mut ParseSess {
@mut ParseSess {
cm: cm,
next_id: 1,
span_diagnostic: sh,
interner: mk_ident_interner(),
}
2012-11-28 18:20:41 -06:00
}
2013-02-11 15:36:24 -06:00
// a bunch of utility functions of the form parse_<thing>_from_<source>
// where <thing> includes crate, expr, item, stmt, tts, and one that
// uses a HOF to parse anything, and <source> includes file and
// source_str.
// this appears to be the main entry point for rust parsing by
// rustc and crate:
pub fn parse_crate_from_file(
input: &Path,
cfg: ast::crate_cfg,
sess: @mut ParseSess
) -> @ast::crate {
let p = new_parser_from_file(sess, /*bad*/ copy cfg, input);
p.parse_crate_mod(/*bad*/ copy cfg)
2013-02-11 15:36:24 -06:00
// why is there no p.abort_if_errors here?
2012-11-28 18:20:41 -06:00
}
pub fn parse_crate_from_source_str(
name: ~str,
source: @~str,
cfg: ast::crate_cfg,
sess: @mut ParseSess
) -> @ast::crate {
let p = new_parser_from_source_str(
sess,
/*bad*/ copy cfg,
/*bad*/ copy name,
codemap::FssNone,
source
);
maybe_aborted(p.parse_crate_mod(/*bad*/ copy cfg),p)
2012-11-28 18:20:41 -06:00
}
pub fn parse_expr_from_source_str(
name: ~str,
source: @~str,
+cfg: ast::crate_cfg,
sess: @mut ParseSess
) -> @ast::expr {
let p = new_parser_from_source_str(
sess,
cfg,
/*bad*/ copy name,
codemap::FssNone,
source
);
maybe_aborted(p.parse_expr(), p)
2012-11-28 18:20:41 -06:00
}
pub fn parse_item_from_source_str(
name: ~str,
source: @~str,
+cfg: ast::crate_cfg,
+attrs: ~[ast::attribute],
sess: @mut ParseSess
) -> Option<@ast::item> {
let p = new_parser_from_source_str(
sess,
cfg,
/*bad*/ copy name,
codemap::FssNone,
source
);
maybe_aborted(p.parse_item(attrs),p)
2012-11-28 18:20:41 -06:00
}
pub fn parse_meta_from_source_str(
name: ~str,
source: @~str,
+cfg: ast::crate_cfg,
sess: @mut ParseSess
) -> @ast::meta_item {
let p = new_parser_from_source_str(
sess,
cfg,
/*bad*/ copy name,
codemap::FssNone,
source
);
maybe_aborted(p.parse_meta_item(),p)
}
pub fn parse_stmt_from_source_str(
name: ~str,
source: @~str,
+cfg: ast::crate_cfg,
+attrs: ~[ast::attribute],
sess: @mut ParseSess
) -> @ast::stmt {
let p = new_parser_from_source_str(
sess,
cfg,
/*bad*/ copy name,
codemap::FssNone,
source
);
maybe_aborted(p.parse_stmt(attrs),p)
2012-11-28 18:20:41 -06:00
}
pub fn parse_tts_from_source_str(
name: ~str,
source: @~str,
+cfg: ast::crate_cfg,
sess: @mut ParseSess
) -> ~[ast::token_tree] {
let p = new_parser_from_source_str(
sess,
cfg,
/*bad*/ copy name,
codemap::FssNone,
source
);
*p.quote_depth += 1u;
maybe_aborted(p.parse_all_token_trees(),p)
2012-11-28 18:20:41 -06:00
}
pub fn parse_from_source_str<T>(
f: &fn (Parser) -> T,
name: ~str, ss: codemap::FileSubstr,
source: @~str,
+cfg: ast::crate_cfg,
sess: @mut ParseSess
) -> T {
2013-02-26 08:35:36 -06:00
let p = new_parser_from_source_str(
sess,
cfg,
/*bad*/ copy name,
/*bad*/ copy ss,
source
);
2012-11-28 18:20:41 -06:00
let r = f(p);
if !p.reader.is_eof() {
p.reader.fatal(~"expected end-of-string");
}
maybe_aborted(r,p)
2012-11-28 18:20:41 -06:00
}
pub fn next_node_id(sess: @mut ParseSess) -> node_id {
2012-11-28 18:20:41 -06:00
let rv = sess.next_id;
sess.next_id += 1;
// ID 0 is reserved for the crate and doesn't actually exist in the AST
fail_unless!(rv != 0);
2012-11-28 18:20:41 -06:00
return rv;
}
pub fn new_parser_from_source_str(sess: @mut ParseSess,
+cfg: ast::crate_cfg,
+name: ~str,
+ss: codemap::FileSubstr,
source: @~str)
-> Parser {
2012-11-28 18:20:41 -06:00
let filemap = sess.cm.new_filemap_w_substr(name, ss, source);
let srdr = lexer::new_string_reader(
copy sess.span_diagnostic,
filemap,
sess.interner
);
Parser(sess, cfg, srdr as @reader)
2012-11-28 18:20:41 -06:00
}
/// Read the entire source file, return a parser
/// that draws from that string
pub fn new_parser_result_from_file(
sess: @mut ParseSess,
+cfg: ast::crate_cfg,
path: &Path
) -> Result<Parser, ~str> {
2012-11-28 18:20:41 -06:00
match io::read_whole_file_str(path) {
Ok(src) => {
let filemap = sess.cm.new_filemap(path.to_str(), @src);
let srdr = lexer::new_string_reader(copy sess.span_diagnostic,
filemap,
sess.interner);
Ok(Parser(sess, cfg, srdr as @reader))
2012-11-28 18:20:41 -06:00
}
Err(e) => Err(e)
2012-11-28 18:20:41 -06:00
}
}
/// Create a new parser, handling errors as appropriate
2012-11-28 18:20:41 -06:00
/// if the file doesn't exist
pub fn new_parser_from_file(
sess: @mut ParseSess,
+cfg: ast::crate_cfg,
path: &Path
) -> Parser {
2013-02-11 15:36:24 -06:00
match new_parser_result_from_file(sess, cfg, path) {
Ok(parser) => parser,
Err(e) => {
2012-11-28 18:20:41 -06:00
sess.span_diagnostic.handler().fatal(e)
}
}
}
/// Create a new parser based on a span from an existing parser. Handles
/// error messages correctly when the file does not exist.
pub fn new_sub_parser_from_file(
sess: @mut ParseSess,
+cfg: ast::crate_cfg,
path: &Path,
sp: span
) -> Parser {
2013-02-11 15:36:24 -06:00
match new_parser_result_from_file(sess, cfg, path) {
Ok(parser) => parser,
Err(e) => {
2012-11-28 18:20:41 -06:00
sess.span_diagnostic.span_fatal(sp, e)
}
}
}
pub fn new_parser_from_tts(
sess: @mut ParseSess,
+cfg: ast::crate_cfg,
+tts: ~[ast::token_tree]
) -> Parser {
let trdr = lexer::new_tt_reader(
copy sess.span_diagnostic,
sess.interner,
None,
tts
);
Parser(sess, cfg, trdr as @reader)
2012-11-28 18:20:41 -06:00
}
2013-01-30 11:56:33 -06:00
// abort if necessary
pub fn maybe_aborted<T>(+result : T, p: Parser) -> T {
p.abort_if_errors();
result
}
2013-02-04 15:15:17 -06:00
#[cfg(test)]
mod test {
use super::*;
use std::serialize::Encodable;
use std;
use core::io;
use core::option::None;
2013-02-04 15:15:17 -06:00
#[test] fn to_json_str<E : Encodable<std::json::Encoder>>(val: @E) -> ~str {
2013-03-07 22:44:38 -06:00
do io::with_str_writer |writer| {
val.encode(~std::json::Encoder(writer));
}
2013-02-04 15:15:17 -06:00
}
#[test] fn alltts () {
let tts = parse_tts_from_source_str(
~"bogofile",
@~"fn foo (x : int) { x; }",
~[],
new_parse_sess(None));
assert_eq!(
to_json_str(@tts),
~"[\
[\"tt_tok\",null,[\"IDENT\",\"fn\",false]],\
[\"tt_tok\",null,[\"IDENT\",\"foo\",false]],\
[\
\"tt_delim\",\
[\
[\"tt_tok\",null,\"LPAREN\"],\
[\"tt_tok\",null,[\"IDENT\",\"x\",false]],\
[\"tt_tok\",null,\"COLON\"],\
[\"tt_tok\",null,[\"IDENT\",\"int\",false]],\
[\"tt_tok\",null,\"RPAREN\"]\
]\
],\
[\
\"tt_delim\",\
[\
[\"tt_tok\",null,\"LBRACE\"],\
[\"tt_tok\",null,[\"IDENT\",\"x\",false]],\
[\"tt_tok\",null,\"SEMI\"],\
[\"tt_tok\",null,\"RBRACE\"]\
]\
]\
]"
);
2013-02-04 15:15:17 -06:00
let ast1 = new_parser_from_tts(new_parse_sess(None),~[],tts)
.parse_item(~[]);
let ast2 = parse_item_from_source_str(
~"bogofile",
@~"fn foo (x : int) { x; }",
~[],~[],
new_parse_sess(None));
assert_eq!(ast1,ast2);
2013-02-04 15:15:17 -06:00
}
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//