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