| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#pragma once |
|
2
|
|
|
|
|
|
|
#include |
|
3
|
|
|
|
|
|
|
#include |
|
4
|
|
|
|
|
|
|
#include |
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
namespace xs { |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
using xs::my_perl; |
|
9
|
|
|
|
|
|
|
|
|
10
|
0
|
|
|
|
|
|
struct Sub : Sv { |
|
11
|
|
|
|
|
|
|
enum class Want { Void = G_VOID, Scalar = G_SCALAR, Array = G_ARRAY }; |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
static Sub create (panda::string_view code); // create sub by evaling perl code |
|
14
|
|
|
|
|
|
|
static Sub create (XSUBADDR_t); // create anon XSub |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
static Sub noinc (SV* val) { return Sub(val, NONE); } |
|
17
|
|
|
|
|
|
|
static Sub noinc (CV* val) { return Sub(val, NONE); } |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
static Sub clone_anon_xsub (const Sub&); |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
Sub (std::nullptr_t = nullptr) {} |
|
22
|
|
|
|
|
|
|
Sub (SV* sv, bool policy = INCREMENT) : Sv(sv, policy) { _validate(); } |
|
23
|
26
|
|
|
|
|
|
Sub (CV* sv, bool policy = INCREMENT) : Sv(sv, policy) {} |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
explicit |
|
26
|
|
|
|
|
|
|
Sub (panda::string_view subname, I32 flags = 0) { |
|
27
|
|
|
|
|
|
|
*this = get_cvn_flags(subname.data(), subname.length(), flags); |
|
28
|
|
|
|
|
|
|
} |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
Sub (const Sub& oth) : Sv(oth) {} |
|
31
|
|
|
|
|
|
|
Sub (Sub&& oth) : Sv(std::move(oth)) {} |
|
32
|
|
|
|
|
|
|
Sub (const Sv& oth) : Sv(oth) { _validate(); } |
|
33
|
|
|
|
|
|
|
Sub (Sv&& oth) : Sv(std::move(oth)) { _validate(); } |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
Sub (const Simple&) = delete; |
|
36
|
|
|
|
|
|
|
Sub (const Array&) = delete; |
|
37
|
|
|
|
|
|
|
Sub (const Hash&) = delete; |
|
38
|
|
|
|
|
|
|
Sub (const Glob&) = delete; |
|
39
|
|
|
|
|
|
|
Sub (const Io&) = delete; |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
Sub& operator= (SV* val) { Sv::operator=(val); _validate(); return *this; } |
|
42
|
|
|
|
|
|
|
Sub& operator= (CV* val) { Sv::operator=(val); return *this; } |
|
43
|
|
|
|
|
|
|
Sub& operator= (const Sub& oth) { Sv::operator=(oth); return *this; } |
|
44
|
|
|
|
|
|
|
Sub& operator= (Sub&& oth) { Sv::operator=(std::move(oth)); return *this; } |
|
45
|
|
|
|
|
|
|
Sub& operator= (const Sv& oth) { return operator=(oth.get()); } |
|
46
|
|
|
|
|
|
|
Sub& operator= (Sv&& oth) { Sv::operator=(std::move(oth)); _validate(); return *this; } |
|
47
|
|
|
|
|
|
|
Sub& operator= (const Simple&) = delete; |
|
48
|
|
|
|
|
|
|
Sub& operator= (const Array&) = delete; |
|
49
|
|
|
|
|
|
|
Sub& operator= (const Hash&) = delete; |
|
50
|
|
|
|
|
|
|
Sub& operator= (const Glob&) = delete; |
|
51
|
|
|
|
|
|
|
Sub& operator= (const Io&) = delete; |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
void set (SV* val) { Sv::operator=(val); } |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
operator AV* () const = delete; |
|
56
|
|
|
|
|
|
|
operator HV* () const = delete; |
|
57
|
|
|
|
|
|
|
operator CV* () const { return (CV*)sv; } |
|
58
|
|
|
|
|
|
|
operator GV* () const = delete; |
|
59
|
|
|
|
|
|
|
operator IO* () const = delete; |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
CV* operator-> () const { return (CV*)sv; } |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
template panda::enable_if_one_of_t* get () const { return (T*)sv; } |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
Stash stash () const; |
|
66
|
|
|
|
|
|
|
Glob glob () const; |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
panda::string_view name () const { |
|
69
|
|
|
|
|
|
|
GV* gv = CvGV((CV*)sv); |
|
70
|
|
|
|
|
|
|
return panda::string_view(GvNAME(gv), GvNAMELEN(gv)); |
|
71
|
|
|
|
|
|
|
} |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
bool named () const { return CvNAMED((CV*)sv); } |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
Sub SUPER () const { |
|
76
|
|
|
|
|
|
|
GV* mygv = CvGV((CV*)sv); |
|
77
|
|
|
|
|
|
|
GV* supergv = gv_fetchmeth_pvn(GvSTASH(mygv), GvNAME(mygv), GvNAMELEN(mygv), 0, GV_SUPER); |
|
78
|
|
|
|
|
|
|
return Sub(supergv ? GvCV(supergv) : nullptr); |
|
79
|
|
|
|
|
|
|
} |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
Sub SUPER_strict () const { |
|
82
|
|
|
|
|
|
|
Sub ret = SUPER(); |
|
83
|
|
|
|
|
|
|
if (!ret) _throw_super(); |
|
84
|
|
|
|
|
|
|
return ret; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
static Want want () { return (Want)GIMME_V; } |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
static int want_count (); |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
private: |
|
92
|
|
|
|
|
|
|
struct CallArgs { |
|
93
|
|
|
|
|
|
|
SV* self; |
|
94
|
|
|
|
|
|
|
SV*const* list; |
|
95
|
|
|
|
|
|
|
const Scalar* scalars; |
|
96
|
|
|
|
|
|
|
size_t items; |
|
97
|
|
|
|
|
|
|
}; |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
template struct CallContext; |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
public: |
|
102
|
|
|
|
|
|
|
template using call_t = decltype(CallContext::call((CV*)nullptr, CallArgs())); |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
template |
|
105
|
|
|
|
|
|
|
call_t call (Args&&...va) const { |
|
106
|
|
|
|
|
|
|
auto args = _get_args(va...); |
|
107
|
|
|
|
|
|
|
return CallContext::call((CV*)sv, args); |
|
108
|
|
|
|
|
|
|
} |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
template |
|
111
|
|
|
|
|
|
|
Scalar operator() (Args&&...args) const { return call(std::forward(args)...); } |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
private: |
|
114
|
|
|
|
|
|
|
void _validate () { |
|
115
|
|
|
|
|
|
|
if (!sv) return; |
|
116
|
|
|
|
|
|
|
if (SvTYPE(sv) == SVt_PVCV) return; |
|
117
|
|
|
|
|
|
|
if (SvROK(sv)) { // reference to code? |
|
118
|
|
|
|
|
|
|
SV* val = SvRV(sv); |
|
119
|
|
|
|
|
|
|
if (SvTYPE(val) == SVt_PVCV) { |
|
120
|
|
|
|
|
|
|
Sv::operator=(val); |
|
121
|
|
|
|
|
|
|
return; |
|
122
|
|
|
|
|
|
|
} |
|
123
|
|
|
|
|
|
|
} |
|
124
|
|
|
|
|
|
|
if (is_undef()) return reset(); |
|
125
|
|
|
|
|
|
|
reset(); |
|
126
|
|
|
|
|
|
|
throw std::invalid_argument("SV is not a Sub or Sub reference"); |
|
127
|
|
|
|
|
|
|
} |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
void _throw_super () const; |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
template |
|
132
|
|
|
|
|
|
|
struct VCallArgs : CallArgs { |
|
133
|
|
|
|
|
|
|
SV* list[sizeof...(Args)]; |
|
134
|
|
|
|
|
|
|
VCallArgs (Args&&...args) : CallArgs{nullptr, list, nullptr, sizeof...(Args)}, list{std::forward(args)...} { |
|
135
|
|
|
|
|
|
|
for (auto sv : list) |
|
136
|
|
|
|
|
|
|
if (sv && SvTYPE(sv) > SVt_PVMG && SvTYPE(sv) != SVt_PVGV) |
|
137
|
|
|
|
|
|
|
throw std::invalid_argument("one of arguments for sub.call() is not a scalar value"); |
|
138
|
|
|
|
|
|
|
} |
|
139
|
|
|
|
|
|
|
}; |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
template struct type_pack {}; |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
static CallArgs _get_args (SV*const* args = nullptr, size_t items = 0) { return {nullptr, args, nullptr, items}; } |
|
144
|
|
|
|
|
|
|
static CallArgs _get_args (SV* arg0, SV*const* args, size_t items) { return { arg0, args, nullptr, items}; } |
|
145
|
|
|
|
|
|
|
static CallArgs _get_args (const Scalar* args, size_t items) { return {nullptr, nullptr, args, items}; } |
|
146
|
|
|
|
|
|
|
static CallArgs _get_args (SV* arg0, const Scalar* args, size_t items) { return { arg0, nullptr, args, items}; } |
|
147
|
|
|
|
|
|
|
static CallArgs _get_args (const std::initializer_list& l) { return {nullptr, nullptr, l.begin(), l.size()}; } |
|
148
|
|
|
|
|
|
|
static CallArgs _get_args (SV* arg0, const std::initializer_list& l) { return { arg0, nullptr, l.begin(), l.size()}; } |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
template ()))...>> |
|
151
|
|
|
|
|
|
|
static VCallArgs _get_args (Args&&...args) { return {std::forward(args)...}; } |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
static size_t _call (CV*, I32 flags, const CallArgs&, SV** ret, size_t maxret, AV** avr); |
|
154
|
|
|
|
|
|
|
}; |
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
template |
|
157
|
|
|
|
|
|
|
struct Sub::CallContext> { |
|
158
|
|
|
|
|
|
|
using type = std::tuple; |
|
159
|
|
|
|
|
|
|
static constexpr size_t N = sizeof...(Types); |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
static type call (CV* cv, const CallArgs& args) { |
|
162
|
|
|
|
|
|
|
SV* ret[N] = {nullptr}; |
|
163
|
|
|
|
|
|
|
_call(cv, G_ARRAY, args, ret, N, nullptr); |
|
164
|
|
|
|
|
|
|
return _make_tuple(ret, std::make_index_sequence()); |
|
165
|
|
|
|
|
|
|
} |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
template |
|
168
|
|
|
|
|
|
|
static T _make_tuple (SV** svs, std::integer_sequence) { |
|
169
|
|
|
|
|
|
|
return T(typename std::tuple_element::type(svs[Inds], Sv::NONE)...); |
|
170
|
|
|
|
|
|
|
} |
|
171
|
|
|
|
|
|
|
}; |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
template |
|
174
|
|
|
|
|
|
|
struct Sub::CallContext : Sub::CallContext> {}; |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
template |
|
177
|
|
|
|
|
|
|
struct Sub::CallContext, T> { |
|
178
|
|
|
|
|
|
|
static T call (CV* cv, const CallArgs& args) { |
|
179
|
|
|
|
|
|
|
SV* ret = NULL; |
|
180
|
|
|
|
|
|
|
_call(cv, G_SCALAR, args, &ret, 1, nullptr); |
|
181
|
|
|
|
|
|
|
return T(ret, Sv::NONE); |
|
182
|
|
|
|
|
|
|
} |
|
183
|
|
|
|
|
|
|
}; |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
template <> |
|
186
|
|
|
|
|
|
|
struct Sub::CallContext : Sub::CallContext {}; |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
template <> |
|
189
|
|
|
|
|
|
|
struct Sub::CallContext { |
|
190
|
|
|
|
|
|
|
static List call (CV* cv, const CallArgs& args) { |
|
191
|
|
|
|
|
|
|
AV* av = NULL; |
|
192
|
|
|
|
|
|
|
_call(cv, G_ARRAY, args, nullptr, 0, &av); |
|
193
|
|
|
|
|
|
|
return List(av, Sv::NONE); |
|
194
|
|
|
|
|
|
|
} |
|
195
|
|
|
|
|
|
|
}; |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
template <> |
|
198
|
|
|
|
|
|
|
struct Sub::CallContext { |
|
199
|
|
|
|
|
|
|
static void call (CV* cv, const CallArgs& args) { _call(cv, G_VOID, args, nullptr, 0, nullptr); } |
|
200
|
|
|
|
|
|
|
}; |
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
template |
|
203
|
|
|
|
|
|
|
struct Sub::CallContext, std::array> { |
|
204
|
|
|
|
|
|
|
using type = std::array; |
|
205
|
|
|
|
|
|
|
static type call (CV* cv, const CallArgs& args) { |
|
206
|
|
|
|
|
|
|
SV* svret[N]; |
|
207
|
|
|
|
|
|
|
auto nret = _call(cv, G_ARRAY, args, svret, N, nullptr); |
|
208
|
|
|
|
|
|
|
type ret; |
|
209
|
|
|
|
|
|
|
for (size_t i = 0; i < nret; ++i) ret[i] = T(svret[i], Sv::NONE); |
|
210
|
|
|
|
|
|
|
return ret; |
|
211
|
|
|
|
|
|
|
} |
|
212
|
|
|
|
|
|
|
}; |
|
213
|
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
template <> |
|
215
|
|
|
|
|
|
|
struct Sub::CallContext { |
|
216
|
|
|
|
|
|
|
static panda::string call (CV* cv, const CallArgs& args) { return CallContext::call(cv, args).as_string(); } |
|
217
|
|
|
|
|
|
|
}; |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
template |
|
220
|
|
|
|
|
|
|
struct Sub::CallContext, T> { |
|
221
|
|
|
|
|
|
|
static T call (CV* cv, const CallArgs& args) { return CallContext::call(cv, args); } |
|
222
|
|
|
|
|
|
|
}; |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
} |