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