103_scan_op_tree/eg/
op1.rs

1#![allow(non_snake_case)]
2#![allow(unused_imports)]
3
4#[cfg(perlapi_ver26)]
5use std::convert::TryFrom;
6
7pub use libperl_sys::op;
8
9use if_chain::if_chain;
10
11use libperl_sys::*;
12use libperl_rs::Perl;
13
14use super::sv0::{Sv, VarName, sv_extract};
15use super::pad0::*;
16use super::op0::{op_sibling, op_sv_or, Name};
17pub use super::op0::op_name;
18
19use typed_arena::Arena;
20
21pub struct OpExtractor<'a> {
22    perl: &'a Perl,
23    ops: Arena<Op<'a>>,
24}
25
26#[derive(Debug, Clone)]
27pub struct PadNameType {
28    name: Option<String>,
29    typ: Option<String>,
30}
31
32struct OpcodeWrap<'a> (&'a opcode);
33
34impl<'a> std::fmt::Debug for OpcodeWrap<'a> {
35    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36        f.write_str("opcode::")?;
37        self.0.fmt(f)
38    }
39}
40
41#[allow(non_camel_case_types)]
42pub enum Op<'a> {
43    NULL,
44    OP (opcode, *const op, Option<PadNameType>, &'a Op<'a>),
45    UNOP (opcode, *const unop, &'a Op<'a>, &'a Op<'a>),
46    BINOP (opcode, *const binop, &'a Op<'a>, &'a Op<'a>),
47    LOGOP (opcode, *const logop, &'a Op<'a>, &'a Op<'a>),
48    LISTOP (opcode, *const listop, &'a Op<'a>, &'a Op<'a>), // , last: &'a Op<'a>
49    PMOP {opcode: opcode// , sibling: &'a Op<'a>, first: &'a Op<'a>, last: &'a Op<'a>
50    },
51    SVOP (opcode, Sv, &'a Op<'a>),
52    PADOP (opcode, *const padop, Sv),
53    PVOP (opcode/*, &'a pvop*/),
54    LOOP (opcode, &'a Op<'a> //, first: &'a Op<'a>, last: &'a Op<'a>, redoop: &'a Op<'a>, next: &'a Op<'a>, last: &'a Op<'a>
55    ),
56    COP (opcode, &'a Op<'a>),
57    METHOP(opcode, Name),
58    // {opcode: opcode, sibling: &'a Op<'a>, name: Name},
59    #[cfg(perlapi_ver26)]
60    UNOP_AUX (opcode, &'a Op<'a>, &'a Op<'a>),
61}
62
63impl<'a> std::fmt::Debug for  Op<'a> {
64    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65        match &self {
66            Op::NULL => { f.debug_tuple("Op::NULL").finish() },
67            Op::OP(oc, _, padname, sibling) => {
68                f.debug_tuple("Op::OP")
69                    .field(&OpcodeWrap(oc))
70                    .field(&VarName("_"))
71                    .field(&padname)
72                    .field(&sibling)
73                    .finish()
74            },
75            Op::UNOP(oc, _, first, sibling) => {
76                f.debug_tuple("Op::UNOP")
77                    .field(&OpcodeWrap(oc))
78                    .field(&VarName("_"))
79                    .field(&first)
80                    .field(&sibling)
81                    .finish()
82            },
83            Op::BINOP(oc, _, first, sibling) => {
84                f.debug_tuple("Op::BINOP")
85                    .field(&OpcodeWrap(oc))
86                    .field(&VarName("_"))
87                    .field(&first)
88                    .field(&sibling)
89                    .finish()
90            },
91            Op::LOGOP(oc, _, first, sibling) => {
92                f.debug_tuple("Op::LOGOP")
93                    .field(&OpcodeWrap(oc))
94                    .field(&VarName("_"))
95                    .field(&first)
96                    .field(&sibling)
97                    .finish()
98            },
99            Op::LISTOP(oc, _, first, sibling) => {
100                f.debug_tuple("Op::LISTOP")
101                    .field(&OpcodeWrap(oc))
102                    .field(&VarName("_"))
103                    .field(&first)
104                    .field(&sibling)
105                    .finish()
106            },
107            Op::PMOP {opcode: oc} => {
108                f.debug_struct("Op::PMOP")
109                    .field("opcode", &OpcodeWrap(oc))
110                    // XXX
111                    .finish()
112            },
113            Op::SVOP(oc, sv, sibling) => {
114                f.debug_tuple("Op::SVOP")
115                    .field(&OpcodeWrap(oc))
116                    .field(&sv)
117                    .field(&sibling)
118                    .finish()
119            },
120            Op::PADOP(oc, _, sibling) => {
121                f.debug_tuple("Op::PADOP")
122                    .field(&OpcodeWrap(oc))
123                    .field(&VarName("_"))
124                    .field(&sibling)
125                    .finish()
126            },
127            Op::PVOP(oc) => {
128                f.debug_tuple("Op::PVOP")
129                    .field(&OpcodeWrap(oc))
130                    .finish()
131            },
132            Op::LOOP(oc, sibling) => {
133                f.debug_tuple("Op::LOOP")
134                    .field(&OpcodeWrap(oc))
135                    .field(&sibling)
136                    .finish()
137            },
138            Op::COP(oc, sibling) => {
139                f.debug_tuple("Op::COP")
140                    .field(&OpcodeWrap(oc))
141                    .field(sibling)
142                    .finish()
143            },
144            Op::METHOP(oc, name) => {
145                f.debug_tuple("Op::METHOP")
146                    .field(&OpcodeWrap(oc))
147                    .field(&name)
148                    .finish()
149            },
150            #[cfg(perlapi_ver26)]
151            Op::UNOP_AUX(oc, first, sibling) => {
152                f.debug_tuple("Op::UNOP_AUX")
153                    .field(&OpcodeWrap(oc))
154                    .field(&first)
155                    .field(&sibling)
156                    .finish()
157            },
158        }
159    }
160}
161
162#[cfg(perlapi_ver26)]
163impl<'a> OpExtractor<'a> {
164    
165    pub fn new(perl: &'a Perl) -> Self {
166        Self {perl, ops: Arena::new()}
167    }
168
169    pub fn extract(&self, cv: *const cv, o: *const op) -> &'a Op {
170        if o.is_null() {
171            return self.ops.alloc(Op::NULL)
172        }
173        let cls = self.perl.op_class(o);
174        let oc = opcode::try_from(o).unwrap();
175        let eo = match cls {
176            OPclass::OPclass_NULL => Op::NULL,
177            OPclass::OPclass_BASEOP => {
178                let op = unsafe {o.as_ref().unwrap()};
179                let sibling = self.extract(cv, op_sibling(o as *const unop));
180                if_chain! {
181                    if let Some(pl) = cv_padnamelist(cv);
182                    if let Some(padname) = padnamelist_nth(pl, op.op_targ as usize);
183                    then {
184                        Op::OP (
185                            oc, o,
186                            Some(PadNameType {
187                                name: PadnamePV(padname), typ: PadnameTYPE(padname)
188                            }),
189                            sibling
190                        )
191                    } else {
192                        Op::OP (oc, o, None, sibling)
193                    }
194                }
195            },
196            OPclass::OPclass_UNOP => {
197                let op = unsafe {(o as *const unop).as_ref()}.unwrap();
198                Op::UNOP (
199                    oc, op,
200                    self.extract(cv, op.op_first),
201                    self.extract(cv, op_sibling(o as *const unop)),
202                )
203            },
204            OPclass::OPclass_BINOP => {
205                let op = unsafe {(o as *const binop).as_ref()}.unwrap();
206                Op::BINOP (
207                    oc, op,
208                    self.extract(cv, op.op_first),
209                    self.extract(cv, op_sibling(o as *const unop)),
210                )
211            },
212            OPclass::OPclass_LOGOP => {
213                let op = unsafe {(o as *const logop).as_ref()}.unwrap();
214                Op::LOGOP (
215                    oc, op,
216                    self.extract(cv, op.op_first),
217                    self.extract(cv, op_sibling(o as *const unop)),
218                )
219            },
220            OPclass::OPclass_LISTOP => {
221                let op = unsafe {(o as *const listop).as_ref()}.unwrap();
222                Op::LISTOP (
223                    oc, op,
224                    self.extract(cv, op.op_first),
225                    self.extract(cv, op_sibling(o as *const unop)),
226                )
227            },
228            // XXX
229            OPclass::OPclass_PMOP => Op::PMOP {opcode: oc},
230            OPclass::OPclass_SVOP => {
231                let sv = op_sv_or(o, |op| PAD_BASE_SV(CvPADLIST(cv), op.op_targ));
232                Op::SVOP (
233                    oc, sv_extract(sv),
234                    self.extract(cv, op_sibling(o as *const unop)),
235                )
236            },
237            OPclass::OPclass_PADOP => {
238                let op = unsafe {(o as *const padop).as_ref()}.unwrap();
239                let sv = PAD_BASE_SV(CvPADLIST(cv), op.op_padix);
240                Op::PADOP(oc, op, sv_extract(sv))
241            },
242            // XXX
243            OPclass::OPclass_PVOP => Op::PVOP (oc),
244            // XXX
245            OPclass::OPclass_LOOP => {
246                Op::LOOP (
247                    oc,
248                    self.extract(cv, op_sibling(o as *const unop)),
249                )
250            },
251            OPclass::OPclass_COP => {
252                // let op = unsafe {(o as *const cop).as_ref()}.unwrap();
253                Op::COP (
254                    oc,
255                    self.extract(cv, op_sibling(o as *const unop)),
256                )
257            },
258            // XXX
259            OPclass::OPclass_METHOP => {
260                if (unsafe {*o}.op_flags & OPf_KIDS as u8) != 0 {
261                    Op::METHOP (oc, Name::Dynamic)
262                        
263                } else {
264                    let sv = op_sv_or(o, |op| PAD_BASE_SV(CvPADLIST(cv), op.op_targ));
265                    Op::METHOP(oc, Name::Const(sv_extract(sv)))
266                }
267            },
268            #[cfg(perlapi_ver26)]
269            OPclass::OPclass_UNOP_AUX => {
270                let op = unsafe {(o as *const unop_aux).as_ref()}.unwrap();
271                Op::UNOP_AUX (
272                    oc,
273                    self.extract(cv, op.op_first),
274                    self.extract(cv, op_sibling(o as *const unop)),
275                )
276            }
277        };
278        
279        self.ops.alloc(eo)
280    }
281}