]> git.lizzy.rs Git - rust.git/blob - src/grammar/verify.rs
Shuffle around check-lexer conditions
[rust.git] / src / grammar / verify.rs
1 // Copyright 2014 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 #![feature(globs, phase, macro_rules)]
12
13 extern crate syntax;
14 extern crate rustc;
15
16 #[phase(link)]
17 extern crate regex;
18
19 #[phase(link, plugin)]
20 extern crate log;
21
22 #[phase(plugin)] extern crate regex_macros;
23
24 use std::collections::HashMap;
25 use std::io::File;
26
27 use syntax::parse;
28 use syntax::parse::lexer;
29 use rustc::driver::{session, config};
30
31 use syntax::ast;
32 use syntax::ast::Name;
33 use syntax::parse::token::*;
34 use syntax::parse::lexer::TokenAndSpan;
35
36 fn parse_token_list(file: &str) -> HashMap<String, Token> {
37     fn id() -> Token {
38         IDENT(ast::Ident { name: Name(0), ctxt: 0, }, false)
39     }
40
41     let mut res = HashMap::new();
42
43     res.insert("-1".to_string(), EOF);
44
45     for line in file.split('\n') {
46         let eq = match line.trim().rfind('=') {
47             Some(val) => val,
48             None => continue
49         };
50
51         let val = line.slice_to(eq);
52         let num = line.slice_from(eq + 1);
53
54         let tok = match val {
55             "SHR" => BINOP(SHR),
56             "DOLLAR" => DOLLAR,
57             "LT" => LT,
58             "STAR" => BINOP(STAR),
59             "FLOAT_SUFFIX" => id(),
60             "INT_SUFFIX" => id(),
61             "SHL" => BINOP(SHL),
62             "LBRACE" => LBRACE,
63             "RARROW" => RARROW,
64             "LIT_STR" => LIT_STR(Name(0)),
65             "DOTDOT" => DOTDOT,
66             "MOD_SEP" => MOD_SEP,
67             "DOTDOTDOT" => DOTDOTDOT,
68             "NOT" => NOT,
69             "AND" => BINOP(AND),
70             "LPAREN" => LPAREN,
71             "ANDAND" => ANDAND,
72             "AT" => AT,
73             "LBRACKET" => LBRACKET,
74             "LIT_STR_RAW" => LIT_STR_RAW(Name(0), 0),
75             "RPAREN" => RPAREN,
76             "SLASH" => BINOP(SLASH),
77             "COMMA" => COMMA,
78             "LIFETIME" => LIFETIME(ast::Ident { name: Name(0), ctxt: 0 }),
79             "CARET" => BINOP(CARET),
80             "TILDE" => TILDE,
81             "IDENT" => id(),
82             "PLUS" => BINOP(PLUS),
83             "LIT_CHAR" => LIT_CHAR(Name(0)),
84             "LIT_BYTE" => LIT_BYTE(Name(0)),
85             "EQ" => EQ,
86             "RBRACKET" => RBRACKET,
87             "COMMENT" => COMMENT,
88             "DOC_COMMENT" => DOC_COMMENT(Name(0)),
89             "DOT" => DOT,
90             "EQEQ" => EQEQ,
91             "NE" => NE,
92             "GE" => GE,
93             "PERCENT" => BINOP(PERCENT),
94             "RBRACE" => RBRACE,
95             "BINOP" => BINOP(PLUS),
96             "POUND" => POUND,
97             "OROR" => OROR,
98             "LIT_INTEGER" => LIT_INTEGER(Name(0)),
99             "BINOPEQ" => BINOPEQ(PLUS),
100             "LIT_FLOAT" => LIT_FLOAT(Name(0)),
101             "WHITESPACE" => WS,
102             "UNDERSCORE" => UNDERSCORE,
103             "MINUS" => BINOP(MINUS),
104             "SEMI" => SEMI,
105             "COLON" => COLON,
106             "FAT_ARROW" => FAT_ARROW,
107             "OR" => BINOP(OR),
108             "GT" => GT,
109             "LE" => LE,
110             "LIT_BINARY" => LIT_BINARY(Name(0)),
111             "LIT_BINARY_RAW" => LIT_BINARY_RAW(Name(0), 0),
112             _ => continue
113         };
114
115         res.insert(num.to_string(), tok);
116     }
117
118     debug!("Token map: {}", res);
119     res
120 }
121
122 fn str_to_binop(s: &str) -> BinOp {
123     match s {
124         "+" => PLUS,
125         "/" => SLASH,
126         "-" => MINUS,
127         "*" => STAR,
128         "%" => PERCENT,
129         "^" => CARET,
130         "&" => AND,
131         "|" => OR,
132         "<<" => SHL,
133         ">>" => SHR,
134         _ => fail!("Bad binop str `{}`", s)
135     }
136 }
137
138 /// Assuming a string/binary literal, strip out the leading/trailing
139 /// hashes and surrounding quotes/raw/binary prefix.
140 fn fix(mut lit: &str) -> ast::Name {
141     if lit.char_at(0) == 'r' {
142         if lit.char_at(1) == 'b' {
143             lit = lit.slice_from(2)
144         } else {
145             lit = lit.slice_from(1);
146         }
147     } else if lit.char_at(0) == 'b' {
148         lit = lit.slice_from(1);
149     }
150
151     let leading_hashes = count(lit);
152
153     // +1/-1 to adjust for single quotes
154     parse::token::intern(lit.slice(leading_hashes + 1, lit.len() - leading_hashes - 1))
155 }
156
157 /// Assuming a char/byte literal, strip the 'b' prefix and the single quotes.
158 fn fixchar(mut lit: &str) -> ast::Name {
159     if lit.char_at(0) == 'b' {
160         lit = lit.slice_from(1);
161     }
162
163     parse::token::intern(lit.slice(1, lit.len() - 1))
164 }
165
166 fn count(lit: &str) -> uint {
167     lit.chars().take_while(|c| *c == '#').count()
168 }
169
170 fn parse_antlr_token(s: &str, tokens: &HashMap<String, Token>) -> TokenAndSpan {
171     let re = regex!(
172       r"\[@(?P<seq>\d+),(?P<start>\d+):(?P<end>\d+)='(?P<content>.+?)',<(?P<toknum>-?\d+)>,\d+:\d+]"
173     );
174
175     let m = re.captures(s).expect(format!("The regex didn't match {}", s).as_slice());
176     let start = m.name("start");
177     let end = m.name("end");
178     let toknum = m.name("toknum");
179     let content = m.name("content");
180
181     let proto_tok = tokens.find_equiv(&toknum).expect(format!("didn't find token {} in the map",
182                                                               toknum).as_slice());
183
184     let nm = parse::token::intern(content);
185
186     debug!("What we got: content (`{}`), proto: {}", content, proto_tok);
187
188     let real_tok = match *proto_tok {
189         BINOP(..) => BINOP(str_to_binop(content)),
190         BINOPEQ(..) => BINOPEQ(str_to_binop(content.slice_to(content.len() - 1))),
191         LIT_STR(..) => LIT_STR(fix(content)),
192         LIT_STR_RAW(..) => LIT_STR_RAW(fix(content), count(content)),
193         LIT_CHAR(..) => LIT_CHAR(fixchar(content)),
194         LIT_BYTE(..) => LIT_BYTE(fixchar(content)),
195         DOC_COMMENT(..) => DOC_COMMENT(nm),
196         LIT_INTEGER(..) => LIT_INTEGER(nm),
197         LIT_FLOAT(..) => LIT_FLOAT(nm),
198         LIT_BINARY(..) => LIT_BINARY(nm),
199         LIT_BINARY_RAW(..) => LIT_BINARY_RAW(fix(content), count(content)),
200         IDENT(..) => IDENT(ast::Ident { name: nm, ctxt: 0 }, true),
201         LIFETIME(..) => LIFETIME(ast::Ident { name: nm, ctxt: 0 }),
202         ref t => t.clone()
203     };
204
205     let offset = if real_tok == EOF {
206         1
207     } else {
208         0
209     };
210
211     let sp = syntax::codemap::Span {
212         lo: syntax::codemap::BytePos(from_str::<u32>(start).unwrap() - offset),
213         hi: syntax::codemap::BytePos(from_str::<u32>(end).unwrap() + 1),
214         expn_info: None
215     };
216
217     TokenAndSpan {
218         tok: real_tok,
219         sp: sp
220     }
221 }
222
223 fn tok_cmp(a: &Token, b: &Token) -> bool {
224     match a {
225         &IDENT(id, _) => match b {
226                 &IDENT(id2, _) => id == id2,
227                 _ => false
228         },
229         _ => a == b
230     }
231 }
232
233 fn main() {
234     fn next(r: &mut lexer::StringReader) -> TokenAndSpan {
235         use syntax::parse::lexer::Reader;
236         r.next_token()
237     }
238
239     let args = std::os::args();
240
241     let mut token_file = File::open(&Path::new(args.get(2).as_slice()));
242     let token_map = parse_token_list(token_file.read_to_string().unwrap().as_slice());
243
244     let mut stdin = std::io::stdin();
245     let mut antlr_tokens = stdin.lines().map(|l| parse_antlr_token(l.unwrap().as_slice().trim(),
246                                                                    &token_map));
247
248     let code = File::open(&Path::new(args.get(1).as_slice())).unwrap().read_to_string().unwrap();
249     let options = config::basic_options();
250     let session = session::build_session(options, None,
251                                          syntax::diagnostics::registry::Registry::new([]));
252     let filemap = parse::string_to_filemap(&session.parse_sess,
253                                            code,
254                                            String::from_str("<n/a>"));
255     let mut lexer = lexer::StringReader::new(session.diagnostic(), filemap);
256
257     for antlr_tok in antlr_tokens {
258         let rustc_tok = next(&mut lexer);
259         if rustc_tok.tok == EOF && antlr_tok.tok == EOF {
260             continue
261         }
262
263         assert!(rustc_tok.sp == antlr_tok.sp, "{} and {} have different spans", rustc_tok,
264                 antlr_tok);
265
266         macro_rules! matches (
267             ( $($x:pat),+ ) => (
268                 match rustc_tok.tok {
269                     $($x => match antlr_tok.tok {
270                         $x => {
271                             if !tok_cmp(&rustc_tok.tok, &antlr_tok.tok) {
272                                 // FIXME #15677: needs more robust escaping in
273                                 // antlr
274                                 warn!("Different names for {} and {}", rustc_tok, antlr_tok);
275                             }
276                         }
277                         _ => fail!("{} is not {}", antlr_tok, rustc_tok)
278                     },)*
279                     ref c => assert!(c == &antlr_tok.tok, "{} is not {}", rustc_tok, antlr_tok)
280                 }
281             )
282         )
283
284         matches!(LIT_BYTE(..),
285             LIT_CHAR(..),
286             LIT_INTEGER(..),
287             LIT_FLOAT(..),
288             LIT_STR(..),
289             LIT_STR_RAW(..),
290             LIT_BINARY(..),
291             LIT_BINARY_RAW(..),
292             IDENT(..),
293             LIFETIME(..),
294             INTERPOLATED(..),
295             DOC_COMMENT(..),
296             SHEBANG(..)
297         );
298     }
299 }