1 /*!
2  * Normalization processes a parse tree until it is in suitable form to
3  * be converted to the more canonical form. This is done as a series of
4  * passes, each contained in their own module below.
5  */
6 
7 use grammar::parse_tree as pt;
8 use grammar::repr as r;
9 use session::Session;
10 
11 pub type NormResult<T> = Result<T, NormError>;
12 
13 #[derive(Clone, Debug)]
14 pub struct NormError {
15     pub message: String,
16     pub span: pt::Span,
17 }
18 
19 macro_rules! return_err {
20     ($span: expr, $($args:expr),+) => {
21         return Err(NormError {
22             message: format!($($args),+),
23             span: $span
24         });
25     }
26 }
27 
normalize(session: &Session, grammar: pt::Grammar) -> NormResult<r::Grammar>28 pub fn normalize(session: &Session, grammar: pt::Grammar) -> NormResult<r::Grammar> {
29     normalize_helper(session, grammar, true)
30 }
31 
32 /// for unit tests, it is convenient to skip the validation step, and supply a dummy session
33 #[cfg(test)]
normalize_without_validating(grammar: pt::Grammar) -> NormResult<r::Grammar>34 pub fn normalize_without_validating(grammar: pt::Grammar) -> NormResult<r::Grammar> {
35     normalize_helper(&Session::new(), grammar, false)
36 }
37 
normalize_helper( session: &Session, grammar: pt::Grammar, validate: bool, ) -> NormResult<r::Grammar>38 fn normalize_helper(
39     session: &Session,
40     grammar: pt::Grammar,
41     validate: bool,
42 ) -> NormResult<r::Grammar> {
43     let grammar = try!(lower_helper(session, grammar, validate));
44     let grammar = profile!(session, "Inlining", try!(inline::inline(grammar)));
45     Ok(grammar)
46 }
47 
lower_helper(session: &Session, grammar: pt::Grammar, validate: bool) -> NormResult<r::Grammar>48 fn lower_helper(session: &Session, grammar: pt::Grammar, validate: bool) -> NormResult<r::Grammar> {
49     profile!(
50         session,
51         "Grammar validation",
52         if validate {
53             try!(prevalidate::validate(&grammar));
54         }
55     );
56     let grammar = profile!(
57         session,
58         "Grammar resolution",
59         try!(resolve::resolve(grammar))
60     );
61     let grammar = profile!(
62         session,
63         "Macro expansion",
64         try!(macro_expand::expand_macros(grammar))
65     );
66     let grammar = profile!(session, "Token check", try!(token_check::validate(grammar)));
67     let types = profile!(session, "Infer types", try!(tyinfer::infer_types(&grammar)));
68     let grammar = profile!(
69         session,
70         "Lowering",
71         try!(lower::lower(session, grammar, types))
72     );
73     Ok(grammar)
74 }
75 
76 // These are executed *IN ORDER*:
77 
78 // Check most safety conditions.
79 mod prevalidate;
80 
81 // Resolve identifiers into terminals/nonterminals etc.
82 mod resolve;
83 
84 // Expands macros and expressions
85 //
86 //     X = ...1 Comma<X> (X Y Z) ...2
87 //
88 // to
89 //
90 //     X = ...1 `Comma<X>` `(X Y Z)` ...2
91 //     `Comma_X`: Vec<<X>> = ...;
92 //     `(X Y Z)` = X Y Z;
93 //
94 // AFTER THIS POINT: No more macros, macro references, guarded
95 // alternatives, repeats, or expr symbols, though type indirections
96 // may occur.
97 mod macro_expand;
98 
99 // Check if there is an extern token and all terminals have have a
100 // conversion; if no extern token, synthesize an intern token.
101 mod token_check;
102 
103 // Computes types where the user omitted them (or from macro
104 // byproducts).
105 //
106 // AFTER THIS POINT: there is a separate `repr::Types` table
107 // providing all nonterminals with an explicit type.
108 mod tyinfer;
109 
110 // Lowers the parse tree to the repr notation.
111 mod lower;
112 
113 // Inline nonterminals that have requested it.
114 mod inline;
115 
116 ///////////////////////////////////////////////////////////////////////////
117 // Shared routines
118 
119 mod norm_util;
120