lrpar_tests/
lib.rs

1#[cfg(test)]
2use cfgrammar::Span;
3
4mod cgen_helper;
5#[allow(unused)]
6use cgen_helper::run_test_path;
7
8mod calc_wasm;
9
10#[cfg(test)]
11use cttests_macro::generate_codegen_fail_tests;
12use lrlex::lrlex_mod;
13use lrpar::lrpar_mod;
14#[cfg(test)]
15use lrpar::{Lexeme, Lexer, NonStreamingLexer};
16
17lrlex_mod!("calc_multitypes.l");
18lrpar_mod!("calc_multitypes.y");
19
20lrlex_mod!("calc_actiontype.l");
21lrpar_mod!("calc_actiontype.y");
22
23lrlex_mod!("calc_noactions.l");
24lrpar_mod!("calc_noactions.y");
25
26lrlex_mod!("calc_nodefault_yacckind.l");
27lrpar_mod!("calc_nodefault_yacckind.y");
28
29lrlex_mod!("calc_unsafeaction.l");
30lrpar_mod!("calc_unsafeaction.y");
31
32lrlex_mod!("calc_input.l");
33lrpar_mod!("calc_input.y");
34
35lrlex_mod!("expect.l");
36lrpar_mod!("expect.y");
37
38lrlex_mod!("lexer_lifetime.l");
39lrpar_mod!("lexer_lifetime.y");
40
41lrlex_mod!("lex_flags.l");
42lrpar_mod!("lex_flags.y");
43
44lrlex_mod!("multitypes.l");
45lrpar_mod!("multitypes.y");
46
47lrlex_mod!("parseparam.l");
48lrpar_mod!("parseparam.y");
49
50lrlex_mod!("parseparam_copy.l");
51lrpar_mod!("parseparam_copy.y");
52
53lrlex_mod!("typeparams.l");
54lrpar_mod!("typeparams.y");
55
56lrlex_mod!("passthrough.l");
57lrpar_mod!("passthrough.y");
58
59lrlex_mod!("regex_opt.l");
60lrlex_mod!("regex_opt.y");
61
62lrlex_mod!("span.l");
63lrpar_mod!("span.y");
64
65lrlex_mod!("storaget.l");
66lrpar_mod!("storaget.y");
67
68lrlex_mod!("grmtools_section.l");
69lrpar_mod!("grmtools_section.y");
70
71lrlex_mod!("ast_unmodified.l");
72lrpar_mod!("ast_unmodified.y");
73
74lrlex_mod!("ast_modified.l");
75lrpar_mod!("ast_modified.y");
76
77#[test]
78fn multitypes() {
79    let lexerdef = multitypes_l::lexerdef();
80    let lexer = lexerdef.lexer("aa");
81    let (r, errs) = multitypes_y::parse(&lexer);
82    assert_eq!(r.unwrap().len(), 2);
83    assert_eq!(errs.len(), 0);
84}
85
86#[test]
87fn test_no_actions() {
88    let lexerdef = calc_noactions_l::lexerdef();
89    let lexer = lexerdef.lexer("2+3");
90    if !calc_noactions_y::parse(&lexer).is_empty() {
91        panic!();
92    }
93    let lexer = lexerdef.lexer("2++3");
94    if calc_noactions_y::parse(&lexer).len() != 1 {
95        panic!();
96    }
97}
98
99#[test]
100fn test_basic_actions() {
101    let lexerdef = calc_actiontype_l::lexerdef();
102    let lexer = lexerdef.lexer("2+3");
103    match calc_actiontype_y::parse(&lexer) {
104        (Some(Ok(5)), ref errs) if errs.is_empty() => (),
105        _ => unreachable!(),
106    }
107}
108
109#[test]
110fn test_calc_input() {
111    let lexerdef = calc_input_l::lexerdef();
112    let lexer = lexerdef.lexer("2+3");
113    match calc_input_y::parse(&lexer) {
114        (Some(Ok(5)), ref errs) if errs.is_empty() => (),
115        _ => unreachable!(),
116    }
117}
118
119#[test]
120fn test_nodefault_yacckind() {
121    let lexerdef = calc_nodefault_yacckind_l::lexerdef();
122    let lexer = lexerdef.lexer("2+3");
123    match calc_nodefault_yacckind_y::parse(&lexer) {
124        (Some(Ok(5)), ref errs) if errs.is_empty() => (),
125        _ => unreachable!(),
126    }
127}
128#[test]
129fn test_unsafe_actions() {
130    let lexerdef = calc_unsafeaction_l::lexerdef();
131    let lexer = lexerdef.lexer("2+3");
132    match calc_unsafeaction_y::parse(&lexer) {
133        (Some(Ok(5)), ref errs) if errs.is_empty() => (),
134        _ => unreachable!(),
135    }
136}
137
138#[test]
139fn test_error_recovery_and_actions() {
140    use lrpar::LexParseError;
141
142    let lexerdef = calc_actiontype_l::lexerdef();
143
144    let lexer = lexerdef.lexer("2++3");
145    let (r, errs) = calc_actiontype_y::parse(&lexer);
146    match r {
147        Some(Ok(5)) => (),
148        _ => unreachable!(),
149    }
150    match errs[0] {
151        LexParseError::ParseError(..) => (),
152        _ => unreachable!(),
153    }
154
155    let lexer = lexerdef.lexer("2+3)");
156    let (r, errs) = calc_actiontype_y::parse(&lexer);
157    assert_eq!(r, Some(Ok(5)));
158    assert_eq!(errs.len(), 1);
159    match errs[0] {
160        LexParseError::ParseError(..) => (),
161        _ => unreachable!(),
162    }
163
164    let lexer = lexerdef.lexer("2+3+18446744073709551616");
165    let (r, errs) = calc_actiontype_y::parse(&lexer);
166    assert_eq!(r, Some(Err(())));
167    assert!(errs.is_empty());
168}
169
170#[test]
171fn test_calc_multitypes() {
172    let lexerdef = calc_multitypes_l::lexerdef();
173    let lexer = lexerdef.lexer("1+2*3");
174    let (res, _errs) = calc_multitypes_y::parse(&lexer);
175    assert_eq!(res, Some(Ok(7)));
176
177    let lexer = lexerdef.lexer("1++2");
178    let (res, _errs) = calc_multitypes_y::parse(&lexer);
179    assert_eq!(res, Some(Ok(3)));
180}
181
182#[test]
183fn test_input_lifetime() {
184    // This test only exists to make sure that this code compiles: there's no need for us to
185    // actually run anything.
186    let lexerdef = lexer_lifetime_l::lexerdef();
187    let input = "a";
188    let _ = {
189        let lexer = lexerdef.lexer(input);
190        let lx = lexer.iter().next().unwrap().unwrap();
191        lexer.span_str(lx.span())
192    };
193}
194
195#[test]
196fn test_lexer_lifetime() {
197    // This test only exists to make sure that this code compiles: there's no need for us to
198    // actually run anything.
199
200    #[allow(clippy::needless_lifetimes)]
201    pub(crate) fn parse_data<'a>(input: &'a str) -> Option<&'a str> {
202        let lexer_def = crate::lexer_lifetime_l::lexerdef();
203        let l = lexer_def.lexer(input);
204        match crate::lexer_lifetime_y::parse(&l) {
205            (Option::Some(x), _) => Some(x),
206            _ => None,
207        }
208    }
209    parse_data("abc");
210}
211
212#[test]
213fn test_span() {
214    let lexerdef = span_l::lexerdef();
215    let lexer = lexerdef.lexer("2+3");
216    match span_y::parse(&lexer) {
217        (Some(ref spans), _)
218            if spans
219                == &vec![
220                    Span::new(0, 1),
221                    Span::new(0, 1),
222                    Span::new(0, 1),
223                    Span::new(2, 3),
224                    Span::new(2, 3),
225                    Span::new(0, 3),
226                ] => {}
227        _ => unreachable!(),
228    }
229
230    let lexer = lexerdef.lexer("2 + 3");
231    match span_y::parse(&lexer) {
232        (Some(ref spans), _)
233            if spans
234                == &vec![
235                    Span::new(0, 1),
236                    Span::new(0, 1),
237                    Span::new(0, 1),
238                    Span::new(4, 5),
239                    Span::new(4, 5),
240                    Span::new(0, 5),
241                ] => {}
242        _ => unreachable!(),
243    }
244
245    let lexer = lexerdef.lexer("2+3*4");
246    match span_y::parse(&lexer) {
247        (Some(ref spans), _)
248            if spans
249                == &vec![
250                    Span::new(0, 1),
251                    Span::new(0, 1),
252                    Span::new(0, 1),
253                    Span::new(2, 3),
254                    Span::new(2, 3),
255                    Span::new(4, 5),
256                    Span::new(2, 5),
257                    Span::new(0, 5),
258                ] => {}
259        _ => unreachable!(),
260    }
261
262    let lexer = lexerdef.lexer("2++3");
263    match span_y::parse(&lexer) {
264        (Some(ref spans), _)
265            if spans
266                == &vec![
267                    Span::new(0, 1),
268                    Span::new(0, 1),
269                    Span::new(0, 1),
270                    Span::new(3, 4),
271                    Span::new(3, 4),
272                    Span::new(0, 4),
273                ] => {}
274        _ => unreachable!(),
275    }
276
277    let lexer = lexerdef.lexer("(2)))");
278    match dbg!(span_y::parse(&lexer)) {
279        (Some(ref spans), _)
280            if spans
281                == &vec![
282                    Span::new(1, 2),
283                    Span::new(1, 2),
284                    Span::new(1, 2),
285                    Span::new(0, 3),
286                    Span::new(0, 3),
287                    Span::new(0, 3),
288                ] => {}
289        _ => unreachable!(),
290    }
291}
292
293#[test]
294fn test_parseparam() {
295    let lexerdef = parseparam_l::lexerdef();
296    let lexer = lexerdef.lexer("101");
297    match parseparam_y::parse(&lexer, &3) {
298        (Some(104), _) => (),
299        _ => unreachable!(),
300    }
301}
302
303#[test]
304fn test_parseparam_copy() {
305    let lexerdef = parseparam_copy_l::lexerdef();
306    let lexer = lexerdef.lexer("101");
307    match parseparam_copy_y::parse(&lexer, 3) {
308        (Some(104), _) => (),
309        _ => unreachable!(),
310    }
311}
312
313#[test]
314fn test_typeparams() {
315    let lexerdef = typeparams_l::lexerdef();
316    let lexer = lexerdef.lexer("101");
317    match typeparams_y::parse(&lexer, &3u64) {
318        (Some(104u64), _) => (),
319        _ => unreachable!(),
320    }
321}
322
323#[test]
324fn test_passthrough() {
325    let lexerdef = passthrough_l::lexerdef();
326    let lexer = lexerdef.lexer("101");
327    match passthrough_y::parse(&lexer) {
328        (Some(Ok(ref s)), _) if s == "$101" => (),
329        _ => unreachable!(),
330    }
331}
332
333#[test]
334fn test_storaget() {
335    let lexerdef = storaget_l::lexerdef();
336    let lexer = lexerdef.lexer("glasses, keys, umbrella");
337    let expect = ["glasses", "keys", "umbrella"]
338        .iter()
339        .map(|x| x.to_string())
340        .collect::<Vec<_>>();
341    let (val, e) = storaget_y::parse(&lexer);
342    assert_eq!(val, Some(expect));
343    assert!(e.is_empty());
344}
345
346#[test]
347fn test_expect() {
348    // This test merely needs to compile in order to be successful.
349}
350
351// This test isn't run on wasm32-wasi because it accesses
352// various files from across the project workspace.
353//
354// Wasi's filesystem access is sandboxed by default.
355#[cfg(all(not(target_arch = "wasm32"), test))]
356#[test]
357fn test_grmtools_section_files() {
358    use glob::glob;
359    use std::fs::File;
360    use std::io::BufReader;
361    use std::io::{BufRead as _, Read as _};
362
363    let manifest_dir = env!("CARGO_MANIFEST_DIR");
364    let examples_glob = format!("{manifest_dir}/../examples/**");
365    let examples_l_glob = format!("{examples_glob}/*.l");
366    let examples_y_glob = format!("{examples_glob}/*.y");
367    let out_dir = env!("OUT_DIR");
368    let cttests_l_glob = format!("{out_dir}/*.l");
369    let cttests_y_glob = format!("{out_dir}/*.y");
370    let files = glob(&examples_l_glob)
371        .unwrap()
372        .chain(glob(&examples_y_glob).unwrap())
373        .chain(glob(&cttests_l_glob).unwrap())
374        .chain(glob(&cttests_y_glob).unwrap())
375        .collect::<Vec<_>>();
376    assert!(!files.is_empty());
377    for file_path in files {
378        let file_path = file_path.unwrap();
379        let mut s = String::new();
380        let mut f = File::open(&file_path).unwrap();
381        let _ = f.read_to_string(&mut s).unwrap();
382        if s.starts_with("%grmtools") {
383            let mut buf = Vec::new();
384            let mut reader = BufReader::new(s.as_bytes());
385            let _ = reader.read_until(b'}', &mut buf);
386            let lexerdef = grmtools_section_l::lexerdef();
387            let s = String::from_utf8(buf).unwrap();
388            let l = lexerdef.lexer(&s);
389            let (yacc_parsed, errs) = grmtools_section_y::parse(&l);
390            let parser = cfgrammar::header::GrmtoolsSectionParser::new(&s, true);
391            let (header_parsed, _) = parser.parse().unwrap();
392            assert_eq!(yacc_parsed.unwrap().unwrap(), header_parsed);
393            assert!(errs.is_empty());
394        }
395    }
396}
397
398#[test]
399fn test_grmtools_section_strings() {
400    let srcs = [
401        "%grmtools{}",
402        "%grmtools{x}",
403        "%grmtools{x,}",
404        "%grmtools{!x}",
405        "%grmtools{!x,}",
406        "%grmtools{x: y}",
407        "%grmtools{x: y,}",
408        "%grmtools{x, y}",
409        "%grmtools{x, y,}",
410        "%grmtools{x, !y}",
411        "%grmtools{x, !y,}",
412        "%grmtools{x: y(z)}",
413        "%grmtools{x: y(z),}",
414        "%grmtools{a, x: y(z),}",
415        "%grmtools{a, x: y(z)}",
416        "%grmtools{a, !b, x: y(z), e: f}",
417        "%grmtools{a, !b, x: y(z), e: f,}",
418        "%grmtools{a, !b, x: w::y(z), e: f}",
419        "%grmtools{a, !b, x: w::y(z), e: f,}",
420        "%grmtools{a, !b, x: w::y(z), e: g::f}",
421        "%grmtools{a, !b, x: w::y(z), e: g::f,}",
422    ];
423
424    let lexerdef = grmtools_section_l::lexerdef();
425    for src in srcs {
426        let l = lexerdef.lexer(src);
427        let (yacc_parsed, errs) = grmtools_section_y::parse(&l);
428        let yacc_parsed = yacc_parsed.unwrap().unwrap();
429        let parser = cfgrammar::header::GrmtoolsSectionParser::new(src, true);
430        let (header_parsed, _) = parser.parse().unwrap();
431        assert_eq!(yacc_parsed, header_parsed);
432        assert!(errs.is_empty());
433    }
434}
435
436// regex options set through the builder methods.
437#[test]
438fn test_regex_opt() {
439    let lexerdef = regex_opt_l::lexerdef();
440    let lexer = lexerdef.lexer("a");
441    match regex_opt_y::parse(&lexer) {
442        ref errs if errs.is_empty() => (),
443        e => panic!("{:?}", e),
444    }
445}
446
447// Lex flags set through the grmtools section.
448#[test]
449fn test_lex_flags() {
450    let lexerdef = lex_flags_l::lexerdef();
451    let lexer = lexerdef.lexer("a");
452    match lex_flags_y::parse(&lexer) {
453        ref errs if errs.is_empty() => (),
454        e => panic!("{:?}", e),
455    }
456}
457
458#[test]
459fn ast_unmodified() {
460    let lexerdef = ast_unmodified_l::lexerdef();
461    let lexer = lexerdef.lexer("A: BBBB, CCCCC;");
462    match &ast_unmodified_y::parse(&lexer) {
463        (_, errs) if errs.is_empty() => (),
464        (_, e) => panic!("{:?}", e),
465    }
466}
467
468#[test]
469fn ast_modified() {
470    let lexerdef = ast_modified_l::lexerdef();
471    let lexer = lexerdef.lexer("CCCCC, BBBB");
472    match &ast_modified_y::parse(&lexer) {
473        (_, errs) if errs.is_empty() => (),
474        (_, e) => panic!("{:?}", e),
475    }
476}
477
478// Codegen failure tests
479#[cfg(test)]
480generate_codegen_fail_tests!("src/ctfails/*.test");