103_scan_op_tree/eg/
op0.rs

1#![allow(non_snake_case)]
2
3#[cfg(perlapi_ver26)]
4use std::convert::TryFrom;
5
6pub use libperl_sys::op;
7
8use libperl_sys::*;
9use libperl_rs::Perl;
10
11use super::sv0::{Sv, sv_extract};
12use super::pad0::*;
13
14#[allow(non_camel_case_types)]
15#[derive(Debug)]
16pub enum Op/* <'a>*/ {
17    NULL,
18    OP (opcode, Option<String>, Option<String>),
19    UNOP (opcode/*, &'a unop*/),
20    BINOP (opcode/*, &'a binop*/),
21    LOGOP (opcode/*, &'a logop*/),
22    LISTOP (opcode/*, &'a listop*/),
23    PMOP (opcode/*, &'a pmop*/),
24    SVOP (opcode, Sv),
25    PADOP (opcode, Sv),
26    PVOP (opcode/*, &'a pvop*/),
27    LOOP (opcode/*, &'a loop_*/),
28    COP (opcode/*, &'a cop*/),
29    METHOP (opcode, Name),
30    #[cfg(perlapi_ver26)]
31    UNOP_AUX(opcode),
32}
33
34#[derive(Debug)]
35pub enum Name {
36    Dynamic,
37    Const(Sv),
38}
39
40#[cfg(perlapi_ver26)]
41pub fn op_extract(perl: &Perl, cv: *const cv, o: *const op) -> Op {
42    let cls = perl.op_class(o);
43    let oc = opcode::try_from(o).unwrap();
44    match cls {
45        OPclass::OPclass_NULL => Op::NULL,
46        OPclass::OPclass_BASEOP => {
47            let op = unsafe {o.as_ref().unwrap()};
48            if let Some(pl) = cv_padnamelist(cv) {
49                if let Some(padname) = padnamelist_nth(pl, op.op_targ as usize) {
50                    return Op::OP(oc, PadnamePV(padname), PadnameTYPE(padname))
51                }
52            }
53            Op::OP(oc, None, None)
54        },
55        OPclass::OPclass_UNOP => Op::UNOP(oc/*, unsafe {(o as *const unop).as_ref()}.unwrap()*/),
56        OPclass::OPclass_BINOP => Op::BINOP(oc/*, unsafe {(o as *const binop).as_ref()}.unwrap()*/),
57        OPclass::OPclass_LOGOP => Op::LOGOP(oc/*, unsafe {(o as *const logop).as_ref()}.unwrap()*/),
58        OPclass::OPclass_LISTOP => Op::LISTOP(oc/*, unsafe {(o as *const listop).as_ref()}.unwrap()*/),
59        OPclass::OPclass_PMOP => Op::PMOP(oc/*, unsafe {(o as *const pmop).as_ref()}.unwrap()*/),
60        OPclass::OPclass_SVOP => {
61            let sv = op_sv_or(o, |op| PAD_BASE_SV(CvPADLIST(cv), op.op_targ));
62            Op::SVOP(oc, sv_extract(sv))
63        },
64        OPclass::OPclass_PADOP => {
65            let op = unsafe {(o as *const padop).as_ref()}.unwrap();
66            let sv = PAD_BASE_SV(CvPADLIST(cv), op.op_padix);
67            Op::PADOP(oc, sv_extract(sv))
68        },
69        OPclass::OPclass_PVOP => Op::PVOP(oc/*, unsafe {(o as *const pvop).as_ref()}.unwrap()*/),
70        OPclass::OPclass_LOOP => Op::LOOP(oc/*, unsafe {(o as *const loop_).as_ref()}.unwrap()*/),
71        OPclass::OPclass_COP => Op::COP(oc/*, unsafe {(o as *const cop).as_ref()}.unwrap()*/),
72        OPclass::OPclass_METHOP => {
73            if (unsafe {*o}.op_flags & OPf_KIDS as u8) != 0 {
74                Op::METHOP(oc, Name::Dynamic)
75                
76            } else {
77                let sv = op_sv_or(o, |op| PAD_BASE_SV(CvPADLIST(cv), op.op_targ));
78                Op::METHOP(oc, Name::Const(sv_extract(sv)))
79            }
80        },
81        #[cfg(perlapi_ver26)]
82        OPclass::OPclass_UNOP_AUX => Op::UNOP_AUX(oc /*, unsafe {(o as *const unop_aux).as_ref()}.unwrap()*/),
83    }
84}
85    
86pub fn op_sv_or<F>(op: *const op, f: F) -> *const libperl_sys::sv
87    where F: Fn(&svop) -> *const libperl_sys::sv
88{
89    let svop = unsafe {(op as *const svop).as_ref()}.unwrap();
90    if !svop.op_sv.is_null() {
91        svop.op_sv
92    } else {
93        f(svop)
94    }
95}
96
97pub fn next_iter(op: *const op) -> OpNextIter {
98    OpNextIter {op}
99}
100
101pub struct OpNextIter {
102    op: *const op,
103}
104
105impl Iterator for OpNextIter {
106    type Item = *const op;
107    
108    fn next(&mut self) -> Option<Self::Item> {
109        let op = self.op;
110        if op.is_null() {
111            None
112        } else {
113            self.op = unsafe {(*op).op_next as *const op};
114            Some(op)
115        }
116    }
117}
118
119pub fn op_name(o: *const op) -> String {
120    let ty = unsafe {*o}.op_type();
121    unsafe {
122        std::ffi::CStr::from_ptr(PL_op_name[ty as usize])
123    }.to_str().unwrap().to_string()
124}
125
126pub fn sibling_iter(op: *const op) -> OpSiblingIter {
127    OpSiblingIter {op: op_first(op)}
128}
129
130pub struct OpSiblingIter {
131    op: *const op,
132}
133
134impl Iterator for OpSiblingIter {
135    type Item = *const op;
136    
137    fn next(&mut self) -> Option<Self::Item> {
138        let op = self.op;
139        if op.is_null() {
140            None
141        } else {
142            self.op = op_sibling(op as *const unop);
143            Some(op)
144        }
145    }
146}
147
148#[cfg(perlapi_ver26)]
149pub fn op_sibling(op: *const unop) -> *const op {
150    // PERL_OP_PARENT is on since 5.26
151    if let Some(op) = unsafe {op.as_ref()} {
152        if u32::try_from(op.op_moresib()).unwrap() == 1 as u32 {
153            op.op_sibparent
154        } else {
155            std::ptr::null()
156        }
157    } else {
158        std::ptr::null()
159    }
160}
161
162#[cfg(not(perlapi_ver26))]
163pub fn op_sibling(op: *const unop) -> *const op {
164    if let Some(op) = unsafe {op.as_ref()} {
165        op.op_sibling
166    } else {
167        std::ptr::null()
168    }
169}
170
171pub fn op_first(o: *const op) -> *const op {
172    if o.is_null() || (unsafe {*o}.op_flags & OPf_KIDS as u8) == 0 {
173        std::ptr::null()
174    } else {
175        let uo = o as *const unop;
176        unsafe {*uo}.op_first as *const op
177    }
178}