Skip to main content

walker_subs/
walker_subs.rs

1//! North-star example #2b for Step 2 (`docs/plan/README.md` §4
2//! Step 2.3): the subs defined in the main script file, with their
3//! location (first COP), lexicals (pad names, `my Foo $x` types
4//! included) and the head of their execution-order op chain.
5//!
6//! ```text
7//! cargo run --example walker_subs -- -e 'sub add { my ($x, $y) = @_; $x + $y }'
8//! ```
9//!
10//! Port of libperl-proto0's `107_scan_subs_in_a_file.rs` /
11//! `108`/`109` — the `my (...) = @_;` pattern-matching part of 109 is
12//! left to a future analyzer layer; this shows the raw material such
13//! an analyzer consumes.
14
15use std::env;
16
17use libperl_rs::{Perl, StashWalker};
18
19fn main() {
20    let mut perl = Perl::new();
21    perl.parse_env_args(env::args(), env::vars());
22
23    let sv0 = perl.get_sv("0", 0).expect("$0 is always set");
24    let main_file = String::from_utf8_lossy(sv0.pv(&perl)).into_owned();
25    println!("$0 = {main_file:?}");
26
27    let mut walker = StashWalker::new(&perl);
28    walker.walk("main", &mut |e| {
29        if e.cv.file().as_deref() != Some(main_file.as_str()) {
30            return;
31        }
32        let qual = e
33            .cv
34            .names(&perl)
35            .map(|(full, _)| full)
36            .unwrap_or_else(|| format!("{}::{}", e.package, e.name));
37        let line = e.cv.first_cop(&perl).map(|c| c.line());
38        println!("sub {qual} (first statement at line {line:?})");
39
40        let lexicals: Vec<String> = e
41            .cv
42            .pad_names()
43            .flatten() // skip unnamed slots
44            .filter_map(|pn| {
45                // Target/temporary slots have a non-null but empty PV;
46                // only real `my`/`our` names are interesting here.
47                let pv = pn.pv().filter(|s| !s.is_empty())?;
48                Some(match pn.type_stash_name() {
49                    Some(t) => format!("{pv}: {t}"),
50                    None => pv,
51                })
52            })
53            .collect();
54        println!("  lexicals: {lexicals:?}");
55
56        let ops: Vec<&str> = e
57            .cv
58            .start_op()
59            .into_iter()
60            .flat_map(|s| s.next_iter())
61            .take(20)
62            .map(|o| o.name().unwrap_or("<custom>"))
63            .collect();
64        println!("  ops (execution order, first 20): {}", ops.join(" "));
65    });
66}