ruby_prism/
lib.rs

1//! # ruby-prism
2//!
3//! Rustified version of Ruby's prism parser.
4//!
5#![warn(clippy::all, clippy::nursery, clippy::pedantic, future_incompatible, missing_docs, nonstandard_style, rust_2018_idioms, trivial_casts, trivial_numeric_casts, unreachable_pub, unused_qualifications)]
6
7// Most of the code in this file is generated, so sometimes it generates code
8// that doesn't follow the clippy rules. We don't want to see those warnings.
9#[allow(clippy::too_many_lines, clippy::use_self)]
10mod bindings {
11    // In `build.rs`, we generate bindings based on the config.yml file. Here is
12    // where we pull in those bindings and make them part of our library.
13    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
14}
15
16mod node;
17mod parse_result;
18
19use std::mem::MaybeUninit;
20use std::ptr::NonNull;
21
22pub use self::bindings::*;
23pub use self::node::{ConstantId, ConstantList, ConstantListIter, Integer, NodeList, NodeListIter};
24pub use self::parse_result::{Comment, CommentType, Comments, Diagnostic, Diagnostics, Location, MagicComment, MagicComments, ParseResult};
25
26use ruby_prism_sys::{pm_arena_t, pm_parse, pm_parser_init, pm_parser_t};
27
28/// Parses the given source string and returns a parse result.
29///
30/// # Panics
31///
32/// Panics if the parser fails to initialize.
33///
34#[must_use]
35pub fn parse(source: &[u8]) -> ParseResult<'_> {
36    unsafe {
37        let mut arena = Box::new(MaybeUninit::<pm_arena_t>::zeroed().assume_init());
38        let uninit = Box::new(MaybeUninit::<pm_parser_t>::uninit());
39        let uninit = Box::into_raw(uninit);
40
41        pm_parser_init(arena.as_mut(), (*uninit).as_mut_ptr(), source.as_ptr(), source.len(), std::ptr::null());
42
43        let parser = (*uninit).assume_init_mut();
44        let parser = NonNull::new_unchecked(parser);
45
46        let node = pm_parse(parser.as_ptr());
47        let node = NonNull::new_unchecked(node);
48
49        ParseResult::new(source, arena, parser, node)
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::parse;
56
57    #[test]
58    fn comments_test() {
59        let source = "# comment 1\n# comment 2\n# comment 3\n";
60        let result = parse(source.as_ref());
61
62        for comment in result.comments() {
63            assert_eq!(super::CommentType::InlineComment, comment.type_());
64            let text = std::str::from_utf8(comment.text()).unwrap();
65            assert!(text.starts_with("# comment"));
66        }
67    }
68
69    #[test]
70    fn line_offsets_test() {
71        let source = "";
72        let result = parse(source.as_ref());
73
74        let expected: [u32; 1] = [0];
75        assert_eq!(expected, result.line_offsets());
76
77        let source = "1 + 1";
78        let result = parse(source.as_ref());
79
80        let expected: [u32; 1] = [0];
81        assert_eq!(expected, result.line_offsets());
82
83        let source = "begin\n1 + 1\n2 + 2\nend";
84        let result = parse(source.as_ref());
85
86        let expected: [u32; 4] = [0, 6, 12, 18];
87        assert_eq!(expected, result.line_offsets());
88    }
89
90    #[test]
91    fn magic_comments_test() {
92        use crate::MagicComment;
93
94        let source = "# typed: ignore\n# typed:true\n#typed: strict\n";
95        let result = parse(source.as_ref());
96
97        let comments: Vec<MagicComment<'_>> = result.magic_comments().collect();
98        assert_eq!(3, comments.len());
99
100        assert_eq!(b"typed", comments[0].key());
101        assert_eq!(b"ignore", comments[0].value());
102
103        assert_eq!(b"typed", comments[1].key());
104        assert_eq!(b"true", comments[1].value());
105
106        assert_eq!(b"typed", comments[2].key());
107        assert_eq!(b"strict", comments[2].value());
108    }
109
110    #[test]
111    fn data_loc_test() {
112        let source = "1";
113        let result = parse(source.as_ref());
114        let data_loc = result.data_loc();
115        assert!(data_loc.is_none());
116
117        let source = "__END__\nabc\n";
118        let result = parse(source.as_ref());
119        let data_loc = result.data_loc().unwrap();
120        let slice = std::str::from_utf8(result.as_slice(&data_loc)).unwrap();
121        assert_eq!(slice, "__END__\nabc\n");
122
123        let source = "1\n2\n3\n__END__\nabc\ndef\n";
124        let result = parse(source.as_ref());
125        let data_loc = result.data_loc().unwrap();
126        let slice = std::str::from_utf8(result.as_slice(&data_loc)).unwrap();
127        assert_eq!(slice, "__END__\nabc\ndef\n");
128    }
129
130    #[test]
131    fn location_test() {
132        let source = "111 + 222 + 333";
133        let result = parse(source.as_ref());
134
135        let node = result.node();
136        let node = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
137        let node = node.as_call_node().unwrap().receiver().unwrap();
138        let plus = node.as_call_node().unwrap();
139        let node = plus.arguments().unwrap().arguments().iter().next().unwrap();
140
141        let location = node.as_integer_node().unwrap().location();
142        let slice = std::str::from_utf8(result.as_slice(&location)).unwrap();
143
144        assert_eq!(slice, "222");
145        assert_eq!(6, location.start);
146        assert_eq!(9, location.end());
147
148        let recv_loc = plus.receiver().unwrap().location();
149        assert_eq!(recv_loc.as_slice(), b"111");
150        assert_eq!(0, recv_loc.start);
151        assert_eq!(3, recv_loc.end());
152
153        let joined = recv_loc.join(&location).unwrap();
154        assert_eq!(joined.as_slice(), b"111 + 222");
155
156        let not_joined = location.join(&recv_loc);
157        assert!(not_joined.is_none());
158
159        {
160            let result = parse(source.as_ref());
161            let node = result.node();
162            let node = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
163            let node = node.as_call_node().unwrap().receiver().unwrap();
164            let plus = node.as_call_node().unwrap();
165            let node = plus.arguments().unwrap().arguments().iter().next().unwrap();
166
167            let location = node.as_integer_node().unwrap().location();
168            let not_joined = recv_loc.join(&location);
169            assert!(not_joined.is_none());
170
171            let not_joined = location.join(&recv_loc);
172            assert!(not_joined.is_none());
173        }
174
175        let location = node.location();
176        let slice = std::str::from_utf8(result.as_slice(&location)).unwrap();
177
178        assert_eq!(slice, "222");
179
180        let slice = std::str::from_utf8(location.as_slice()).unwrap();
181
182        assert_eq!(slice, "222");
183    }
184
185    #[test]
186    fn visitor_test() {
187        use super::{visit_interpolated_regular_expression_node, visit_regular_expression_node, InterpolatedRegularExpressionNode, RegularExpressionNode, Visit};
188
189        struct RegularExpressionVisitor {
190            count: usize,
191        }
192
193        impl Visit<'_> for RegularExpressionVisitor {
194            fn visit_interpolated_regular_expression_node(&mut self, node: &InterpolatedRegularExpressionNode<'_>) {
195                self.count += 1;
196                visit_interpolated_regular_expression_node(self, node);
197            }
198
199            fn visit_regular_expression_node(&mut self, node: &RegularExpressionNode<'_>) {
200                self.count += 1;
201                visit_regular_expression_node(self, node);
202            }
203        }
204
205        let source = "# comment 1\n# comment 2\nmodule Foo; class Bar; /abc #{/def/}/; end; end";
206        let result = parse(source.as_ref());
207
208        let mut visitor = RegularExpressionVisitor { count: 0 };
209        visitor.visit(&result.node());
210
211        assert_eq!(visitor.count, 2);
212    }
213
214    #[test]
215    fn node_upcast_test() {
216        use super::Node;
217
218        let source = "module Foo; end";
219        let result = parse(source.as_ref());
220
221        let node = result.node();
222        let upcast_node = node.as_program_node().unwrap().as_node();
223        assert!(matches!(upcast_node, Node::ProgramNode { .. }));
224
225        let node = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
226        let upcast_node = node.as_module_node().unwrap().as_node();
227        assert!(matches!(upcast_node, Node::ModuleNode { .. }));
228    }
229
230    #[test]
231    fn constant_id_test() {
232        let source = "module Foo; x = 1; y = 2; end";
233        let result = parse(source.as_ref());
234
235        let node = result.node();
236        assert_eq!(node.as_program_node().unwrap().statements().body().len(), 1);
237        assert!(!node.as_program_node().unwrap().statements().body().is_empty());
238        let module = node.as_program_node().and_then(|pn| pn.statements().body().first()).unwrap();
239        let module = module.as_module_node().unwrap();
240
241        assert_eq!(module.locals().len(), 2);
242        assert!(!module.locals().is_empty());
243
244        assert_eq!(module.locals().first().unwrap().as_slice(), b"x");
245        assert_eq!(module.locals().last().unwrap().as_slice(), b"y");
246
247        let source = "module Foo; end";
248        let result = parse(source.as_ref());
249
250        let node = result.node();
251        assert_eq!(node.as_program_node().unwrap().statements().body().len(), 1);
252        assert!(!node.as_program_node().unwrap().statements().body().is_empty());
253        let module = node.as_program_node().and_then(|pn| pn.statements().body().first()).unwrap();
254        let module = module.as_module_node().unwrap();
255
256        assert_eq!(module.locals().len(), 0);
257        assert!(module.locals().is_empty());
258    }
259
260    #[test]
261    fn optional_loc_test() {
262        let source = r"
263module Example
264  x = call_func(3, 4)
265  y = x.call_func 5, 6
266end
267";
268        let result = parse(source.as_ref());
269
270        let node = result.node();
271        let module = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
272        let module = module.as_module_node().unwrap();
273        let body = module.body();
274        let writes = body.iter().next().unwrap().as_statements_node().unwrap().body().iter().collect::<Vec<_>>();
275        assert_eq!(writes.len(), 2);
276
277        let asgn = &writes[0];
278        let call = asgn.as_local_variable_write_node().unwrap().value();
279        let call = call.as_call_node().unwrap();
280
281        let call_operator_loc = call.call_operator_loc();
282        assert!(call_operator_loc.is_none());
283        let closing_loc = call.closing_loc();
284        assert!(closing_loc.is_some());
285
286        let asgn = &writes[1];
287        let call = asgn.as_local_variable_write_node().unwrap().value();
288        let call = call.as_call_node().unwrap();
289
290        let call_operator_loc = call.call_operator_loc();
291        assert!(call_operator_loc.is_some());
292        let closing_loc = call.closing_loc();
293        assert!(closing_loc.is_none());
294    }
295
296    #[test]
297    fn frozen_strings_test() {
298        let source = r#"
299# frozen_string_literal: true
300"foo"
301"#;
302        let result = parse(source.as_ref());
303        assert!(result.frozen_string_literals());
304
305        let source = "3";
306        let result = parse(source.as_ref());
307        assert!(!result.frozen_string_literals());
308    }
309
310    #[test]
311    fn string_flags_test() {
312        let source = r#"
313# frozen_string_literal: true
314"foo"
315"#;
316        let result = parse(source.as_ref());
317
318        let node = result.node();
319        let string = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
320        let string = string.as_string_node().unwrap();
321        assert!(string.is_frozen());
322
323        let source = r#"
324"foo"
325"#;
326        let result = parse(source.as_ref());
327
328        let node = result.node();
329        let string = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
330        let string = string.as_string_node().unwrap();
331        assert!(!string.is_frozen());
332    }
333
334    #[test]
335    fn call_flags_test() {
336        let source = r"
337x
338";
339        let result = parse(source.as_ref());
340
341        let node = result.node();
342        let call = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
343        let call = call.as_call_node().unwrap();
344        assert!(call.is_variable_call());
345
346        let source = r"
347x&.foo
348";
349        let result = parse(source.as_ref());
350
351        let node = result.node();
352        let call = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
353        let call = call.as_call_node().unwrap();
354        assert!(call.is_safe_navigation());
355    }
356
357    #[test]
358    fn integer_flags_test() {
359        let source = r"
3600b1
361";
362        let result = parse(source.as_ref());
363
364        let node = result.node();
365        let i = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
366        let i = i.as_integer_node().unwrap();
367        assert!(i.is_binary());
368        assert!(!i.is_decimal());
369        assert!(!i.is_octal());
370        assert!(!i.is_hexadecimal());
371
372        let source = r"
3731
374";
375        let result = parse(source.as_ref());
376
377        let node = result.node();
378        let i = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
379        let i = i.as_integer_node().unwrap();
380        assert!(!i.is_binary());
381        assert!(i.is_decimal());
382        assert!(!i.is_octal());
383        assert!(!i.is_hexadecimal());
384
385        let source = r"
3860o1
387";
388        let result = parse(source.as_ref());
389
390        let node = result.node();
391        let i = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
392        let i = i.as_integer_node().unwrap();
393        assert!(!i.is_binary());
394        assert!(!i.is_decimal());
395        assert!(i.is_octal());
396        assert!(!i.is_hexadecimal());
397
398        let source = r"
3990x1
400";
401        let result = parse(source.as_ref());
402
403        let node = result.node();
404        let i = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
405        let i = i.as_integer_node().unwrap();
406        assert!(!i.is_binary());
407        assert!(!i.is_decimal());
408        assert!(!i.is_octal());
409        assert!(i.is_hexadecimal());
410    }
411
412    #[test]
413    fn range_flags_test() {
414        let source = r"
4150..1
416";
417        let result = parse(source.as_ref());
418
419        let node = result.node();
420        let range = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
421        let range = range.as_range_node().unwrap();
422        assert!(!range.is_exclude_end());
423
424        let source = r"
4250...1
426";
427        let result = parse(source.as_ref());
428
429        let node = result.node();
430        let range = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
431        let range = range.as_range_node().unwrap();
432        assert!(range.is_exclude_end());
433    }
434
435    #[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
436    #[test]
437    fn regex_flags_test() {
438        let source = r"
439/a/i
440";
441        let result = parse(source.as_ref());
442
443        let node = result.node();
444        let regex = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
445        let regex = regex.as_regular_expression_node().unwrap();
446        assert!(regex.is_ignore_case());
447        assert!(!regex.is_extended());
448        assert!(!regex.is_multi_line());
449        assert!(!regex.is_euc_jp());
450        assert!(!regex.is_ascii_8bit());
451        assert!(!regex.is_windows_31j());
452        assert!(!regex.is_utf_8());
453        assert!(!regex.is_once());
454
455        let source = r"
456/a/x
457";
458        let result = parse(source.as_ref());
459
460        let node = result.node();
461        let regex = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
462        let regex = regex.as_regular_expression_node().unwrap();
463        assert!(!regex.is_ignore_case());
464        assert!(regex.is_extended());
465        assert!(!regex.is_multi_line());
466        assert!(!regex.is_euc_jp());
467        assert!(!regex.is_ascii_8bit());
468        assert!(!regex.is_windows_31j());
469        assert!(!regex.is_utf_8());
470        assert!(!regex.is_once());
471
472        let source = r"
473/a/m
474";
475        let result = parse(source.as_ref());
476
477        let node = result.node();
478        let regex = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
479        let regex = regex.as_regular_expression_node().unwrap();
480        assert!(!regex.is_ignore_case());
481        assert!(!regex.is_extended());
482        assert!(regex.is_multi_line());
483        assert!(!regex.is_euc_jp());
484        assert!(!regex.is_ascii_8bit());
485        assert!(!regex.is_windows_31j());
486        assert!(!regex.is_utf_8());
487        assert!(!regex.is_once());
488
489        let source = r"
490/a/e
491";
492        let result = parse(source.as_ref());
493
494        let node = result.node();
495        let regex = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
496        let regex = regex.as_regular_expression_node().unwrap();
497        assert!(!regex.is_ignore_case());
498        assert!(!regex.is_extended());
499        assert!(!regex.is_multi_line());
500        assert!(regex.is_euc_jp());
501        assert!(!regex.is_ascii_8bit());
502        assert!(!regex.is_windows_31j());
503        assert!(!regex.is_utf_8());
504        assert!(!regex.is_once());
505
506        let source = r"
507/a/n
508";
509        let result = parse(source.as_ref());
510
511        let node = result.node();
512        let regex = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
513        let regex = regex.as_regular_expression_node().unwrap();
514        assert!(!regex.is_ignore_case());
515        assert!(!regex.is_extended());
516        assert!(!regex.is_multi_line());
517        assert!(!regex.is_euc_jp());
518        assert!(regex.is_ascii_8bit());
519        assert!(!regex.is_windows_31j());
520        assert!(!regex.is_utf_8());
521        assert!(!regex.is_once());
522
523        let source = r"
524/a/s
525";
526        let result = parse(source.as_ref());
527
528        let node = result.node();
529        let regex = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
530        let regex = regex.as_regular_expression_node().unwrap();
531        assert!(!regex.is_ignore_case());
532        assert!(!regex.is_extended());
533        assert!(!regex.is_multi_line());
534        assert!(!regex.is_euc_jp());
535        assert!(!regex.is_ascii_8bit());
536        assert!(regex.is_windows_31j());
537        assert!(!regex.is_utf_8());
538        assert!(!regex.is_once());
539
540        let source = r"
541/a/u
542";
543        let result = parse(source.as_ref());
544
545        let node = result.node();
546        let regex = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
547        let regex = regex.as_regular_expression_node().unwrap();
548        assert!(!regex.is_ignore_case());
549        assert!(!regex.is_extended());
550        assert!(!regex.is_multi_line());
551        assert!(!regex.is_euc_jp());
552        assert!(!regex.is_ascii_8bit());
553        assert!(!regex.is_windows_31j());
554        assert!(regex.is_utf_8());
555        assert!(!regex.is_once());
556
557        let source = r"
558/a/o
559";
560        let result = parse(source.as_ref());
561
562        let node = result.node();
563        let regex = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
564        let regex = regex.as_regular_expression_node().unwrap();
565        assert!(!regex.is_ignore_case());
566        assert!(!regex.is_extended());
567        assert!(!regex.is_multi_line());
568        assert!(!regex.is_euc_jp());
569        assert!(!regex.is_ascii_8bit());
570        assert!(!regex.is_windows_31j());
571        assert!(!regex.is_utf_8());
572        assert!(regex.is_once());
573    }
574
575    #[test]
576    fn visitor_traversal_test() {
577        use crate::{Node, Visit};
578
579        #[derive(Default)]
580        struct NodeCounts {
581            pre_parent: usize,
582            post_parent: usize,
583            pre_leaf: usize,
584            post_leaf: usize,
585        }
586
587        #[derive(Default)]
588        struct CountingVisitor {
589            counts: NodeCounts,
590        }
591
592        impl Visit<'_> for CountingVisitor {
593            fn visit_branch_node_enter(&mut self, _node: Node<'_>) {
594                self.counts.pre_parent += 1;
595            }
596
597            fn visit_branch_node_leave(&mut self) {
598                self.counts.post_parent += 1;
599            }
600
601            fn visit_leaf_node_enter(&mut self, _node: Node<'_>) {
602                self.counts.pre_leaf += 1;
603            }
604
605            fn visit_leaf_node_leave(&mut self) {
606                self.counts.post_leaf += 1;
607            }
608        }
609
610        let source = r"
611module Example
612  x = call_func(3, 4)
613  y = x.call_func 5, 6
614end
615";
616        let result = parse(source.as_ref());
617        let node = result.node();
618        let mut visitor = CountingVisitor::default();
619        visitor.visit(&node);
620
621        assert_eq!(7, visitor.counts.pre_parent);
622        assert_eq!(7, visitor.counts.post_parent);
623        assert_eq!(6, visitor.counts.pre_leaf);
624        assert_eq!(6, visitor.counts.post_leaf);
625    }
626
627    #[test]
628    fn visitor_lifetime_test() {
629        use crate::{Node, Visit};
630
631        #[derive(Default)]
632        struct StackingNodeVisitor<'a> {
633            stack: Vec<Node<'a>>,
634            max_depth: usize,
635        }
636
637        impl<'pr> Visit<'pr> for StackingNodeVisitor<'pr> {
638            fn visit_branch_node_enter(&mut self, node: Node<'pr>) {
639                self.stack.push(node);
640            }
641
642            fn visit_branch_node_leave(&mut self) {
643                self.stack.pop();
644            }
645
646            fn visit_leaf_node_leave(&mut self) {
647                self.max_depth = self.max_depth.max(self.stack.len());
648            }
649        }
650
651        let source = r"
652module Example
653  x = call_func(3, 4)
654  y = x.call_func 5, 6
655end
656";
657        let result = parse(source.as_ref());
658        let node = result.node();
659        let mut visitor = StackingNodeVisitor::default();
660        visitor.visit(&node);
661
662        assert_eq!(0, visitor.stack.len());
663        assert_eq!(5, visitor.max_depth);
664    }
665
666    #[test]
667    fn integer_value_test() {
668        let result = parse("0xA".as_ref());
669        let integer = result.node().as_program_node().unwrap().statements().body().iter().next().unwrap().as_integer_node().unwrap().value();
670        let value: i32 = integer.try_into().unwrap();
671
672        assert_eq!(value, 10);
673    }
674
675    #[test]
676    fn integer_small_value_to_u32_digits_test() {
677        let result = parse("0xA".as_ref());
678        let integer = result.node().as_program_node().unwrap().statements().body().iter().next().unwrap().as_integer_node().unwrap().value();
679        let (negative, digits) = integer.to_u32_digits();
680
681        assert!(!negative);
682        assert_eq!(digits, &[10]);
683    }
684
685    #[test]
686    fn integer_large_value_to_u32_digits_test() {
687        let result = parse("0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".as_ref());
688        let integer = result.node().as_program_node().unwrap().statements().body().iter().next().unwrap().as_integer_node().unwrap().value();
689        let (negative, digits) = integer.to_u32_digits();
690
691        assert!(!negative);
692        assert_eq!(digits, &[4_294_967_295, 4_294_967_295, 4_294_967_295, 2_147_483_647]);
693    }
694
695    #[test]
696    fn float_value_test() {
697        let result = parse("1.0".as_ref());
698        let value: f64 = result.node().as_program_node().unwrap().statements().body().iter().next().unwrap().as_float_node().unwrap().value();
699
700        assert!((value - 1.0).abs() < f64::EPSILON);
701    }
702
703    #[test]
704    fn regex_value_test() {
705        let result = parse(b"//");
706        let node = result.node().as_program_node().unwrap().statements().body().iter().next().unwrap().as_regular_expression_node().unwrap();
707        assert_eq!(node.unescaped(), b"");
708    }
709
710    #[test]
711    fn node_field_lifetime_test() {
712        // The code below wouldn't typecheck prior to https://github.com/ruby/prism/pull/2519,
713        // but we need to stop clippy from complaining about it.
714        #![allow(clippy::needless_pass_by_value)]
715
716        use crate::Node;
717
718        #[derive(Default)]
719        struct Extract<'pr> {
720            scopes: Vec<crate::ConstantId<'pr>>,
721        }
722
723        impl<'pr> Extract<'pr> {
724            fn push_scope(&mut self, path: Node<'pr>) {
725                if let Some(cread) = path.as_constant_read_node() {
726                    self.scopes.push(cread.name());
727                } else if let Some(cpath) = path.as_constant_path_node() {
728                    if let Some(parent) = cpath.parent() {
729                        self.push_scope(parent);
730                    }
731                    self.scopes.push(cpath.name().unwrap());
732                } else {
733                    panic!("Wrong node kind!");
734                }
735            }
736        }
737
738        let source = "Some::Random::Constant";
739        let result = parse(source.as_ref());
740        let node = result.node();
741        let mut extractor = Extract::default();
742        extractor.push_scope(node.as_program_node().unwrap().statements().body().iter().next().unwrap());
743        assert_eq!(3, extractor.scopes.len());
744    }
745
746    #[test]
747    fn malformed_shebang() {
748        let source = "#!\x00";
749        let result = parse(source.as_ref());
750        assert!(result.errors().next().is_none());
751        assert!(result.warnings().next().is_none());
752    }
753}