| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#ifndef __XS_PARSE_SUBLIKE_H__ |
|
2
|
|
|
|
|
|
|
#define __XS_PARSE_SUBLIKE_H__ |
|
3
|
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
#define XSPARSESUBLIKE_ABI_VERSION 8 |
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
struct XSParseSublikeContext { |
|
7
|
|
|
|
|
|
|
SV *name; /* may be NULL for anon subs */ |
|
8
|
|
|
|
|
|
|
/* STAGE pre_subparse */ |
|
9
|
|
|
|
|
|
|
OP *attrs; /* may be NULL */ |
|
10
|
|
|
|
|
|
|
/* STAGE post_blockstart */ |
|
11
|
|
|
|
|
|
|
OP *body; |
|
12
|
|
|
|
|
|
|
/* STAGE pre_blockend */ |
|
13
|
|
|
|
|
|
|
CV *cv; |
|
14
|
|
|
|
|
|
|
/* STAGE post_newcv */ |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
U32 actions; |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
/* Unused by XS::Parse::Sublike itself but can be handy for modules to store |
|
19
|
|
|
|
|
|
|
* data in between stages */ |
|
20
|
|
|
|
|
|
|
HV *moddata; |
|
21
|
|
|
|
|
|
|
}; |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
enum { |
|
24
|
|
|
|
|
|
|
XS_PARSE_SUBLIKE_FLAG_FILTERATTRS = 1<<0, /* API v4 flag, no longer used */ |
|
25
|
|
|
|
|
|
|
XS_PARSE_SUBLIKE_FLAG_BODY_OPTIONAL = 1<<1, |
|
26
|
|
|
|
|
|
|
XS_PARSE_SUBLIKE_FLAG_PREFIX = 1<<2, |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
XS_PARSE_SUBLIKE_FLAG_SIGNATURE_NAMED_PARAMS = 1<<3, |
|
29
|
|
|
|
|
|
|
XS_PARSE_SUBLIKE_FLAG_SIGNATURE_PARAM_ATTRIBUTES = 1<<4, |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
XS_PARSE_SUBLIKE_FLAG_ALLOW_PKGNAME = 1<<5, |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
XS_PARSE_SUBLIKE_FLAG_SIGNATURE_REFALIAS = 1<<6, |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
/* Back-compat flags we hope to remove in the next ABI version */ |
|
36
|
|
|
|
|
|
|
XS_PARSE_SUBLIKE_COMPAT_FLAG_DYNAMIC_ACTIONS = 1<<15, |
|
37
|
|
|
|
|
|
|
}; |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
enum { |
|
40
|
|
|
|
|
|
|
XS_PARSE_SUBLIKE_PART_NAME = 1<<0, |
|
41
|
|
|
|
|
|
|
XS_PARSE_SUBLIKE_PART_ATTRS = 1<<1, |
|
42
|
|
|
|
|
|
|
XS_PARSE_SUBLIKE_PART_SIGNATURE = 1<<2, |
|
43
|
|
|
|
|
|
|
XS_PARSE_SUBLIKE_PART_BODY = 1<<3, |
|
44
|
|
|
|
|
|
|
}; |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
enum { |
|
47
|
|
|
|
|
|
|
XS_PARSE_SUBLIKE_ACTION_CVf_ANON = (1<<0), /* should start_subparse() take CVf_ANON ? */ |
|
48
|
|
|
|
|
|
|
XS_PARSE_SUBLIKE_ACTION_SET_CVNAME = (1<<1), /* do we set a CvNAME? */ |
|
49
|
|
|
|
|
|
|
XS_PARSE_SUBLIKE_ACTION_INSTALL_SYMBOL = (1<<2), /* do we install the new CV into the symbol table? */ |
|
50
|
|
|
|
|
|
|
XS_PARSE_SUBLIKE_ACTION_REFGEN_ANONCODE = (1<<3), /* do we emit OP_REFGEN of OP_ANONCODE, or simply OP_NULL ? */ |
|
51
|
|
|
|
|
|
|
XS_PARSE_SUBLIKE_ACTION_RET_EXPR = (1<<4), /* do we return KEYWORD_PLUGIN_EXPR, or KEYWORD_PLUGIN_STMT ? */ |
|
52
|
|
|
|
|
|
|
XS_PARSE_SUBLIKE_ACTION_INSTALL_LEXICAL = (1<<5), /* do we install the new CV into the current lexical pad? (Perl 5.18+) */ |
|
53
|
|
|
|
|
|
|
}; |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
struct XSParseSublikeHooks { |
|
56
|
|
|
|
|
|
|
U32 ver; /* caller must initialise to XSPARSESUBLIKE_ABI_VERSION */ |
|
57
|
|
|
|
|
|
|
U16 flags; |
|
58
|
|
|
|
|
|
|
U8 require_parts; |
|
59
|
|
|
|
|
|
|
U8 skip_parts; |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
/* These two hooks are ANDed together; both must pass, if present */ |
|
62
|
|
|
|
|
|
|
const char *permit_hintkey; |
|
63
|
|
|
|
|
|
|
bool (*permit)(pTHX_ void *hookdata); |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
void (*pre_subparse) (pTHX_ struct XSParseSublikeContext *ctx, void *hookdata); |
|
66
|
|
|
|
|
|
|
bool (*filter_attr) (pTHX_ struct XSParseSublikeContext *ctx, SV *attr, SV *val, void *hookdata); |
|
67
|
|
|
|
|
|
|
void (*post_blockstart)(pTHX_ struct XSParseSublikeContext *ctx, void *hookdata); |
|
68
|
|
|
|
|
|
|
void (*pre_blockend) (pTHX_ struct XSParseSublikeContext *ctx, void *hookdata); |
|
69
|
|
|
|
|
|
|
void (*post_newcv) (pTHX_ struct XSParseSublikeContext *ctx, void *hookdata); |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
/* if ver >= 7: */ |
|
72
|
|
|
|
|
|
|
void (*start_signature) (pTHX_ struct XSParseSublikeContext *ctx, void *hookdata); |
|
73
|
|
|
|
|
|
|
void (*finish_signature)(pTHX_ struct XSParseSublikeContext *ctx, void *hookdata); |
|
74
|
|
|
|
|
|
|
}; |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
static int (*parse_xs_parse_sublike_func)(pTHX_ const struct XSParseSublikeHooks *hooks, void *hookdata, OP **op_ptr); |
|
77
|
|
|
|
|
|
|
#define xs_parse_sublike(hooks, hookdata, op_ptr) S_xs_parse_sublike(aTHX_ hooks, hookdata, op_ptr) |
|
78
|
|
|
|
|
|
|
static int S_xs_parse_sublike(pTHX_ const struct XSParseSublikeHooks *hooks, void *hookdata, OP **op_ptr) |
|
79
|
|
|
|
|
|
|
{ |
|
80
|
|
|
|
|
|
|
if(!parse_xs_parse_sublike_func) |
|
81
|
|
|
|
|
|
|
croak("Must call boot_xs_parse_sublike() first"); |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
return (*parse_xs_parse_sublike_func)(aTHX_ hooks, hookdata, op_ptr); |
|
84
|
|
|
|
|
|
|
} |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
static void (*register_xs_parse_sublike_func)(pTHX_ const char *kw, const struct XSParseSublikeHooks *hooks, void *hookdata); |
|
87
|
|
|
|
|
|
|
#define register_xs_parse_sublike(kw, hooks, hookdata) S_register_xs_parse_sublike(aTHX_ kw, hooks, hookdata) |
|
88
|
48
|
|
|
|
|
|
static void S_register_xs_parse_sublike(pTHX_ const char *kw, const struct XSParseSublikeHooks *hooks, void *hookdata) |
|
89
|
|
|
|
|
|
|
{ |
|
90
|
48
|
50
|
|
|
|
|
if(!register_xs_parse_sublike_func) |
|
91
|
0
|
|
|
|
|
|
croak("Must call boot_xs_parse_sublike() first"); |
|
92
|
|
|
|
|
|
|
|
|
93
|
48
|
|
|
|
|
|
return (*register_xs_parse_sublike_func)(aTHX_ kw, hooks, hookdata); |
|
94
|
|
|
|
|
|
|
} |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
static int (*parseany_xs_parse_sublike_func)(pTHX_ const struct XSParseSublikeHooks *hooks, void *hookdata, OP **op_ptr); |
|
97
|
|
|
|
|
|
|
#define xs_parse_sublike_any(hooks, hookdata, op_ptr) S_xs_parse_sublike_any(aTHX_ hooks, hookdata, op_ptr) |
|
98
|
|
|
|
|
|
|
static int S_xs_parse_sublike_any(pTHX_ const struct XSParseSublikeHooks *hooks, void *hookdata, OP **op_ptr) |
|
99
|
|
|
|
|
|
|
{ |
|
100
|
|
|
|
|
|
|
if(!parseany_xs_parse_sublike_func) |
|
101
|
|
|
|
|
|
|
croak("Must call boot_xs_parse_sublike() first"); |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
return (*parseany_xs_parse_sublike_func)(aTHX_ hooks, hookdata, op_ptr); |
|
104
|
|
|
|
|
|
|
} |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
/* arguments to the signature_add_param function */ |
|
107
|
|
|
|
|
|
|
struct XPSSignatureParamDetails { |
|
108
|
|
|
|
|
|
|
U32 ver; /* caller must initialise to XSPARSESUBLIKE_ABI_VERSION */ |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
/* TODO: Right now this is entirely ABI-unstable and prone to change between versions |
|
111
|
|
|
|
|
|
|
* For now this can only add mandatory positional scalar, or final slurpy |
|
112
|
|
|
|
|
|
|
* params whose pad variable has already been declared, and that have no |
|
113
|
|
|
|
|
|
|
* attributes attached. |
|
114
|
|
|
|
|
|
|
*/ |
|
115
|
|
|
|
|
|
|
char sigil; |
|
116
|
|
|
|
|
|
|
PADOFFSET padix; |
|
117
|
|
|
|
|
|
|
}; |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
static void (*signature_add_param_func)(pTHX_ struct XSParseSublikeContext *ctx, struct XPSSignatureParamDetails *details); |
|
120
|
|
|
|
|
|
|
#define xps_signature_add_param(ctx, details) S_xps_signature_add_param(aTHX_ ctx, details) |
|
121
|
|
|
|
|
|
|
static void S_xps_signature_add_param(pTHX_ struct XSParseSublikeContext *ctx, struct XPSSignatureParamDetails *details) |
|
122
|
|
|
|
|
|
|
{ |
|
123
|
|
|
|
|
|
|
if(!signature_add_param_func) |
|
124
|
|
|
|
|
|
|
croak("Must call boot_xs_parse_sublike() first"); |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
(*signature_add_param_func)(aTHX_ ctx, details); |
|
127
|
|
|
|
|
|
|
} |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
/* Easier to define one query function that takes a `q` parameter, that |
|
130
|
|
|
|
|
|
|
* indicates which question we are asking. This saves us having to export |
|
131
|
|
|
|
|
|
|
* lots of functions. This is internal implementation detail, not exposed |
|
132
|
|
|
|
|
|
|
* API. |
|
133
|
|
|
|
|
|
|
*/ |
|
134
|
|
|
|
|
|
|
static IV (*signature_query_func)(pTHX_ struct XSParseSublikeContext *ctx, int q); |
|
135
|
|
|
|
|
|
|
#define xps_signature_query_params(ctx) S_xps_signature_query(aTHX_ ctx, 0) |
|
136
|
|
|
|
|
|
|
#define xps_signature_query_optparams(ctx) S_xps_signature_query(aTHX_ ctx, 1) |
|
137
|
|
|
|
|
|
|
#define xps_signature_query_slurpy(ctx) ((char)S_xps_signature_query(aTHX_ ctx, 2)) |
|
138
|
|
|
|
|
|
|
static IV S_xps_signature_query(pTHX_ struct XSParseSublikeContext *ctx, int q) |
|
139
|
|
|
|
|
|
|
{ |
|
140
|
|
|
|
|
|
|
if(!signature_query_func) |
|
141
|
|
|
|
|
|
|
croak("Must call boot_xs_parse_sublike() first"); |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
return (*signature_query_func)(aTHX_ ctx, q); |
|
144
|
|
|
|
|
|
|
} |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
/* Experimental support for subroutine parameter attributes. |
|
147
|
|
|
|
|
|
|
* Only supported on Perl v5.26 or later |
|
148
|
|
|
|
|
|
|
*/ |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
struct XPSSignatureParamContext { |
|
151
|
|
|
|
|
|
|
bool is_named; |
|
152
|
|
|
|
|
|
|
PADOFFSET padix; |
|
153
|
|
|
|
|
|
|
OP *varop; |
|
154
|
|
|
|
|
|
|
/* apply phase runs here */ |
|
155
|
|
|
|
|
|
|
OP *defop; |
|
156
|
|
|
|
|
|
|
OP *op; |
|
157
|
|
|
|
|
|
|
/* post_defop phase runs here */ |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
/* TODO: in next ABI-breaking change, move this to the top */ |
|
160
|
|
|
|
|
|
|
char sigil; |
|
161
|
|
|
|
|
|
|
const char *namepv; |
|
162
|
|
|
|
|
|
|
STRLEN namelen; |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
bool is_refalias; |
|
165
|
|
|
|
|
|
|
}; |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
struct XPSSignatureAttributeFuncs { |
|
168
|
|
|
|
|
|
|
U32 ver; /* caller must initialise to XSPARSESUBLIKE_ABI_VERSION */ |
|
169
|
|
|
|
|
|
|
U32 flags; |
|
170
|
|
|
|
|
|
|
const char *permit_hintkey; |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
void (*apply)(pTHX_ struct XPSSignatureParamContext *ctx, SV *attrvalue, void **attrdata_ptr, void *funcdata); |
|
173
|
|
|
|
|
|
|
void (*post_defop)(pTHX_ struct XPSSignatureParamContext *ctx, void *attrdata, void *funcdata); |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
void (*free)(pTHX_ void *attrdata, void *funcdata); |
|
176
|
|
|
|
|
|
|
}; |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
static void (*register_xps_signature_attribute_func)(pTHX_ const char *name, const struct XPSSignatureAttributeFuncs *funcs, void *funcdata); |
|
179
|
|
|
|
|
|
|
#define register_xps_signature_attribute(name, funcs, funcdata) S_register_xps_signature_attribute(aTHX_ name, funcs, funcdata) |
|
180
|
|
|
|
|
|
|
static void S_register_xps_signature_attribute(pTHX_ const char *name, const struct XPSSignatureAttributeFuncs *funcs, void *funcdata) |
|
181
|
|
|
|
|
|
|
{ |
|
182
|
|
|
|
|
|
|
if(!register_xps_signature_attribute_func) |
|
183
|
|
|
|
|
|
|
croak("Must call boot_xs_parse_sublike() first"); |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
(*register_xps_signature_attribute_func)(aTHX_ name, funcs, funcdata); |
|
186
|
|
|
|
|
|
|
} |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
#define boot_xs_parse_sublike(ver) S_boot_xs_parse_sublike(aTHX_ ver) |
|
190
|
48
|
|
|
|
|
|
static void S_boot_xs_parse_sublike(pTHX_ double ver) { |
|
191
|
|
|
|
|
|
|
SV **svp; |
|
192
|
48
|
50
|
|
|
|
|
SV *versv = ver ? newSVnv(ver) : NULL; |
|
193
|
|
|
|
|
|
|
|
|
194
|
48
|
|
|
|
|
|
load_module(PERL_LOADMOD_NOIMPORT, newSVpvs("XS::Parse::Sublike"), versv, NULL); |
|
195
|
|
|
|
|
|
|
|
|
196
|
48
|
|
|
|
|
|
svp = hv_fetchs(PL_modglobal, "XS::Parse::Sublike/ABIVERSION_MIN", 0); |
|
197
|
48
|
50
|
|
|
|
|
if(!svp) |
|
198
|
0
|
|
|
|
|
|
croak("XS::Parse::Sublike ABI minimum version missing"); |
|
199
|
48
|
|
|
|
|
|
int abi_ver = SvIV(*svp); |
|
200
|
48
|
50
|
|
|
|
|
if(abi_ver > XSPARSESUBLIKE_ABI_VERSION) |
|
201
|
0
|
|
|
|
|
|
croak("XS::Parse::Sublike ABI version mismatch - library supports >= %d, compiled for %d", |
|
202
|
|
|
|
|
|
|
abi_ver, XSPARSESUBLIKE_ABI_VERSION); |
|
203
|
|
|
|
|
|
|
|
|
204
|
48
|
|
|
|
|
|
svp = hv_fetchs(PL_modglobal, "XS::Parse::Sublike/ABIVERSION_MAX", 0); |
|
205
|
48
|
|
|
|
|
|
abi_ver = SvIV(*svp); |
|
206
|
48
|
50
|
|
|
|
|
if(abi_ver < XSPARSESUBLIKE_ABI_VERSION) |
|
207
|
0
|
|
|
|
|
|
croak("XS::Parse::Sublike ABI version mismatch - library supports <= %d, compiled for %d", |
|
208
|
|
|
|
|
|
|
abi_ver, XSPARSESUBLIKE_ABI_VERSION); |
|
209
|
|
|
|
|
|
|
|
|
210
|
48
|
|
|
|
|
|
parse_xs_parse_sublike_func = INT2PTR(int (*)(pTHX_ const struct XSParseSublikeHooks *, void *, OP**), |
|
211
|
|
|
|
|
|
|
SvUV(*hv_fetchs(PL_modglobal, "XS::Parse::Sublike/parse()@6", 0))); |
|
212
|
|
|
|
|
|
|
|
|
213
|
48
|
|
|
|
|
|
register_xs_parse_sublike_func = INT2PTR(void (*)(pTHX_ const char *, const struct XSParseSublikeHooks *, void *), |
|
214
|
|
|
|
|
|
|
SvUV(*hv_fetchs(PL_modglobal, "XS::Parse::Sublike/register()@6", 0))); |
|
215
|
|
|
|
|
|
|
|
|
216
|
48
|
|
|
|
|
|
parseany_xs_parse_sublike_func = INT2PTR(int (*)(pTHX_ const struct XSParseSublikeHooks *, void *, OP**), |
|
217
|
|
|
|
|
|
|
SvUV(*hv_fetchs(PL_modglobal, "XS::Parse::Sublike/parseany()@6", 0))); |
|
218
|
|
|
|
|
|
|
|
|
219
|
48
|
|
|
|
|
|
register_xps_signature_attribute_func = INT2PTR(void (*)(pTHX_ const char *, const struct XPSSignatureAttributeFuncs *, void *), |
|
220
|
|
|
|
|
|
|
SvUV(*hv_fetchs(PL_modglobal, "XS::Parse::Sublike/register_sigattr()@5", 0))); |
|
221
|
|
|
|
|
|
|
|
|
222
|
48
|
|
|
|
|
|
signature_add_param_func = INT2PTR(void (*)(pTHX_ struct XSParseSublikeContext *ctx, struct XPSSignatureParamDetails *details), |
|
223
|
|
|
|
|
|
|
SvUV(*hv_fetchs(PL_modglobal, "XS::Parse::Sublike/signature_add_param()@7", 0))); |
|
224
|
|
|
|
|
|
|
|
|
225
|
48
|
|
|
|
|
|
signature_query_func = INT2PTR(IV (*)(pTHX_ struct XSParseSublikeContext *ctx, int q), |
|
226
|
|
|
|
|
|
|
SvUV(*hv_fetchs(PL_modglobal, "XS::Parse::Sublike/signature_query()@8", 0))); |
|
227
|
48
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
#endif |