103_scan_op_tree/eg/
op0.rs1#![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{
17 NULL,
18 OP (opcode, Option<String>, Option<String>),
19 UNOP (opcode),
20 BINOP (opcode),
21 LOGOP (opcode),
22 LISTOP (opcode),
23 PMOP (opcode),
24 SVOP (opcode, Sv),
25 PADOP (opcode, Sv),
26 PVOP (opcode),
27 LOOP (opcode),
28 COP (opcode),
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),
56 OPclass::OPclass_BINOP => Op::BINOP(oc),
57 OPclass::OPclass_LOGOP => Op::LOGOP(oc),
58 OPclass::OPclass_LISTOP => Op::LISTOP(oc),
59 OPclass::OPclass_PMOP => Op::PMOP(oc),
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),
70 OPclass::OPclass_LOOP => Op::LOOP(oc),
71 OPclass::OPclass_COP => Op::COP(oc),
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 ),
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 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}