2012-12-04 00:48:01 +00:00
|
|
|
// 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-29 00:20:41 +00:00
|
|
|
//! The main parser interface
|
|
|
|
|
2013-01-30 17:56:33 +00:00
|
|
|
|
2012-12-23 22:41:37 +00:00
|
|
|
use ast::node_id;
|
|
|
|
use ast;
|
|
|
|
use codemap::{span, CodeMap, FileMap, CharPos, BytePos};
|
|
|
|
use codemap;
|
2013-02-04 22:02:01 +00:00
|
|
|
use diagnostic::{span_handler, mk_span_handler, mk_handler, Emitter};
|
2012-12-23 22:41:37 +00:00
|
|
|
use parse::attr::parser_attr;
|
2013-02-04 22:02:01 +00:00
|
|
|
use parse::lexer::{reader, StringReader};
|
2012-12-23 22:41:37 +00:00
|
|
|
use parse::parser::Parser;
|
|
|
|
use parse::token::{ident_interner, mk_ident_interner};
|
|
|
|
|
|
|
|
use core::io;
|
2013-01-09 03:37:25 +00:00
|
|
|
use core::option::{None, Option, Some};
|
|
|
|
use core::path::Path;
|
|
|
|
use core::result::{Err, Ok, Result};
|
2012-12-23 22:41:37 +00:00
|
|
|
|
2013-01-09 03:37:25 +00:00
|
|
|
pub mod lexer;
|
|
|
|
pub mod parser;
|
|
|
|
pub mod token;
|
|
|
|
pub mod comments;
|
|
|
|
pub mod attr;
|
2012-11-19 01:56:50 +00:00
|
|
|
|
2013-01-30 17:56:33 +00:00
|
|
|
|
2012-11-19 01:56:50 +00:00
|
|
|
/// Common routines shared by parser mods
|
2013-01-09 03:37:25 +00:00
|
|
|
pub mod common;
|
2012-11-19 01:56:50 +00:00
|
|
|
|
|
|
|
/// Functions dealing with operator precedence
|
2013-01-09 03:37:25 +00:00
|
|
|
pub mod prec;
|
2012-11-19 01:56:50 +00:00
|
|
|
|
|
|
|
/// Routines the parser uses to classify AST nodes
|
2013-01-09 03:37:25 +00:00
|
|
|
pub mod classify;
|
2012-11-19 01:56:50 +00:00
|
|
|
|
|
|
|
/// Reporting obsolete syntax
|
2013-01-09 03:37:25 +00:00
|
|
|
pub mod obsolete;
|
2012-11-29 00:20:41 +00:00
|
|
|
|
2013-02-21 08:16:31 +00:00
|
|
|
pub struct ParseSess {
|
2012-11-29 00:20:41 +00:00
|
|
|
cm: @codemap::CodeMap,
|
2013-02-21 08:16:31 +00:00
|
|
|
next_id: node_id,
|
2013-03-12 20:00:50 +00:00
|
|
|
span_diagnostic: @span_handler,
|
2012-11-29 00:20:41 +00:00
|
|
|
interner: @ident_interner,
|
2013-02-21 08:16:31 +00:00
|
|
|
}
|
2012-11-29 00:20:41 +00:00
|
|
|
|
2013-02-21 08:16:31 +00:00
|
|
|
pub fn new_parse_sess(demitter: Option<Emitter>) -> @mut ParseSess {
|
2012-11-29 00:20:41 +00:00
|
|
|
let cm = @CodeMap::new();
|
2013-02-21 08:16:31 +00:00
|
|
|
@mut ParseSess {
|
|
|
|
cm: cm,
|
|
|
|
next_id: 1,
|
|
|
|
span_diagnostic: mk_span_handler(mk_handler(demitter), cm),
|
|
|
|
interner: mk_ident_interner(),
|
|
|
|
}
|
2012-11-29 00:20:41 +00:00
|
|
|
}
|
|
|
|
|
2013-03-12 20:00:50 +00:00
|
|
|
pub fn new_parse_sess_special_handler(sh: @span_handler,
|
|
|
|
cm: @codemap::CodeMap)
|
|
|
|
-> @mut ParseSess {
|
2013-02-21 08:16:31 +00:00
|
|
|
@mut ParseSess {
|
|
|
|
cm: cm,
|
|
|
|
next_id: 1,
|
|
|
|
span_diagnostic: sh,
|
|
|
|
interner: mk_ident_interner(),
|
|
|
|
}
|
2012-11-29 00:20:41 +00:00
|
|
|
}
|
|
|
|
|
2013-02-11 21:36:24 +00: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:
|
2013-02-27 04:18:01 +00:00
|
|
|
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 21:36:24 +00:00
|
|
|
// why is there no p.abort_if_errors here?
|
2012-11-29 00:20:41 +00:00
|
|
|
}
|
|
|
|
|
2013-02-27 04:18:01 +00: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
|
|
|
|
);
|
2013-02-27 19:03:21 +00:00
|
|
|
maybe_aborted(p.parse_crate_mod(/*bad*/ copy cfg),p)
|
2012-11-29 00:20:41 +00:00
|
|
|
}
|
|
|
|
|
2013-02-27 04:18:01 +00: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
|
|
|
|
);
|
2013-02-26 18:15:29 +00:00
|
|
|
maybe_aborted(p.parse_expr(), p)
|
2012-11-29 00:20:41 +00:00
|
|
|
}
|
|
|
|
|
2013-02-27 04:18:01 +00: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
|
|
|
|
);
|
2013-02-26 18:15:29 +00:00
|
|
|
maybe_aborted(p.parse_item(attrs),p)
|
2012-11-29 00:20:41 +00:00
|
|
|
}
|
|
|
|
|
2013-01-19 15:52:06 +00: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)
|
|
|
|
}
|
|
|
|
|
2013-02-27 04:18:01 +00:00
|
|
|
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
|
|
|
|
);
|
2013-02-26 18:15:29 +00:00
|
|
|
maybe_aborted(p.parse_stmt(attrs),p)
|
2012-11-29 00:20:41 +00:00
|
|
|
}
|
|
|
|
|
2013-02-27 04:18:01 +00: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
|
|
|
|
);
|
2013-02-22 02:12:13 +00:00
|
|
|
*p.quote_depth += 1u;
|
2013-02-26 18:15:29 +00:00
|
|
|
maybe_aborted(p.parse_all_token_trees(),p)
|
2012-11-29 00:20:41 +00:00
|
|
|
}
|
|
|
|
|
2013-02-27 04:18:01 +00:00
|
|
|
pub fn parse_from_source_str<T>(
|
2013-03-07 22:38:38 +00:00
|
|
|
f: &fn (Parser) -> T,
|
2013-02-27 04:18:01 +00:00
|
|
|
name: ~str, ss: codemap::FileSubstr,
|
|
|
|
source: @~str,
|
|
|
|
+cfg: ast::crate_cfg,
|
|
|
|
sess: @mut ParseSess
|
|
|
|
) -> T {
|
2013-02-26 14:35:36 +00:00
|
|
|
let p = new_parser_from_source_str(
|
|
|
|
sess,
|
|
|
|
cfg,
|
|
|
|
/*bad*/ copy name,
|
|
|
|
/*bad*/ copy ss,
|
|
|
|
source
|
|
|
|
);
|
2012-11-29 00:20:41 +00:00
|
|
|
let r = f(p);
|
|
|
|
if !p.reader.is_eof() {
|
|
|
|
p.reader.fatal(~"expected end-of-string");
|
|
|
|
}
|
2013-02-26 18:15:29 +00:00
|
|
|
maybe_aborted(r,p)
|
2012-11-29 00:20:41 +00:00
|
|
|
}
|
|
|
|
|
2013-02-21 08:16:31 +00:00
|
|
|
pub fn next_node_id(sess: @mut ParseSess) -> node_id {
|
2012-11-29 00:20:41 +00: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
|
2013-03-06 21:58:02 +00:00
|
|
|
fail_unless!(rv != 0);
|
2012-11-29 00:20:41 +00:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2013-03-12 20:00:50 +00:00
|
|
|
pub fn new_parser_from_source_str(sess: @mut ParseSess,
|
|
|
|
+cfg: ast::crate_cfg,
|
|
|
|
+name: ~str,
|
|
|
|
+ss: codemap::FileSubstr,
|
|
|
|
source: @~str)
|
|
|
|
-> Parser {
|
2012-11-29 00:20:41 +00:00
|
|
|
let filemap = sess.cm.new_filemap_w_substr(name, ss, source);
|
2013-02-27 04:18:01 +00:00
|
|
|
let srdr = lexer::new_string_reader(
|
|
|
|
copy sess.span_diagnostic,
|
|
|
|
filemap,
|
|
|
|
sess.interner
|
|
|
|
);
|
2013-03-12 20:00:50 +00:00
|
|
|
Parser(sess, cfg, srdr as @reader)
|
2012-11-29 00:20:41 +00:00
|
|
|
}
|
|
|
|
|
2013-02-26 18:15:29 +00:00
|
|
|
/// Read the entire source file, return a parser
|
|
|
|
/// that draws from that string
|
2013-02-27 04:18:01 +00:00
|
|
|
pub fn new_parser_result_from_file(
|
|
|
|
sess: @mut ParseSess,
|
|
|
|
+cfg: ast::crate_cfg,
|
|
|
|
path: &Path
|
|
|
|
) -> Result<Parser, ~str> {
|
2012-11-29 00:20:41 +00:00
|
|
|
match io::read_whole_file_str(path) {
|
2013-02-27 04:18:01 +00:00
|
|
|
Ok(src) => {
|
|
|
|
let filemap = sess.cm.new_filemap(path.to_str(), @src);
|
2013-03-12 20:00:50 +00:00
|
|
|
let srdr = lexer::new_string_reader(copy sess.span_diagnostic,
|
|
|
|
filemap,
|
|
|
|
sess.interner);
|
|
|
|
Ok(Parser(sess, cfg, srdr as @reader))
|
2012-11-29 00:20:41 +00:00
|
|
|
|
2013-02-27 04:18:01 +00:00
|
|
|
}
|
|
|
|
Err(e) => Err(e)
|
2012-11-29 00:20:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-26 18:15:29 +00:00
|
|
|
/// Create a new parser, handling errors as appropriate
|
2012-11-29 00:20:41 +00:00
|
|
|
/// if the file doesn't exist
|
2013-02-27 04:18:01 +00:00
|
|
|
pub fn new_parser_from_file(
|
|
|
|
sess: @mut ParseSess,
|
|
|
|
+cfg: ast::crate_cfg,
|
|
|
|
path: &Path
|
|
|
|
) -> Parser {
|
2013-02-11 21:36:24 +00:00
|
|
|
match new_parser_result_from_file(sess, cfg, path) {
|
2013-02-15 09:15:53 +00:00
|
|
|
Ok(parser) => parser,
|
|
|
|
Err(e) => {
|
2012-11-29 00:20:41 +00: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.
|
2013-02-27 04:18:01 +00:00
|
|
|
pub fn new_sub_parser_from_file(
|
|
|
|
sess: @mut ParseSess,
|
|
|
|
+cfg: ast::crate_cfg,
|
|
|
|
path: &Path,
|
|
|
|
sp: span
|
|
|
|
) -> Parser {
|
2013-02-11 21:36:24 +00:00
|
|
|
match new_parser_result_from_file(sess, cfg, path) {
|
2013-02-15 09:15:53 +00:00
|
|
|
Ok(parser) => parser,
|
|
|
|
Err(e) => {
|
2012-11-29 00:20:41 +00:00
|
|
|
sess.span_diagnostic.span_fatal(sp, e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-27 04:18:01 +00:00
|
|
|
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
|
|
|
|
);
|
2013-03-12 20:00:50 +00:00
|
|
|
Parser(sess, cfg, trdr as @reader)
|
2012-11-29 00:20:41 +00:00
|
|
|
}
|
2013-01-30 17:56:33 +00:00
|
|
|
|
2013-02-26 18:15:29 +00:00
|
|
|
// abort if necessary
|
|
|
|
pub fn maybe_aborted<T>(+result : T, p: Parser) -> T {
|
|
|
|
p.abort_if_errors();
|
|
|
|
result
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-02-04 21:15:17 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
use std::serialize::Encodable;
|
|
|
|
use std;
|
2013-02-25 19:11:21 +00:00
|
|
|
use core::io;
|
|
|
|
use core::option::None;
|
2013-02-04 21:15:17 +00:00
|
|
|
|
2013-03-15 16:17:49 +00:00
|
|
|
#[test] fn to_json_str<E : Encodable<std::json::Encoder>>(val: @E) -> ~str {
|
2013-03-08 04:44:38 +00:00
|
|
|
do io::with_str_writer |writer| {
|
|
|
|
val.encode(~std::json::Encoder(writer));
|
|
|
|
}
|
2013-02-04 21:15:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test] fn alltts () {
|
|
|
|
let tts = parse_tts_from_source_str(
|
|
|
|
~"bogofile",
|
|
|
|
@~"fn foo (x : int) { x; }",
|
|
|
|
~[],
|
|
|
|
new_parse_sess(None));
|
2013-03-27 07:13:01 +00:00
|
|
|
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 21:15:17 +00: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));
|
2013-03-13 22:30:37 +00:00
|
|
|
assert_eq!(ast1,ast2);
|
2013-02-04 21:15:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Local Variables:
|
|
|
|
// mode: rust
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
|
|
|
// End:
|
|
|
|
//
|