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