line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#pragma once |
2
|
|
|
|
|
|
|
#include "basic.h" |
3
|
|
|
|
|
|
|
#include <string> |
4
|
|
|
|
|
|
|
#include <panda/memory.h> |
5
|
|
|
|
|
|
|
#include <panda/traits.h> |
6
|
|
|
|
|
|
|
#include <panda/string.h> |
7
|
|
|
|
|
|
|
#include <panda/string_view.h> |
8
|
|
|
|
|
|
|
#include <panda/exception.h> |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
namespace xs { |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
struct Sv; struct Scalar; struct Simple; struct Ref; struct Array; struct Hash; struct List; struct Sub; struct Stash; struct Glob; struct Object; struct Io; |
13
|
|
|
|
|
|
|
using xs::my_perl; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
template <class T, class R = T> using enable_if_sv_t = std::enable_if_t<panda::is_one_of<T,Sv,Scalar,Ref,Simple,Object,Sub,Hash,Array,Glob,Stash,List,Io>::value, R>; |
16
|
|
|
|
|
|
|
template <class T, class R = T> using enable_if_rawsv_t = std::enable_if_t<panda::is_one_of<T,SV,AV,HV,CV,GV,IO>::value, R>; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
struct Sv { |
19
|
|
|
|
|
|
|
static const bool INCREMENT = true; |
20
|
|
|
|
|
|
|
static const bool NONE = false; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
static const Sv undef; |
23
|
|
|
|
|
|
|
static const Sv yes; |
24
|
|
|
|
|
|
|
static const Sv no; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
typedef int (*on_svdup_t) (pTHX_ MAGIC* mg, CLONE_PARAMS* param); |
27
|
|
|
|
|
|
|
using payload_marker_t = MGVTBL; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
struct Payload { |
30
|
|
|
|
|
|
|
void* ptr; |
31
|
|
|
|
|
|
|
SV* obj; |
32
|
|
|
|
|
|
|
}; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
template <class T> struct PayloadMarker { |
35
|
14322
|
100
|
|
|
|
|
PANDA_GLOBAL_MEMBER_AS_PTR(PayloadMarker, payload_marker_t, get, payload_marker_t()); |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
36
|
|
|
|
|
|
|
}; |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
static payload_marker_t* default_marker(); |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
template <class T, typename = enable_if_rawsv_t<T>> |
41
|
14322
|
|
|
|
|
|
static Sv noinc (T* val) { return Sv((SV*)val, NONE); } |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
static Sv create () { return Sv(newSV(0), NONE); } |
44
|
|
|
|
|
|
|
|
45
|
21740
|
|
|
|
|
|
Sv (std::nullptr_t = nullptr) : sv(nullptr) {} |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
template <class T, typename = enable_if_rawsv_t<T>> |
48
|
23678
|
50
|
|
|
|
|
Sv (T* sv, bool policy = INCREMENT) : sv((SV*)sv) { if (policy == INCREMENT) SvREFCNT_inc_simple_void(sv); } |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
49
|
|
|
|
|
|
|
|
50
|
0
|
|
|
|
|
|
Sv (const Sv& oth) : Sv(oth.sv) {} |
51
|
7162
|
|
|
|
|
|
Sv (Sv&& oth) : sv(oth.sv) { oth.sv = nullptr; } |
52
|
|
|
|
|
|
|
|
53
|
0
|
|
|
|
|
|
~Sv () { SvREFCNT_dec(sv); } |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
template <class T, typename = enable_if_rawsv_t<T>> |
56
|
2614
|
|
|
|
|
|
Sv& operator= (T* val) { |
57
|
2614
|
50
|
|
|
|
|
SvREFCNT_inc_simple_void(val); |
|
|
50
|
|
|
|
|
|
58
|
2614
|
|
|
|
|
|
auto old = sv; |
59
|
2614
|
|
|
|
|
|
sv = (SV*)val; |
60
|
2614
|
50
|
|
|
|
|
SvREFCNT_dec(old); |
|
|
50
|
|
|
|
|
|
61
|
2614
|
|
|
|
|
|
return *this; |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
0
|
|
|
|
|
|
Sv& operator= (const Sv& oth) { return operator=(oth.sv); } |
65
|
|
|
|
|
|
|
|
66
|
7161
|
|
|
|
|
|
Sv& operator= (Sv&& oth) { |
67
|
7161
|
|
|
|
|
|
std::swap(sv, oth.sv); |
68
|
7161
|
|
|
|
|
|
return *this; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
// safe getters (slower) |
72
|
42436
|
|
|
|
|
|
operator SV* () const { return sv; } |
73
|
|
|
|
|
|
|
operator AV* () const { return is_array() ? (AV*)sv : nullptr; } |
74
|
|
|
|
|
|
|
operator HV* () const { return is_hash() ? (HV*)sv : nullptr; } |
75
|
|
|
|
|
|
|
operator CV* () const { return is_sub() ? (CV*)sv : nullptr; } |
76
|
|
|
|
|
|
|
operator GV* () const { return is_glob() ? (GV*)sv : nullptr; } |
77
|
|
|
|
|
|
|
operator IO* () const { return is_io() ? (IO*)sv : nullptr; } |
78
|
|
|
|
|
|
|
operator void* () const { return sv; } // resolves ambiguity for passing to perl-macros-api |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
// unsafe getters (faster) |
81
|
8
|
|
|
|
|
|
template <typename T = SV> enable_if_rawsv_t<T>* get () const { return (T*)sv; } |
82
|
|
|
|
|
|
|
|
83
|
14322
|
|
|
|
|
|
explicit operator bool () const { return sv; } |
84
|
13834
|
|
|
|
|
|
explicit operator bool () { return sv; } |
85
|
|
|
|
|
|
|
|
86
|
23818
|
|
|
|
|
|
SV* operator-> () const { return sv; } |
87
|
|
|
|
|
|
|
|
88
|
9324
|
50
|
|
|
|
|
bool defined () const { return sv && SvOK(sv); } |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
89
|
|
|
|
|
|
|
bool is_true () const { return SvTRUE(sv); } |
90
|
5004
|
|
|
|
|
|
svtype type () const { return SvTYPE(sv); } |
91
|
|
|
|
|
|
|
bool readonly () const { return SvREADONLY(sv); } |
92
|
|
|
|
|
|
|
U32 use_count () const { return sv ? SvREFCNT(sv) : 0; } |
93
|
|
|
|
|
|
|
bool is_scalar () const { return sv && is_scalar_unsafe(); } |
94
|
|
|
|
|
|
|
bool is_ref () const { return sv && SvROK(sv); } |
95
|
|
|
|
|
|
|
bool is_simple () const { return sv && SvTYPE(sv) <= SVt_PVMG && !SvROK(sv); } |
96
|
|
|
|
|
|
|
bool is_string () const { return sv && SvPOK(sv); } |
97
|
9300
|
50
|
|
|
|
|
bool is_like_number () const { return sv && looks_like_number(sv); } |
|
|
100
|
|
|
|
|
|
98
|
|
|
|
|
|
|
bool is_array () const { return sv && type() == SVt_PVAV; } |
99
|
|
|
|
|
|
|
bool is_array_ref () const { return is_ref_of_type(SVt_PVAV); } |
100
|
|
|
|
|
|
|
bool is_hash () const { return sv && type() == SVt_PVHV; } |
101
|
|
|
|
|
|
|
bool is_hash_ref () const { return is_ref_of_type(SVt_PVHV); } |
102
|
|
|
|
|
|
|
bool is_sub () const { return sv && type() == SVt_PVCV; } |
103
|
|
|
|
|
|
|
bool is_sub_ref () const { return is_ref_of_type(SVt_PVCV); } |
104
|
|
|
|
|
|
|
bool is_glob () const { return sv && type() == SVt_PVGV; } |
105
|
9300
|
50
|
|
|
|
|
bool is_object () const { return sv && SvOBJECT(sv); } |
|
|
50
|
|
|
|
|
|
106
|
|
|
|
|
|
|
bool is_object_ref () const { return is_ref() && SvOBJECT(SvRV(sv)); } |
107
|
|
|
|
|
|
|
bool is_stash () const { return is_hash() && HvNAME(sv); } |
108
|
|
|
|
|
|
|
bool is_io () const { return sv && type() == SVt_PVIO; } |
109
|
|
|
|
|
|
|
bool is_io_ref () const { return is_ref_of_type(SVt_PVIO); } |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
bool is_ref_of_type (svtype type) const { return sv && SvROK(sv) && SvTYPE(SvRV(sv)) == type; } |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
void readonly (bool val) { |
114
|
|
|
|
|
|
|
if (val) SvREADONLY_on(sv); |
115
|
|
|
|
|
|
|
else SvREADONLY_off(sv); |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
void upgrade (svtype type) { |
119
|
|
|
|
|
|
|
if (SvREADONLY(sv)) throw "cannot upgrade readonly sv"; |
120
|
|
|
|
|
|
|
if (type > SVt_PVMG && SvOK(sv)) throw "only undefined scalars can be upgraded to something more than SVt_PVMG"; |
121
|
|
|
|
|
|
|
SvUPGRADE(sv, type); |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
void dump () const { sv_dump(sv); } |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
MAGIC* payload_attach (Payload p, const payload_marker_t* marker) { return payload_attach(p.ptr, p.obj, marker); } |
127
|
|
|
|
|
|
|
MAGIC* payload_attach (void* ptr, SV* obj, const payload_marker_t* marker); |
128
|
|
|
|
|
|
|
MAGIC* payload_attach (void* ptr, const Sv& obj, const payload_marker_t* marker) { return payload_attach(ptr, (SV*)obj, marker); } |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
MAGIC* payload_attach (const Sv& obj, const payload_marker_t* marker) { return payload_attach(NULL, obj, marker); } |
131
|
|
|
|
|
|
|
MAGIC* payload_attach (SV* obj, const payload_marker_t* marker) { return payload_attach(NULL, obj, marker); } |
132
|
|
|
|
|
|
|
MAGIC* payload_attach (void* ptr, const payload_marker_t* marker) { return payload_attach(ptr, NULL, marker); } |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
bool payload_exists (const payload_marker_t* marker) const { |
135
|
|
|
|
|
|
|
if (type() < SVt_PVMG) return false; |
136
|
|
|
|
|
|
|
for (MAGIC* mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) if (mg->mg_virtual == marker) return true; |
137
|
|
|
|
|
|
|
return false; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
Payload payload (const payload_marker_t* marker) const { |
141
|
|
|
|
|
|
|
if (type() < SVt_PVMG) return Payload(); |
142
|
|
|
|
|
|
|
for (MAGIC* mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) if (mg->mg_virtual == marker) return Payload { mg->mg_ptr, mg->mg_obj }; |
143
|
|
|
|
|
|
|
return Payload(); |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
int payload_detach (payload_marker_t* marker) { |
147
|
|
|
|
|
|
|
if (type() < SVt_PVMG) return 0; |
148
|
|
|
|
|
|
|
return sv_unmagicext(sv, PERL_MAGIC_ext, marker); |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
|
151
|
0
|
|
|
|
|
|
void reset () { |
152
|
0
|
|
|
|
|
|
SvREFCNT_dec(sv); |
153
|
0
|
|
|
|
|
|
sv = nullptr; |
154
|
0
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
7171
|
|
|
|
|
|
SV* detach () { |
157
|
7171
|
|
|
|
|
|
auto tmp = sv; |
158
|
7171
|
|
|
|
|
|
sv = nullptr; |
159
|
7171
|
|
|
|
|
|
return tmp; |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
SV* detach_mortal () { |
163
|
|
|
|
|
|
|
return sv_2mortal(detach()); |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
static void __at_perl_destroy (); |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
protected: |
169
|
|
|
|
|
|
|
friend void swap (Sv&, Sv&); |
170
|
|
|
|
|
|
|
|
171
|
0
|
0
|
|
|
|
|
inline bool is_undef() const { return (SvTYPE(sv) <= SVt_PVMG && !SvOK(sv)); } |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
172
|
|
|
|
|
|
|
inline bool is_scalar_unsafe() const { return (SvTYPE(sv) <= SVt_PVMG || SvTYPE(sv) == SVt_PVGV || SvTYPE(sv) == SVt_PVLV); } |
173
|
|
|
|
|
|
|
SV* sv; |
174
|
|
|
|
|
|
|
}; |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
inline bool operator== (const Sv& lh, const Sv& rh) { return lh.get<SV>() == rh.get<SV>(); } |
177
|
|
|
|
|
|
|
inline bool operator!= (const Sv& lh, const Sv& rh) { return !(lh == rh); } |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
template <class T, typename = enable_if_rawsv_t<T>> inline bool operator== (const Sv& lh, T* rh) { return lh.get() == (SV*)rh; } |
180
|
|
|
|
|
|
|
template <class T, typename = enable_if_rawsv_t<T>> inline bool operator!= (const Sv& lh, T* rh) { return lh.get() != (SV*)rh; } |
181
|
|
|
|
|
|
|
template <class T, typename = enable_if_rawsv_t<T>> inline bool operator== (T* lh, const Sv& rh) { return rh.get() == (SV*)lh; } |
182
|
|
|
|
|
|
|
template <class T, typename = enable_if_rawsv_t<T>> inline bool operator!= (T* lh, const Sv& rh) { return rh.get() != (SV*)lh; } |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
inline void swap (Sv& lh, Sv& rh) { std::swap(lh.sv, rh.sv); } |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
std::ostream& operator<< (std::ostream& os, const Sv& sv); |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
struct PerlRuntimeException : std::exception { |
190
|
|
|
|
|
|
|
Sv sv; |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
PerlRuntimeException(const Sv& sv) : sv(sv) {assert(sv);} |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
virtual const char* what() const noexcept override { |
195
|
|
|
|
|
|
|
return SvPV_nolen(sv); |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
}; |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
Sv eval (const panda::string& code); |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
} |