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