]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/parse/mod.rs
Get rid of structural records in libsyntax and the last bit in librustc.
[rust.git] / src / libsyntax / parse / mod.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! The main parser interface
12
13
14 use ast::node_id;
15 use ast;
16 use codemap::{span, CodeMap, FileMap, CharPos, BytePos};
17 use codemap;
18 use diagnostic::{span_handler, mk_span_handler, mk_handler, Emitter};
19 use parse::attr::parser_attr;
20 use parse::lexer::{reader, StringReader};
21 use parse::parser::Parser;
22 use parse::token::{ident_interner, mk_ident_interner};
23 use util::interner;
24
25 use core::io;
26 use core::option::{None, Option, Some};
27 use core::path::Path;
28 use core::result::{Err, Ok, Result};
29 use core::result;
30
31 pub mod lexer;
32 pub mod parser;
33 pub mod token;
34 pub mod comments;
35 pub mod attr;
36
37
38 /// Common routines shared by parser mods
39 pub mod common;
40
41 /// Functions dealing with operator precedence
42 pub mod prec;
43
44 /// Routines the parser uses to classify AST nodes
45 pub mod classify;
46
47 /// Reporting obsolete syntax
48 pub mod obsolete;
49
50 pub struct ParseSess {
51     cm: @codemap::CodeMap,
52     next_id: node_id,
53     span_diagnostic: span_handler,
54     interner: @ident_interner,
55 }
56
57 pub fn new_parse_sess(demitter: Option<Emitter>) -> @mut ParseSess {
58     let cm = @CodeMap::new();
59     @mut ParseSess {
60         cm: cm,
61         next_id: 1,
62         span_diagnostic: mk_span_handler(mk_handler(demitter), cm),
63         interner: mk_ident_interner(),
64     }
65 }
66
67 pub fn new_parse_sess_special_handler(sh: span_handler, cm: @codemap::CodeMap)
68     -> @mut ParseSess {
69     @mut ParseSess {
70         cm: cm,
71         next_id: 1,
72         span_diagnostic: sh,
73         interner: mk_ident_interner(),
74     }
75 }
76
77 pub fn parse_crate_from_file(input: &Path, cfg: ast::crate_cfg,
78                          sess: @mut ParseSess) -> @ast::crate {
79     let p = new_crate_parser_from_file(sess, cfg, input);
80     let r = p.parse_crate_mod(cfg);
81     return r;
82 }
83
84 pub fn parse_crate_from_source_str(name: ~str,
85                                    source: @~str,
86                                    cfg: ast::crate_cfg,
87                                    sess: @mut ParseSess) -> @ast::crate {
88     let p = new_parser_from_source_str(sess, cfg, name,
89                                        codemap::FssNone, source);
90     let r = p.parse_crate_mod(cfg);
91     p.abort_if_errors();
92     return r;
93 }
94
95 pub fn parse_expr_from_source_str(name: ~str,
96                                   source: @~str,
97                                   cfg: ast::crate_cfg,
98                                   sess: @mut ParseSess) -> @ast::expr {
99     let p = new_parser_from_source_str(sess, cfg, name,
100                                        codemap::FssNone, source);
101     let r = p.parse_expr();
102     p.abort_if_errors();
103     return r;
104 }
105
106 pub fn parse_item_from_source_str(name: ~str,
107                                   source: @~str,
108                                   cfg: ast::crate_cfg,
109                                   +attrs: ~[ast::attribute],
110                                   sess: @mut ParseSess)
111                                -> Option<@ast::item> {
112     let p = new_parser_from_source_str(sess, cfg, name,
113                                        codemap::FssNone, source);
114     let r = p.parse_item(attrs);
115     p.abort_if_errors();
116     return r;
117 }
118
119 pub fn parse_stmt_from_source_str(name: ~str,
120                                   source: @~str,
121                                   cfg: ast::crate_cfg,
122                                   +attrs: ~[ast::attribute],
123                                   sess: @mut ParseSess) -> @ast::stmt {
124     let p = new_parser_from_source_str(sess, cfg, name,
125                                        codemap::FssNone, source);
126     let r = p.parse_stmt(attrs);
127     p.abort_if_errors();
128     return r;
129 }
130
131 pub fn parse_tts_from_source_str(name: ~str,
132                                  source: @~str,
133                                  cfg: ast::crate_cfg,
134                                  sess: @mut ParseSess) -> ~[ast::token_tree] {
135     let p = new_parser_from_source_str(sess, cfg, name,
136                                        codemap::FssNone, source);
137     p.quote_depth += 1u;
138     let r = p.parse_all_token_trees();
139     p.abort_if_errors();
140     return r;
141 }
142
143 pub fn parse_from_source_str<T>(f: fn (p: Parser) -> T,
144                             name: ~str, ss: codemap::FileSubstr,
145                             source: @~str, cfg: ast::crate_cfg,
146                             sess: @mut ParseSess)
147     -> T
148 {
149     let p = new_parser_from_source_str(sess, cfg, name, ss,
150                                        source);
151     let r = f(p);
152     if !p.reader.is_eof() {
153         p.reader.fatal(~"expected end-of-string");
154     }
155     p.abort_if_errors();
156     r
157 }
158
159 pub fn next_node_id(sess: @mut ParseSess) -> node_id {
160     let rv = sess.next_id;
161     sess.next_id += 1;
162     // ID 0 is reserved for the crate and doesn't actually exist in the AST
163     assert rv != 0;
164     return rv;
165 }
166
167 pub fn new_parser_from_source_str(sess: @mut ParseSess, cfg: ast::crate_cfg,
168                               +name: ~str, +ss: codemap::FileSubstr,
169                               source: @~str) -> Parser {
170     let filemap = sess.cm.new_filemap_w_substr(name, ss, source);
171     let srdr = lexer::new_string_reader(copy sess.span_diagnostic,
172                                         filemap,
173                                         sess.interner);
174     return Parser(sess, cfg, srdr as reader);
175 }
176
177 pub fn new_parser_from_file(sess: @mut ParseSess,
178                             cfg: ast::crate_cfg,
179                             path: &Path)
180                          -> Result<Parser, ~str> {
181     match io::read_whole_file_str(path) {
182       result::Ok(src) => {
183
184           let filemap = sess.cm.new_filemap(path.to_str(), @src);
185           let srdr = lexer::new_string_reader(copy sess.span_diagnostic,
186                                               filemap,
187                                               sess.interner);
188           Ok(Parser(sess, cfg, srdr as reader))
189
190       }
191       result::Err(e) => Err(e)
192     }
193 }
194
195 /// Create a new parser for an entire crate, handling errors as appropriate
196 /// if the file doesn't exist
197 pub fn new_crate_parser_from_file(sess: @mut ParseSess, cfg: ast::crate_cfg,
198                               path: &Path) -> Parser {
199     match new_parser_from_file(sess, cfg, path) {
200         Ok(parser) => parser,
201         Err(e) => {
202             sess.span_diagnostic.handler().fatal(e)
203         }
204     }
205 }
206
207 /// Create a new parser based on a span from an existing parser. Handles
208 /// error messages correctly when the file does not exist.
209 pub fn new_sub_parser_from_file(sess: @mut ParseSess, cfg: ast::crate_cfg,
210                             path: &Path, sp: span) -> Parser {
211     match new_parser_from_file(sess, cfg, path) {
212         Ok(parser) => parser,
213         Err(e) => {
214             sess.span_diagnostic.span_fatal(sp, e)
215         }
216     }
217 }
218
219 pub fn new_parser_from_tts(sess: @mut ParseSess, cfg: ast::crate_cfg,
220                        tts: ~[ast::token_tree]) -> Parser {
221     let trdr = lexer::new_tt_reader(copy sess.span_diagnostic, sess.interner,
222                                     None, tts);
223     return Parser(sess, cfg, trdr as reader)
224 }
225
226
227 #[cfg(test)]
228 mod test {
229     use super::*;
230     use std::serialize::Encodable;
231     use std;
232     use core::str;
233     use util::testing::*;
234
235     #[test] fn to_json_str (val: Encodable<std::json::Encoder>) -> ~str {
236         let bw = @io::BytesWriter();
237         val.encode(~std::json::Encoder(bw as io::Writer));
238         str::from_bytes(bw.bytes.data)
239     }
240
241     #[test] fn alltts () {
242         let tts = parse_tts_from_source_str(
243             ~"bogofile",
244             @~"fn foo (x : int) { x; }",
245             ~[],
246             new_parse_sess(None));
247         check_equal(to_json_str(tts as Encodable::<std::json::Encoder>),
248                     ~"[[\"tt_tok\",[,[\"IDENT\",[\"fn\",false]]]],\
249                       [\"tt_tok\",[,[\"IDENT\",[\"foo\",false]]]],\
250                       [\"tt_delim\",[[[\"tt_tok\",[,[\"LPAREN\",[]]]],\
251                       [\"tt_tok\",[,[\"IDENT\",[\"x\",false]]]],\
252                       [\"tt_tok\",[,[\"COLON\",[]]]],\
253                       [\"tt_tok\",[,[\"IDENT\",[\"int\",false]]]],\
254                       [\"tt_tok\",[,[\"RPAREN\",[]]]]]]],\
255                       [\"tt_delim\",[[[\"tt_tok\",[,[\"LBRACE\",[]]]],\
256                       [\"tt_tok\",[,[\"IDENT\",[\"x\",false]]]],\
257                       [\"tt_tok\",[,[\"SEMI\",[]]]],\
258                       [\"tt_tok\",[,[\"RBRACE\",[]]]]]]]]"
259                    );
260         let ast1 = new_parser_from_tts(new_parse_sess(None),~[],tts)
261             .parse_item(~[]);
262         let ast2 = parse_item_from_source_str(
263             ~"bogofile",
264             @~"fn foo (x : int) { x; }",
265             ~[],~[],
266             new_parse_sess(None));
267         check_equal(ast1,ast2);
268     }
269 }
270
271 //
272 // Local Variables:
273 // mode: rust
274 // fill-column: 78;
275 // indent-tabs-mode: nil
276 // c-basic-offset: 4
277 // buffer-file-coding-system: utf-8-unix
278 // End:
279 //