1 use super::norm_util::{self, AlternativeAction, Symbols};
2 use super::{NormError, NormResult};
3 
4 use grammar::consts::{ERROR, LOCATION};
5 use grammar::parse_tree::{
6     ActionKind, Alternative, Grammar, Lifetime, NonterminalData, NonterminalString, Path, Span,
7     SymbolKind, TypeParameter, TypeRef,
8 };
9 use grammar::repr::{NominalTypeRepr, TypeRepr, Types};
10 use std::collections::{HashMap, HashSet};
11 use string_cache::DefaultAtom as Atom;
12 
13 #[cfg(test)]
14 mod test;
15 
infer_types(grammar: &Grammar) -> NormResult<Types>16 pub fn infer_types(grammar: &Grammar) -> NormResult<Types> {
17     let inferencer = try!(TypeInferencer::new(&grammar));
18     inferencer.infer_types()
19 }
20 
21 struct TypeInferencer<'grammar> {
22     stack: Vec<NonterminalString>,
23     nonterminals: HashMap<NonterminalString, NT<'grammar>>,
24     types: Types,
25     type_parameters: HashSet<Atom>,
26 }
27 
28 #[derive(Copy, Clone)]
29 struct NT<'grammar> {
30     span: Span,
31     type_decl: &'grammar Option<TypeRef>,
32     alternatives: &'grammar Vec<Alternative>,
33 }
34 
35 impl<'grammar> TypeInferencer<'grammar> {
new(grammar: &'grammar Grammar) -> NormResult<TypeInferencer<'grammar>>36     fn new(grammar: &'grammar Grammar) -> NormResult<TypeInferencer<'grammar>> {
37         let types = TypeInferencer::make_types(grammar);
38 
39         let nonterminals = grammar
40             .items
41             .iter()
42             .filter_map(|item| item.as_nonterminal())
43             .map(|data| {
44                 assert!(!data.is_macro_def()); // normalized away by now
45                 (data.name.clone(), NT::new(data))
46             })
47             .collect();
48 
49         let type_parameters = grammar
50             .type_parameters
51             .iter()
52             .filter_map(|p| match *p {
53                 TypeParameter::Lifetime(_) => None,
54                 TypeParameter::Id(ref ty) => Some(ty.clone()),
55             })
56             .collect();
57 
58         Ok(TypeInferencer {
59             stack: vec![],
60             nonterminals: nonterminals,
61             types: types,
62             type_parameters: type_parameters,
63         })
64     }
65 
make_types(grammar: &Grammar) -> Types66     fn make_types(grammar: &Grammar) -> Types {
67         let opt_extern_token = grammar.extern_token();
68 
69         // Determine error type (if any).
70         let error_type = opt_extern_token.and_then(|extern_token| {
71             extern_token
72                 .associated_type(Atom::from(ERROR))
73                 .map(|tr| tr.type_ref.type_repr())
74         });
75 
76         // Determine location type and enum type. If using an internal
77         // token, that's specified by us, not user.
78         if let Some(intern_token) = grammar.intern_token() {
79             let loc_type = // usize
80                 TypeRepr::usize();
81             let input_str = // &'input str
82                 TypeRepr::Ref {
83                     lifetime: Some(Lifetime::input()),
84                     mutable: false,
85                     referent: Box::new(TypeRepr::str())
86                 };
87             let enum_type = // Token<'input>
88                 TypeRepr::Nominal(NominalTypeRepr {
89                     path: Path {
90                         absolute: false,
91                         ids: vec![Atom::from("Token")],
92                     },
93                     types: vec![TypeRepr::Lifetime(Lifetime::input())]
94                 });
95 
96             let mut types = Types::new(&grammar.prefix, Some(loc_type), error_type, enum_type);
97 
98             for match_entry in &intern_token.match_entries {
99                 types.add_term_type(match_entry.user_name.clone(), input_str.clone());
100             }
101 
102             types
103         } else {
104             let extern_token = opt_extern_token.unwrap();
105             let loc_type = extern_token
106                 .associated_type(Atom::from(LOCATION))
107                 .map(|tr| tr.type_ref.type_repr());
108             let enum_type = extern_token
109                 .enum_token
110                 .as_ref()
111                 .unwrap()
112                 .type_name
113                 .type_repr();
114             let mut types = Types::new(&grammar.prefix, loc_type, error_type, enum_type);
115 
116             // For each defined conversion, figure out the type of the
117             // terminal and enter it into `types` by hand if it is not the
118             // default. For terminals with custom types, the user should
119             // have one or more bindings in the pattern -- if more than
120             // one, make a tuple.
121             //
122             // e.g. "(" => Lparen(..) ==> no custom type
123             //      "Num" => Num(<u32>) ==> custom type is u32
124             //      "Fraction" => Real(<u32>,<u32>) ==> custom type is (u32, u32)
125             for conversion in grammar
126                 .enum_token()
127                 .into_iter()
128                 .flat_map(|et| &et.conversions)
129             {
130                 let mut tys = Vec::new();
131                 conversion
132                     .to
133                     .for_each_binding(&mut |ty| tys.push(ty.type_repr()));
134                 if tys.is_empty() {
135                     continue;
136                 }
137                 let ty = maybe_tuple(tys);
138                 types.add_term_type(conversion.from.clone(), ty);
139             }
140 
141             types
142         }
143     }
144 
infer_types(mut self) -> NormResult<Types>145     fn infer_types(mut self) -> NormResult<Types> {
146         let ids: Vec<NonterminalString> =
147             self.nonterminals.iter().map(|(id, _)| id.clone()).collect();
148 
149         for id in ids {
150             try!(self.nonterminal_type(&id));
151             debug_assert!(self.types.lookup_nonterminal_type(&id).is_some());
152         }
153 
154         Ok(self.types)
155     }
156 
nonterminal_type(&mut self, id: &NonterminalString) -> NormResult<TypeRepr>157     fn nonterminal_type(&mut self, id: &NonterminalString) -> NormResult<TypeRepr> {
158         if let Some(repr) = self.types.lookup_nonterminal_type(id) {
159             return Ok(repr.clone());
160         }
161 
162         let nt = self.nonterminals[&id];
163         if self.stack.contains(&id) {
164             return_err!(
165                 nt.span,
166                 "cannot infer type of `{}` because it references itself",
167                 id
168             );
169         }
170 
171         let ty = try!(self.push(id, |this| {
172             if let &Some(ref type_decl) = nt.type_decl {
173                 return this.type_ref(type_decl);
174             }
175 
176             // Try to compute the types of all alternatives; note that
177             // some may result in an error. Don't report these errors
178             // (yet).
179             let mut alternative_types = vec![];
180             let mut alternative_errors = vec![];
181             for alt in nt.alternatives.iter() {
182                 match this.alternative_type(alt) {
183                     Ok(t) => alternative_types.push(t),
184                     Err(e) => alternative_errors.push(e),
185                 }
186             }
187 
188             // if it never succeeded, report first error
189             if alternative_types.is_empty() {
190                 match alternative_errors.into_iter().next() {
191                     Some(err) => {
192                         return Err(err);
193                     }
194                     None => {
195                         // if nothing succeeded, and nothing errored,
196                         // must have been nothing to start with
197                         return_err!(
198                             nt.span,
199                             "nonterminal `{}` has no alternatives and hence parse cannot succeed",
200                             id
201                         );
202                     }
203                 }
204             }
205 
206             // otherwise, check that all the cases where we had success agree
207             for ((ty, alt), i) in alternative_types[1..]
208                 .iter()
209                 .zip(&nt.alternatives[1..])
210                 .zip(1..)
211             {
212                 if &alternative_types[0] != ty {
213                     return_err!(
214                         alt.span,
215                         "type of alternative #{} is `{}`, \
216                          but type of first alternative is `{}`",
217                         i + 1,
218                         ty,
219                         alternative_types[0]
220                     );
221                 }
222             }
223 
224             // and use that type
225             Ok(alternative_types.pop().unwrap())
226         }));
227 
228         self.types.add_type(id.clone(), ty.clone());
229         Ok(ty)
230     }
231 
push<F, R>(&mut self, id: &NonterminalString, f: F) -> NormResult<R> where F: FnOnce(&mut TypeInferencer) -> NormResult<R>,232     fn push<F, R>(&mut self, id: &NonterminalString, f: F) -> NormResult<R>
233     where
234         F: FnOnce(&mut TypeInferencer) -> NormResult<R>,
235     {
236         self.stack.push(id.clone());
237         let r = f(self);
238         assert_eq!(self.stack.pop().unwrap(), *id);
239         r
240     }
241 
type_ref(&mut self, type_ref: &TypeRef) -> NormResult<TypeRepr>242     fn type_ref(&mut self, type_ref: &TypeRef) -> NormResult<TypeRepr> {
243         match *type_ref {
244             TypeRef::Tuple(ref types) => {
245                 let types = try! {
246                     types.iter().map(|t| self.type_ref(t)).collect()
247                 };
248                 Ok(TypeRepr::Tuple(types))
249             }
250             TypeRef::Nominal {
251                 ref path,
252                 ref types,
253             } => {
254                 if path.ids.len() == 2 && self.type_parameters.contains(&path.ids[0]) {
255                     return Ok(TypeRepr::Associated {
256                         type_parameter: path.ids[0].clone(),
257                         id: path.ids[1].clone(),
258                     });
259                 }
260 
261                 let types = try! {
262                     types.iter().map(|t| self.type_ref(t)).collect()
263                 };
264                 Ok(TypeRepr::Nominal(NominalTypeRepr {
265                     path: path.clone(),
266                     types: types,
267                 }))
268             }
269             TypeRef::Lifetime(ref id) => Ok(TypeRepr::Lifetime(id.clone())),
270             TypeRef::Id(ref id) => Ok(TypeRepr::Nominal(NominalTypeRepr {
271                 path: Path::from_id(id.clone()),
272                 types: vec![],
273             })),
274             TypeRef::Ref {
275                 ref lifetime,
276                 mutable,
277                 ref referent,
278             } => Ok(TypeRepr::Ref {
279                 lifetime: lifetime.clone(),
280                 mutable: mutable,
281                 referent: Box::new(try!(self.type_ref(referent))),
282             }),
283             TypeRef::OfSymbol(ref symbol) => self.symbol_type(symbol),
284         }
285     }
286 
alternative_type(&mut self, alt: &Alternative) -> NormResult<TypeRepr>287     fn alternative_type(&mut self, alt: &Alternative) -> NormResult<TypeRepr> {
288         match norm_util::analyze_action(alt) {
289             AlternativeAction::User(&ActionKind::User(_))
290             | AlternativeAction::User(&ActionKind::Fallible(_)) => {
291                 return_err!(
292                     alt.span,
293                     "cannot infer types if there is custom action code"
294                 );
295             }
296 
297             AlternativeAction::User(&ActionKind::Lookahead)
298             | AlternativeAction::User(&ActionKind::Lookbehind) => {
299                 Ok(self.types.opt_terminal_loc_type().unwrap().clone())
300             }
301 
302             AlternativeAction::Default(Symbols::Named(ref syms)) => {
303                 return_err!(
304                     alt.span,
305                     "cannot infer types in the presence of named symbols like `{}:{}`",
306                     syms[0].1,
307                     syms[0].2
308                 );
309             }
310 
311             AlternativeAction::Default(Symbols::Anon(syms)) => {
312                 let symbol_types: Vec<TypeRepr> = try! {
313                     syms.iter()
314                         .map(|&(_, sym)| self.symbol_type(&sym.kind))
315                         .collect()
316                 };
317                 Ok(maybe_tuple(symbol_types))
318             }
319         }
320     }
321 
symbol_type(&mut self, symbol: &SymbolKind) -> NormResult<TypeRepr>322     fn symbol_type(&mut self, symbol: &SymbolKind) -> NormResult<TypeRepr> {
323         match *symbol {
324             SymbolKind::Terminal(ref id) => Ok(self.types.terminal_type(id).clone()),
325             SymbolKind::Nonterminal(ref id) => self.nonterminal_type(id),
326             SymbolKind::Choose(ref s) => self.symbol_type(&s.kind),
327             SymbolKind::Name(_, ref s) => self.symbol_type(&s.kind),
328             SymbolKind::Error => Ok(self.types.error_recovery_type().clone()),
329 
330             SymbolKind::Repeat(..)
331             | SymbolKind::Expr(..)
332             | SymbolKind::Macro(..)
333             | SymbolKind::AmbiguousId(..)
334             | SymbolKind::Lookahead
335             | SymbolKind::Lookbehind => {
336                 unreachable!("symbol `{:?}` should have been expanded away", symbol)
337             }
338         }
339     }
340 }
341 
342 impl<'grammar> NT<'grammar> {
new(data: &'grammar NonterminalData) -> NT<'grammar>343     fn new(data: &'grammar NonterminalData) -> NT<'grammar> {
344         NT {
345             span: data.span,
346             type_decl: &data.type_decl,
347             alternatives: &data.alternatives,
348         }
349     }
350 }
351 
maybe_tuple(v: Vec<TypeRepr>) -> TypeRepr352 fn maybe_tuple(v: Vec<TypeRepr>) -> TypeRepr {
353     if v.len() == 1 {
354         v.into_iter().next().unwrap()
355     } else {
356         TypeRepr::Tuple(v)
357     }
358 }
359