1 use grammar::parse_tree::NonterminalString;
2 use grammar::repr::TypeRepr;
3 use normalize::macro_expand::expand_macros;
4 use normalize::token_check;
5 use normalize::tyinfer::infer_types;
6 use parser;
7 use string_cache::DefaultAtom as Atom;
8 
type_repr(s: &str) -> TypeRepr9 fn type_repr(s: &str) -> TypeRepr {
10     let type_ref = parser::parse_type_ref(s).unwrap();
11     return type_ref.type_repr();
12 }
13 
compare(g1: &str, expected: Vec<(&'static str, &'static str)>)14 fn compare(g1: &str, expected: Vec<(&'static str, &'static str)>) {
15     let grammar = parser::parse_grammar(g1).unwrap();
16     let grammar = expand_macros(grammar).unwrap();
17     let grammar = token_check::validate(grammar).unwrap();
18     let types = infer_types(&grammar).unwrap();
19 
20     println!("types table: {:?}", types);
21 
22     for (nt_id, nt_type) in expected {
23         let id = NonterminalString(Atom::from(nt_id));
24         let ty = type_repr(nt_type);
25         println!("expected type of {:?} is {:?}", id, ty);
26         assert_eq!(types.nonterminal_type(&id), &ty);
27     }
28 }
29 
30 #[test]
test_pairs_and_tokens()31 fn test_pairs_and_tokens() {
32     compare(
33         r#"
34 grammar;
35     extern { enum Tok { "Hi" => Hi(..), "Ho" => Ho(..) } }
36     X = Y Z;
37     Y: Foo = "Hi";
38     Z = "Ho";
39 "#,
40         vec![("X", "(Foo, Tok)"), ("Y", "Foo"), ("Z", "Tok")],
41     )
42 }
43 
44 #[test]
test_cycle_direct()45 fn test_cycle_direct() {
46     let grammar = parser::parse_grammar(
47         r#"
48 grammar;
49     extern { enum Tok { "Hi" => Hi(..), "Ho" => Ho(..) } }
50     X = {
51         X Y,
52         <Y> => vec![<>]
53     };
54     Y = "Hi";
55 "#,
56     )
57     .unwrap();
58 
59     let actual = expand_macros(grammar).unwrap();
60     assert!(infer_types(&actual).is_err());
61 }
62 
63 #[test]
test_cycle_indirect()64 fn test_cycle_indirect() {
65     let grammar = parser::parse_grammar(
66         r#"
67 grammar;
68     extern { enum Tok { } }
69     A = B;
70     B = C;
71     C = D;
72     D = A;
73 "#,
74     )
75     .unwrap();
76 
77     let actual = expand_macros(grammar).unwrap();
78     assert!(infer_types(&actual).is_err());
79 }
80 
81 #[test]
test_macro_expansion()82 fn test_macro_expansion() {
83     compare(
84         r#"
85 grammar;
86     extern { enum Tok { "Id" => Id(..) } }
87     Two<X>: (X, X) = X X;
88     Ids = Two<"Id">;
89 "#,
90         vec![("Ids", "(Tok, Tok)"), (r#"Two<"Id">"#, "(Tok, Tok)")],
91     )
92 }
93 
94 #[test]
test_macro_expansion_infer()95 fn test_macro_expansion_infer() {
96     compare(
97         r#"
98 grammar;
99     extern { enum Tok { "Id" => Id(..) } }
100     Two<X> = X X;
101     Ids = Two<"Id">;
102 "#,
103         vec![("Ids", "(Tok, Tok)"), (r#"Two<"Id">"#, "(Tok, Tok)")],
104     )
105 }
106 
107 #[test]
test_type_question()108 fn test_type_question() {
109     compare(
110         r#"
111 grammar;
112     extern { enum Tok { "Hi" => Hi(..) } }
113     X = Y?;
114     Y = "Hi";
115 "#,
116         vec![("X", "::std::option::Option<Tok>"), ("Y", "Tok")],
117     )
118 }
119 
120 #[test]
test_star_plus_question()121 fn test_star_plus_question() {
122     compare(
123         r#"
124 grammar;
125     extern { enum Tok { "Hi" => Hi(..) } }
126     A = Z*;
127     X = "Hi"*;
128     Y = "Hi"+;
129     Z = "Hi"?;
130 "#,
131         vec![
132             ("A", "::std::vec::Vec<::std::option::Option<Tok>>"),
133             ("X", "::std::vec::Vec<Tok>"),
134             ("Y", "::std::vec::Vec<Tok>"),
135             ("Z", "::std::option::Option<Tok>"),
136         ],
137     )
138 }
139 
140 #[test]
test_lookahead()141 fn test_lookahead() {
142     compare(
143         r#"
144 grammar;
145     extern { type Location = usize; enum Tok { } }
146     A = @L;
147 "#,
148         vec![("A", "usize")],
149     )
150 }
151 
152 #[test]
test_spanned_macro()153 fn test_spanned_macro() {
154     compare(
155         r#"
156         grammar;
157         extern { type Location = usize; enum Tok { "Foo" => Foo(..) } }
158         A = Spanned<"Foo">;
159         Spanned<T> = {
160             @L T @R
161         };
162 "#,
163         vec![("A", "(usize, Tok, usize)")],
164     )
165 }
166 
167 #[test]
test_action()168 fn test_action() {
169     compare(
170         r#"
171 grammar;
172     extern { enum Tok { "+" => .., "foo" => .. } }
173 
174     X = {
175         Y,
176         <l:X> "+" <r:Y> => l + r
177     };
178 
179     Y: i32 = "foo" => 22;
180 "#,
181         vec![("X", "i32"), ("Y", "i32")],
182     )
183 }
184 
185 #[test]
test_inconsistent_action()186 fn test_inconsistent_action() {
187     let grammar = parser::parse_grammar(
188         r#"
189 grammar;
190     extern { enum Tok { "+" => .., "foo" => .., "bar" => .. } }
191 
192     X = {
193         Y,
194         Z,
195         <l:X> "+" <r:Y> => l + r
196     };
197 
198     Y: i32 = "foo" => 22;
199 
200     Z: u32 = "bar" => 22;
201 "#,
202     )
203     .unwrap();
204 
205     let actual = expand_macros(grammar).unwrap();
206     assert!(infer_types(&actual).is_err());
207 }
208 
209 #[test]
custom_token()210 fn custom_token() {
211     compare(
212         r#"
213 grammar;
214 extern { enum Tok { N => N(<u32>) } }
215 A = N;
216 "#,
217         vec![("A", "u32")],
218     )
219 }
220 
221 #[test]
intern_token()222 fn intern_token() {
223     compare(
224         r#"
225 grammar;
226     Z = @L "Ho" @R;
227 "#,
228         vec![("Z", "(usize, &'input str, usize)")],
229     )
230 }
231 
232 #[test]
error()233 fn error() {
234     compare(
235         r#"
236 grammar;
237     Z = !;
238 "#,
239         vec![(
240             "Z",
241             "__lalrpop_util::ErrorRecovery<usize, Token<'input>, &'static str>",
242         )],
243     )
244 }
245