1 #define NEED_newSVpvn_flags_GLOBAL
2 #define NEED_newSVpvn_share
3 #define NEED_newSV_type
4 #include "xslate.h"
5
6 #include "uri_unsafe.h"
7
8 /* aliases */
9 #define TXCODE_literal_i TXCODE_literal
10 #define TXCODE_depend TXCODE_noop
11 #define TXCODE_macro_begin TXCODE_noop
12 #define TXCODE_macro_nargs TXCODE_noop
13 #define TXCODE_macro_outer TXCODE_noop
14 #define TXCODE_set_opinfo TXCODE_noop
15 #define TXCODE_super TXCODE_noop
16
17 #include "xslate_ops.h"
18
19 static bool dump_load = FALSE;
20
21 #ifdef DEBUGGING
22 #define TX_st_sa *tx_sv_safe(aTHX_ &(TX_st->sa), "TX_st->sa", __FILE__, __LINE__)
23 #define TX_st_sb *tx_sv_safe(aTHX_ &(TX_st->sb), "TX_st->sb", __FILE__, __LINE__)
24 static SV**
tx_sv_safe(pTHX_ SV ** const svp,const char * const name,const char * const f,int const l)25 tx_sv_safe(pTHX_ SV** const svp, const char* const name, const char* const f, int const l) {
26 if(*svp == NULL) {
27 croak("[BUG] %s is NULL at %s line %d.\n", name, f, l);
28 }
29 return svp;
30 }
31
32 #define TX_lvarx_get(st, ix) tx_lvar_get_safe(aTHX_ st, ix)
33
34 static SV*
tx_lvar_get_safe(pTHX_ tx_state_t * const st,I32 const lvar_ix)35 tx_lvar_get_safe(pTHX_ tx_state_t* const st, I32 const lvar_ix) {
36 AV* const cframe = TX_current_framex(st);
37 I32 const real_ix = lvar_ix + TXframe_START_LVAR;
38
39 assert(SvTYPE(cframe) == SVt_PVAV);
40 if(AvFILLp(cframe) < real_ix) {
41 croak("[BUG] Refers to unallocated local variable %d (> %d)",
42 (int)lvar_ix, (int)(AvFILLp(cframe) - TXframe_START_LVAR));
43 }
44
45 if(!st->pad) {
46 croak("[BUG] Refers to local variable %d before initialization",
47 (int)lvar_ix);
48 }
49 return st->pad[lvar_ix];
50 }
51
52
53 #else /* DEBUGGING */
54 #define TX_st_sa (TX_st->sa)
55 #define TX_st_sb (TX_st->sb)
56
57 #define TX_lvarx_get(st, ix) ((st)->pad[ix])
58 #endif /* DEBUGGING */
59
60 #define TX_op_arg (TX_op->u_arg)
61 #define TX_op_arg_sv (TX_op_arg.sv)
62 #define TX_op_arg_iv (TX_op_arg.iv)
63 #define TX_op_arg_pc (TX_op_arg.pc)
64
65 #define TX_lvarx(st, ix) tx_load_lvar(aTHX_ st, ix)
66
67 #define TX_lvar(ix) TX_lvarx(TX_st, ix) /* init if uninitialized */
68 #define TX_lvar_get(ix) TX_lvarx_get(TX_st, ix)
69
70 #define TX_ckuuv_lhs(x) tx_sv_check_uuv(aTHX_ (x), "lhs")
71 #define TX_ckuuv_rhs(x) tx_sv_check_uuv(aTHX_ (x), "rhs")
72
73 #define TX_UNMARK_RAW(sv) SvRV(sv)
74
75 #define MY_CXT_KEY "Text::Xslate::_guts" XS_VERSION
76 typedef struct {
77 I32 depth;
78 HV* raw_stash;
79 HV* macro_stash;
80
81 tx_state_t* current_st; /* set while tx_execute(), othewise NULL */
82
83 /* those handlers are just \&_warn and \&_die,
84 but stored here for performance */
85 SV* warn_handler;
86 SV* die_handler;
87
88 /* original error handlers */
89 SV* orig_warn_handler;
90 SV* orig_die_handler;
91 SV* make_error;
92 } my_cxt_t;
93 START_MY_CXT
94
95 static void
tx_sv_clear(pTHX_ SV * const sv)96 tx_sv_clear(pTHX_ SV* const sv) {
97 sv_unmagic(sv, PERL_MAGIC_taint);
98 sv_setsv(sv, NULL);
99 }
100
101 const char*
102 tx_neat(pTHX_ SV* const sv);
103
104 static SV*
105 tx_load_lvar(pTHX_ tx_state_t* const st, I32 const lvar_ix);
106
107 static AV*
108 tx_push_frame(pTHX_ tx_state_t* const st);
109
110 static void
111 tx_pop_frame(pTHX_ tx_state_t* const st, bool const replace_output);
112
113 static SV*
114 tx_funcall(pTHX_ tx_state_t* const st, SV* const func, const char* const name);
115
116 static SV*
117 tx_fetch(pTHX_ tx_state_t* const st, SV* const var, SV* const key);
118
119 static SV*
120 tx_sv_to_ref(pTHX_ SV* const sv, svtype const svt, int const amg_id);
121
122 int
tx_sv_is_array_ref(pTHX_ SV * const sv)123 tx_sv_is_array_ref(pTHX_ SV* const sv) {
124 assert(sv);
125 return SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV && !SvOBJECT(SvRV(sv));
126 }
127
128 int
tx_sv_is_hash_ref(pTHX_ SV * const sv)129 tx_sv_is_hash_ref(pTHX_ SV* const sv) {
130 assert(sv);
131 return SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVHV && !SvOBJECT(SvRV(sv));
132 }
133
134 int
tx_sv_is_code_ref(pTHX_ SV * const sv)135 tx_sv_is_code_ref(pTHX_ SV* const sv) {
136 assert(sv);
137 return SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVCV && !SvOBJECT(SvRV(sv));
138 }
139
140 SV*
tx_merge_hash(pTHX_ tx_state_t * const st,SV * base,SV * value)141 tx_merge_hash(pTHX_ tx_state_t* const st, SV* base, SV* value) {
142 HV* const hv = (HV*)SvRV(base);
143 HV* const result = newHVhv(hv);
144 SV* const resultref = newRV_noinc((SV*)result);
145 HE* he;
146 HV* m;
147 sv_2mortal((SV*)resultref);
148
149 SvGETMAGIC(base);
150 SvGETMAGIC(value);
151
152 if(!tx_sv_is_hash_ref(aTHX_ value)) {
153 if (st) {
154 tx_error(aTHX_ st, "Merging value is not a HASH reference");
155 }
156 else {
157 Perl_croak(aTHX_ "Merging value is not a HASH reference");
158 }
159 return resultref;
160 }
161
162 m = (HV*)SvRV(value);
163
164 hv_iterinit(m);
165 while((he = hv_iternext(m))) {
166 (void)hv_store_ent(result,
167 hv_iterkeysv(he),
168 newSVsv(hv_iterval(hv, he)),
169 0U);
170 }
171
172 return resultref;
173 }
174
175 STATIC_INLINE bool
176 tx_str_is_raw(pTHX_ pMY_CXT_ SV* const sv); /* doesn't handle magics */
177
178 STATIC_INLINE void
179 tx_sv_cat(pTHX_ SV* const dest, SV* const src);
180
181 static void
182 tx_sv_cat_with_html_escape_force(pTHX_ SV* const dest, SV* const src);
183
184 STATIC_INLINE void
185 tx_print(pTHX_ tx_state_t* const st, SV* const sv);
186
187 static SV*
188 tx_html_escape(pTHX_ SV* const str);
189
190 static SV*
191 tx_uri_escape(pTHX_ SV* const src);
192
193 STATIC_INLINE I32
194 tx_sv_eq(pTHX_ SV* const a, SV* const b);
195
196 static SV*
197 tx_sv_check_uuv(pTHX_ SV* const sv, const char* const name);
198
199 static I32
200 tx_sv_match(pTHX_ SV* const a, SV* const b);
201
202 static bool
203 tx_sv_is_macro(pTHX_ SV* const sv);
204
205 static void
206 tx_macro_enter(pTHX_ tx_state_t* const txst, AV* const macro, tx_pc_t const retaddr);
207
208 static void
209 tx_execute(pTHX_ pMY_CXT_ tx_state_t* const base, SV* const output, HV* const hv);
210
211 static tx_state_t*
212 tx_load_template(pTHX_ SV* const self, SV* const name, bool const from_include);
213
214 #ifndef save_op
215 #define save_op() my_save_op(aTHX)
216 static void
my_save_op(pTHX)217 my_save_op(pTHX) { /* copied from scope.c */
218 SSCHECK(2);
219 SSPUSHPTR(PL_op);
220 SSPUSHINT(SAVEt_OP);
221 }
222 #endif
223
224 #include "src/xslate_opcode.inc"
225
226 const char*
tx_neat(pTHX_ SV * const sv)227 tx_neat(pTHX_ SV* const sv) {
228 if(SvOK(sv)) {
229 if(SvROK(sv) || looks_like_number(sv) || isGV(sv)) {
230 return form("%"SVf, sv);
231 }
232 else {
233 return form("'%"SVf"'", sv);
234 }
235 }
236 return "nil";
237 }
238
239 static IV
tx_verbose(pTHX_ tx_state_t * const st)240 tx_verbose(pTHX_ tx_state_t* const st) {
241 HV* const hv = (HV*)SvRV(st->engine);
242 SV* const sv = *hv_fetchs(hv, "verbose", TRUE);
243 return SvIV(sv);
244 }
245
246
247 static void
tx_call_error_handler(pTHX_ SV * const handler,SV * const msg)248 tx_call_error_handler(pTHX_ SV* const handler, SV* const msg) {
249 dSP;
250 PUSHMARK(SP);
251 XPUSHs(msg);
252 PUTBACK;
253 call_sv(handler, G_VOID | G_DISCARD);
254 }
255
256 /* for trivial errors, ignored by default */
257 void
tx_warn(pTHX_ tx_state_t * const st,const char * const fmt,...)258 tx_warn(pTHX_ tx_state_t* const st, const char* const fmt, ...) {
259 assert(st);
260 assert(fmt);
261 if(tx_verbose(aTHX_ st) > TX_VERBOSE_DEFAULT) { /* stronger than the default */
262 dMY_CXT;
263 SV* msg;
264 va_list args;
265 va_start(args, fmt);
266
267 ENTER;
268 SAVETMPS;
269 msg = sv_2mortal( vnewSVpvf(fmt, &args) );
270 tx_call_error_handler(aTHX_ MY_CXT.warn_handler, msg);
271 va_end(args);
272 FREETMPS;
273 LEAVE;
274 }
275 }
276
277 /* for severe errors, warned by default */
278 void
tx_error(pTHX_ tx_state_t * const st,const char * const fmt,...)279 tx_error(pTHX_ tx_state_t* const st, const char* const fmt, ...) {
280 assert(st);
281 assert(fmt);
282 if(tx_verbose(aTHX_ st) >= TX_VERBOSE_DEFAULT) { /* equal or stronger than the default */
283 dMY_CXT;
284 SV* msg;
285 va_list args;
286 va_start(args, fmt);
287 msg = sv_2mortal( vnewSVpvf(fmt, &args) );
288 tx_call_error_handler(aTHX_ MY_CXT.warn_handler, msg);
289 /* not reached */
290 va_end(args);
291 }
292 }
293
294 static SV* /* allocate and load a lexcal variable */
tx_load_lvar(pTHX_ tx_state_t * const st,I32 const lvar_ix)295 tx_load_lvar(pTHX_ tx_state_t* const st, I32 const lvar_ix) { /* the guts of TX_lvar() */
296 AV* const cframe = TX_current_framex(st);
297 I32 const real_ix = lvar_ix + TXframe_START_LVAR;
298
299 assert(SvTYPE(cframe) == SVt_PVAV);
300
301 if(AvFILLp(cframe) < real_ix
302 || AvARRAY(cframe)[real_ix] == NULL
303 || SvREADONLY(AvARRAY(cframe)[real_ix])) {
304 av_store(cframe, real_ix, newSV(0));
305 }
306 st->pad = AvARRAY(cframe) + TXframe_START_LVAR;
307
308 return TX_lvarx_get(st, lvar_ix);
309 }
310
311 static AV*
tx_push_frame(pTHX_ tx_state_t * const st)312 tx_push_frame(pTHX_ tx_state_t* const st) {
313 AV* newframe;
314
315 if(st->current_frame > TX_MAX_DEPTH) {
316 croak("Macro call is too deep (> %d)", TX_MAX_DEPTH);
317 }
318 st->current_frame++;
319
320 newframe = (AV*)*av_fetch(st->frames, st->current_frame, TRUE);
321
322 (void)SvUPGRADE((SV*)newframe, SVt_PVAV);
323 if(AvFILLp(newframe) < TXframe_START_LVAR) {
324 av_extend(newframe, TXframe_START_LVAR);
325 }
326 /* switch the pad */
327 st->pad = AvARRAY(newframe) + TXframe_START_LVAR;
328 return newframe;
329 }
330
331 static void
tx_pop_frame(pTHX_ tx_state_t * const st,bool const replace_output)332 tx_pop_frame(pTHX_ tx_state_t* const st, bool const replace_output) {
333 AV* const top = TX_frame_at(st, st->current_frame);
334
335 av_fill(top, TXframe_START_LVAR - 1);
336
337 assert( st->current_frame >= 0 );
338 if (--st->current_frame >= 0) {
339 /* switch the pad */
340 st->pad = AvARRAY(TX_frame_at(st, st->current_frame))
341 + TXframe_START_LVAR;
342 }
343
344 if(replace_output) {
345 SV** const ary = AvARRAY(top);
346 SV* const tmp = ary[TXframe_OUTPUT];
347 ary[TXframe_OUTPUT] = st->output;
348 st->output = tmp;
349 }
350 }
351
352 SV* /* thin wrapper of Perl_call_sv() */
tx_call_sv(pTHX_ tx_state_t * const st,SV * const sv,I32 const flags,const char * const name)353 tx_call_sv(pTHX_ tx_state_t* const st, SV* const sv, I32 const flags, const char* const name) {
354 SV* retval;
355 call_sv(sv, G_SCALAR | G_EVAL | flags);
356 retval = TX_pop();
357 if(TX_CATCH_ERROR()) {
358 tx_error(aTHX_ st, "%"SVf "\n"
359 "\t... exception caught on %s", ERRSV, name);
360 }
361 return retval;
362 }
363
364 static SV*
tx_funcall(pTHX_ tx_state_t * const st,SV * const func,const char * const name)365 tx_funcall(pTHX_ tx_state_t* const st, SV* const func, const char* const name) {
366 HV* dummy_stash;
367 GV* dummy_gv;
368 CV* cv;
369 SV* retval;
370 SvGETMAGIC(func);
371
372 if(UNLIKELY(!SvOK(func))) {
373 dTX_optable;
374 tx_code_t* const c = st->pc - 1;
375 (void)POPMARK;
376 tx_error(aTHX_ st, "Undefined function%s is called on %s",
377 c->exec_code == tx_optable[TXOP_fetch_s]
378 ? form(" %"SVf"()", c->u_arg.sv)
379 : "", name);
380 retval = NULL;
381 goto finish;
382 }
383
384 cv = sv_2cv(func, &dummy_stash, &dummy_gv, FALSE);
385
386 if(UNLIKELY(!cv)) {
387 (void)POPMARK;
388 tx_error(aTHX_ st, "Functions must be a CODE reference, not %s",
389 tx_neat(aTHX_ func));
390 retval = NULL;
391 goto finish;
392 }
393
394 retval = tx_call_sv(aTHX_ st, (SV*)cv, 0, "function call");
395
396 finish:
397 sv_setsv_nomg(st->targ, retval);
398
399 return st->targ;
400 }
401
402 static SV*
tx_fetch(pTHX_ tx_state_t * const st,SV * const var,SV * const key)403 tx_fetch(pTHX_ tx_state_t* const st, SV* const var, SV* const key) {
404 SV* retval;
405
406 SvGETMAGIC(var);
407 if(SvROK(var) && SvOBJECT(SvRV(var))) {
408 dSP;
409 PUSHMARK(SP);
410 XPUSHs(var);
411 PUTBACK;
412
413 return tx_call_sv(aTHX_ st, key, G_METHOD, "accessor");
414 }
415
416 retval = NULL;
417 if(SvROK(var)){
418 SV* const rv = SvRV(var);
419 SvGETMAGIC(key);
420 if(SvTYPE(rv) == SVt_PVHV) {
421 if(SvOK(key)) {
422 HE* const he = hv_fetch_ent((HV*)rv, key, FALSE, 0U);
423 if(he) {
424 retval = hv_iterval((HV*)rv, he);
425 }
426 }
427 else {
428 tx_warn(aTHX_ st, "Use of nil as a field key");
429 }
430 }
431 else if(SvTYPE(rv) == SVt_PVAV) {
432 if(LooksLikeNumber(key)) {
433 SV** const svp = av_fetch((AV*)rv, SvIV(key), FALSE);
434 if(svp) {
435 retval = *svp;
436 }
437 }
438 else {
439 tx_warn(aTHX_ st, "Use of %s as an array index",
440 tx_neat(aTHX_ key));
441 }
442 }
443 else {
444 goto invalid_container;
445 }
446 }
447 else if(SvOK(var)){ /* string, number, etc. */
448 invalid_container:
449 tx_error(aTHX_ st, "Cannot access %s (%s is not a container)",
450 tx_neat(aTHX_ key), tx_neat(aTHX_ var));
451 }
452 else { /* undef */
453 tx_warn(aTHX_ st, "Use of nil to access %s", tx_neat(aTHX_ key));
454 }
455 TAINT_NOT;
456
457 return retval ? retval : &PL_sv_undef;
458 }
459
460 #ifndef amagic_deref_call
461 #define amagic_deref_call(ref, method) my_amagic_deref_call(aTHX_ ref, method)
462 /* portability */
463 static SV*
my_amagic_deref_call(pTHX_ SV * ref,const int method)464 my_amagic_deref_call(pTHX_ SV* ref, const int method) {
465 SV* tmpsv = NULL;
466
467 while (SvAMAGIC(ref) &&
468 (tmpsv = amagic_call(ref, &PL_sv_undef, method,
469 AMGf_noright | AMGf_unary))) {
470 if (!SvROK(tmpsv))
471 Perl_croak(aTHX_ "Overloaded dereference did not return a reference");
472 if (tmpsv == ref || SvRV(tmpsv) == SvRV(ref)) {
473 /* Bail out if it returns us the same reference. */
474 return tmpsv;
475 }
476 ref = tmpsv;
477 }
478 return tmpsv ? tmpsv : ref;
479 }
480 #endif
481
482 static SV*
tx_sv_to_ref(pTHX_ SV * const sv,svtype const svt,const int amg_id)483 tx_sv_to_ref(pTHX_ SV* const sv, svtype const svt, const int amg_id) {
484 if(SvROK(sv)) {
485 SV* const r = SvRV(sv);
486 if(SvOBJECT(r)) {
487 if(SvAMAGIC(sv)) {
488 SV* const tmpsv = amagic_deref_call(sv, amg_id);
489 if(SvROK(tmpsv)
490 && SvTYPE(SvRV(tmpsv)) == svt
491 && !SvOBJECT(SvRV(tmpsv))) {
492 return tmpsv;
493 }
494 }
495 }
496 else if(SvTYPE(r) == svt) {
497 return sv;
498 }
499 }
500 return NULL;
501 }
502
503 STATIC_INLINE bool
tx_str_is_raw(pTHX_ pMY_CXT_ SV * const sv)504 tx_str_is_raw(pTHX_ pMY_CXT_ SV* const sv) {
505 if(SvROK(sv) && SvOBJECT(SvRV(sv))) {
506 return SvTYPE(SvRV(sv)) <= SVt_PVMG
507 && SvSTASH(SvRV(sv)) == MY_CXT.raw_stash;
508 }
509 return FALSE;
510 }
511
512 SV*
tx_mark_raw(pTHX_ SV * const str)513 tx_mark_raw(pTHX_ SV* const str) {
514 dMY_CXT;
515 SvGETMAGIC(str);
516 if(!SvOK(str)) {
517 return str;
518 }
519 else if(tx_str_is_raw(aTHX_ aMY_CXT_ str)) {
520 return str;
521 }
522 else {
523 SV* const sv = newSV_type(SVt_PVMG);
524 sv_setsv(sv, str);
525 return sv_2mortal(sv_bless(newRV_noinc(sv), MY_CXT.raw_stash));
526 }
527 }
528
529 SV*
tx_unmark_raw(pTHX_ SV * const str)530 tx_unmark_raw(pTHX_ SV* const str) {
531 dMY_CXT;
532 SvGETMAGIC(str);
533 if(tx_str_is_raw(aTHX_ aMY_CXT_ str)) {
534 return TX_UNMARK_RAW(str);
535 }
536 else {
537 return str;
538 }
539 }
540
541 /* does sv_catsv_nomg(dest, src), but significantly faster */
542 STATIC_INLINE void
tx_sv_cat(pTHX_ SV * const dest,SV * const src)543 tx_sv_cat(pTHX_ SV* const dest, SV* const src) {
544 STRLEN len;
545 const char* pv = SvPV_const(src, len);
546
547 if(!SvUTF8(dest) && SvUTF8(src)) {
548 sv_utf8_upgrade(dest);
549 }
550
551 if(SvUTF8(dest) == SvUTF8(src)
552 || is_utf8_string((const U8 *)pv, len)) {
553 STRLEN const dest_cur = SvCUR(dest);
554 char* const d = SvGROW(dest, dest_cur + len + 1 /* count '\0' */);
555
556 SvCUR_set(dest, dest_cur + len);
557 Copy(pv, d + dest_cur, len + 1 /* copy '\0' */, char);
558 }
559 else {
560 STRLEN const dest_cur = SvCUR(dest);
561 /* Longest UTF-8 representation of each char is 2 octets. */
562 char* const d_start = SvGROW(dest, dest_cur + 2 * len + 1 /* count '\0' */);
563 char* d = d_start + dest_cur;
564
565 while(len--) {
566 const U8 c = *pv++;
567 if (UTF8_IS_INVARIANT(c)) {
568 *(d++) = c;
569 } else {
570 *(d++) = UTF8_EIGHT_BIT_HI(c);
571 *(d++) = UTF8_EIGHT_BIT_LO(c);
572 }
573 }
574 *d = '\0';
575 SvCUR_set(dest, d - d_start);
576 }
577 }
578
579 static void /* doesn't care about raw-ness */
tx_sv_cat_with_html_escape_force(pTHX_ SV * const dest,SV * const src)580 tx_sv_cat_with_html_escape_force(pTHX_ SV* const dest, SV* const src) {
581 STRLEN len;
582 const char* cur = SvPV_const(src, len);
583 const char* const end = cur + len;
584 STRLEN const dest_cur = SvCUR(dest);
585 char* d;
586 const U32 upgrade_on_copy = SvUTF8(dest) && !SvUTF8(src)
587 && !is_utf8_string((const U8 *)cur, len);
588
589 (void)SvGROW(dest, dest_cur + ( len * ( sizeof(""") - 1) ) + 1);
590 if(!SvUTF8(dest) && SvUTF8(src)) {
591 sv_utf8_upgrade(dest);
592 }
593
594 d = SvPVX(dest) + dest_cur;
595
596 #define CopyToken(token, to) STMT_START { \
597 Copy(token "", to, sizeof(token)-1, char); \
598 to += sizeof(token)-1; \
599 } STMT_END
600
601 while(cur != end) {
602 const char c = *(cur++);
603 if(c == '&') {
604 CopyToken("&", d);
605 }
606 else if(c == '<') {
607 CopyToken("<", d);
608 }
609 else if(c == '>') {
610 CopyToken(">", d);
611 }
612 else if(c == '"') {
613 CopyToken(""", d);
614 }
615 else if(c == '\'') {
616 // XXX: Internet Explorer (at least version 8) doesn't support ' in title
617 // CopyToken("'", d);
618 CopyToken("'", d);
619 }
620 else if (upgrade_on_copy && !UTF8_IS_INVARIANT(c)) {
621 *(d++) = UTF8_EIGHT_BIT_HI((U8) c);
622 *(d++) = UTF8_EIGHT_BIT_LO((U8) c);
623 }
624 else {
625 *(d++) = c;
626 }
627 }
628
629 #undef CopyToken
630
631 SvCUR_set(dest, d - SvPVX(dest));
632 *SvEND(dest) = '\0';
633 }
634
635 STATIC_INLINE void
tx_print(pTHX_ tx_state_t * const st,SV * const sv)636 tx_print(pTHX_ tx_state_t* const st, SV* const sv) {
637 dMY_CXT;
638 SV* const out = st->output;
639
640 SvGETMAGIC(sv);
641 if(tx_str_is_raw(aTHX_ aMY_CXT_ sv)) {
642 SV* const arg = TX_UNMARK_RAW(sv);
643 if(SvOK(arg)) {
644 tx_sv_cat(aTHX_ out, arg);
645 }
646 else {
647 tx_warn(aTHX_ st, "Use of nil to print");
648 }
649 }
650 else if(SvOK(sv)) {
651 tx_sv_cat_with_html_escape_force(aTHX_ out, sv);
652 }
653 else {
654 tx_warn(aTHX_ st, "Use of nil to print");
655 /* does nothing */
656 }
657 }
658
659 static SV*
tx_html_escape(pTHX_ SV * const str)660 tx_html_escape(pTHX_ SV* const str) {
661 dMY_CXT;
662 SvGETMAGIC(str);
663 if(!( !SvOK(str) || tx_str_is_raw(aTHX_ aMY_CXT_ str) )) {
664 SV* const dest = newSVpvs_flags("", SVs_TEMP);
665 tx_sv_cat_with_html_escape_force(aTHX_ dest, str);
666 return tx_mark_raw(aTHX_ dest);
667 }
668 else {
669 return str;
670 }
671 }
672
673
674 static SV*
tx_uri_escape(pTHX_ SV * const src)675 tx_uri_escape(pTHX_ SV* const src) {
676 /* TODO:
677 Currently it is encoded to UTF-8, but
678 the output encoding can be specified in a future (?).
679 */
680
681 SvGETMAGIC(src);
682 if(SvOK(src)) {
683 STRLEN len;
684 const char* pv = SvPV_const(src, len);
685 const char* const end = pv + len;
686 SV* const dest = sv_newmortal();
687 sv_grow(dest, len * 2); /* just a hint; upgrading Svt_PV */
688 SvPOK_on(dest);
689
690 while(pv != end) {
691 if(is_uri_unsafe(*pv)) {
692 /* identical to PL_hexdigit + 16 */
693 static const char hexdigit[] = "0123456789ABCDEF";
694 char p[3];
695 p[0] = '%';
696 p[1] = hexdigit[((U8)*pv & 0xF0) >> 4]; /* high 4 bits */
697 p[2] = hexdigit[((U8)*pv & 0x0F)]; /* low 4 bits */
698 sv_catpvn(dest, p, 3);
699 }
700 else {
701 sv_catpvn(dest, pv, 1);
702 }
703 pv++;
704 }
705 return dest;
706 }
707 else {
708 return &PL_sv_undef;
709 }
710 }
711
712 /* for tx_ckuuv_lhs() / tx_ckuuv_rhs() macros */
713 static SV*
tx_sv_check_uuv(pTHX_ SV * const sv,const char * const name)714 tx_sv_check_uuv(pTHX_ SV* const sv, const char* const name) {
715 /* check "Use of uninitialized value" (uuv) */
716 SvGETMAGIC(sv);
717 if(!SvOK(sv)) {
718 dMY_CXT;
719 tx_warn(aTHX_ MY_CXT.current_st,
720 "Use of nil for %s of binary operator", name);
721 return &PL_sv_no;
722 }
723 return sv;
724 }
725
726 static I32
tx_sv_eq_nomg(pTHX_ SV * const a,SV * const b)727 tx_sv_eq_nomg(pTHX_ SV* const a, SV* const b) {
728 if(SvOK(a)) {
729 if(SvOK(b)) {
730 U32 const af = (SvFLAGS(a) & (SVf_POK|SVf_IOK|SVf_NOK));
731 U32 const bf = SvFLAGS(b) & af;
732 return bf == SVf_IOK
733 ? SvIVX(a) == SvIVX(b)
734 : sv_eq(a, b);
735 }
736 else {
737 return FALSE;
738 }
739 }
740 else { /* !SvOK(a) */
741 return !SvOK(b);
742 }
743 }
744
745 STATIC_INLINE I32
tx_sv_eq(pTHX_ SV * const a,SV * const b)746 tx_sv_eq(pTHX_ SV* const a, SV* const b) {
747 SvGETMAGIC(a);
748 SvSETMAGIC(b);
749 return tx_sv_eq_nomg(aTHX_ a, b);
750 }
751
752 static I32
tx_sv_match(pTHX_ SV * const a,SV * const b)753 tx_sv_match(pTHX_ SV* const a, SV* const b) {
754 SvGETMAGIC(a);
755 SvGETMAGIC(b);
756
757 if(SvROK(b)) {
758 SV* const r = SvRV(b);
759 if(SvOBJECT(r)) { /* a ~~ $object */
760 /* XXX: what I should do? */
761 return tx_sv_eq_nomg(aTHX_ a, b);
762 }
763 else if(SvTYPE(r) == SVt_PVAV) { /* a ~~ [ ... ] */
764 AV* const av = (AV*)r;
765 I32 const len = av_len(av) + 1;
766 I32 i;
767 for(i = 0; i < len; i++) {
768 SV** const svp = av_fetch(av, i, FALSE);
769 SV* item;
770 if(svp) {
771 item = *svp;
772 SvGETMAGIC(item);
773 }
774 else {
775 item = &PL_sv_undef;
776 }
777 if(tx_sv_eq_nomg(aTHX_ a, item)) {
778 return TRUE;
779 }
780 }
781 return FALSE;
782 }
783 else if(SvTYPE(r) == SVt_PVHV) { /* a ~~ { ... } */
784 if(SvOK(a)) {
785 HV* const hv = (HV*)r;
786 return hv_exists_ent(hv, a, 0U);
787 }
788 else {
789 return FALSE;
790 }
791 }
792 /* fallthrough */
793 }
794
795 return tx_sv_eq_nomg(aTHX_ a, b);
796 }
797
798 static bool
tx_sv_is_macro(pTHX_ SV * const sv)799 tx_sv_is_macro(pTHX_ SV* const sv) {
800
801 if(sv_isobject(sv)) {
802 AV* const macro = (AV*)SvRV(sv);
803 dMY_CXT;
804 if(SvSTASH(macro) == MY_CXT.macro_stash) {
805 if(!(SvTYPE(macro) == SVt_PVAV && AvFILLp(macro) == (TXm_size - 1))) {
806 croak("Oops: Invalid macro object");
807 }
808 return TRUE;
809 }
810 }
811 return FALSE;
812 }
813
814 XS(XS_Text__Xslate__macrocall); /* -Wmissing-prototype */
XS(XS_Text__Xslate__macrocall)815 XS(XS_Text__Xslate__macrocall){
816 dVAR; dSP; /* macrocall routine do dMARK, so we don't it here */
817 dMY_CXT;
818 SV* const macro = (SV*)CvXSUBANY(cv).any_ptr;
819 if(!(MY_CXT.current_st && macro)) {
820 croak("Macro is not callable outside of templates");
821 }
822 XPUSHs( tx_proccall(aTHX_ MY_CXT.current_st, macro, "macro") );
823 PUTBACK;
824 return;
825 }
826
827 /* called by tx_methodcall() */
828 /* proc may be a Xslate macro or a Perl subroutine (code ref) */
829 SV*
tx_proccall(pTHX_ tx_state_t * const txst,SV * const proc,const char * const name)830 tx_proccall(pTHX_ tx_state_t* const txst, SV* const proc, const char* const name) {
831 if(tx_sv_is_macro(aTHX_ proc)) {
832 dTX_optable;
833 tx_pc_t const save_pc = TX_st->pc;
834 tx_code_t proc_end;
835
836 proc_end.exec_code = tx_optable[ TXOP_end ];
837 tx_macro_enter(aTHX_ TX_st, (AV*)SvRV(proc), &proc_end);
838 TX_RUNOPS(TX_st);
839 /* after tx_macro_end */
840
841 TX_st->pc = save_pc;
842 //warn("# return from %s\n", name);
843
844 return TX_st_sa;
845 }
846 else if (tx_sv_is_code_ref(aTHX_ proc) && CvXSUB((CV*)SvRV(proc)) == XS_Text__Xslate__macrocall) {
847 /* macro wrapper XSUB created by Text::Xslate::Type::as_code_ref() */
848 SV* const m = CvXSUBANY((CV*)SvRV(proc)).any_ptr;
849 sv_dump(proc);
850 sv_dump(m);
851 Perl_croak(aTHX_ "xxx");
852 return tx_proccall(aTHX_ TX_st, m, name);
853 }
854 else {
855 return tx_funcall(aTHX_ TX_st, proc, name);
856 }
857 }
858
859
860 static void
tx_macro_enter(pTHX_ tx_state_t * const txst,AV * const macro,tx_pc_t const retaddr)861 tx_macro_enter(pTHX_ tx_state_t* const txst, AV* const macro, tx_pc_t const retaddr) {
862 dSP;
863 dMARK;
864 I32 const items = SP - MARK;
865 SV* const name = AvARRAY(macro)[TXm_NAME];
866 tx_pc_t const addr = INT2PTR(tx_pc_t, SvUVX(AvARRAY(macro)[TXm_ADDR]));
867 IV const nargs = SvIVX(AvARRAY(macro)[TXm_NARGS]);
868 UV const outer = SvUVX(AvARRAY(macro)[TXm_OUTER]);
869 AV* cframe; /* new frame */
870 UV i;
871 SV* tmp;
872
873 if(items != nargs) {
874 tx_error(aTHX_ TX_st, "Wrong number of arguments for %"SVf" (%d %c %d)",
875 name, (int)items, items > nargs ? '>' : '<', (int)nargs);
876 TX_st->sa = &PL_sv_undef;
877 TX_RETURN_NEXT();
878 }
879
880 /* create a new frame */
881 cframe = tx_push_frame(aTHX_ TX_st);
882
883 /* setup frame info: name, retaddr and output buffer */
884 sv_setsv(*av_fetch(cframe, TXframe_NAME, TRUE), name);
885 sv_setuv(*av_fetch(cframe, TXframe_RETADDR, TRUE), PTR2UV(retaddr));
886
887 /* swap TXframe_OUTPUT and TX_st->output.
888 I know it's ugly. Any ideas?
889 */
890 tmp = *av_fetch(cframe, TXframe_OUTPUT, TRUE);
891 AvARRAY(cframe)[TXframe_OUTPUT] = TX_st->output;
892 TX_st->output = tmp;
893 sv_setpvs(tmp, "");
894 SvGROW(tmp, TX_HINT_SIZE);
895
896 i = 0;
897 if(outer > 0) { /* refers outer lexical variales */
898 /* copies lexical variables from the old frame to the new one */
899 AV* const oframe = TX_frame_at(TX_st, TX_st->current_frame-1);
900 for(NOOP; i < outer; i++) {
901 IV const real_ix = i + TXframe_START_LVAR;
902 /* XXX: macros can refer to unallocated lvars */
903 SV* sv;
904 SV* v = AvARRAY(oframe)[real_ix];
905 if (v != NULL && AvFILLp(oframe) >= real_ix) {
906 sv = sv_mortalcopy(v);
907 } else {
908 sv = &PL_sv_undef;
909 }
910 av_store(cframe, real_ix , sv);
911 SvREFCNT_inc_simple_void_NN(sv);
912 }
913 }
914 if(items > 0) { /* has arguments */
915 dORIGMARK;
916 MARK++;
917 for(NOOP; MARK <= SP; i++) {
918 sv_setsv(TX_lvar(i), *MARK);
919 MARK++;
920 }
921 SP = ORIGMARK;
922 PUTBACK;
923 }
924 TX_st->pad = AvARRAY(cframe) + TXframe_START_LVAR;
925 TX_RETURN_PC(addr);
926 }
927
928 /* The virtual machine code interpreter */
929 /* NOTE: tx_execute() must be surrounded in ENTER and LEAVE */
930 static void
tx_execute(pTHX_ pMY_CXT_ tx_state_t * const base,SV * const output,HV * const hv)931 tx_execute(pTHX_ pMY_CXT_ tx_state_t* const base, SV* const output, HV* const hv) {
932 dXCPT;
933 tx_state_t st;
934
935 StructCopy(base, &st, tx_state_t);
936
937 //PerlIO_stdoutf("#>> 0x%p %d %d\n", base, (int)MY_CXT.depth, (int)st.current_frame);
938 st.output = output;
939 st.vars = hv;
940
941 assert(st.tmpl != NULL);
942
943 /* local $current_st */
944 SAVEVPTR(MY_CXT.current_st);
945 MY_CXT.current_st = &st;
946
947 assert(MY_CXT.depth >= 0);
948 if(MY_CXT.depth > TX_MAX_DEPTH) {
949 croak("Execution is too deep (> %d)", TX_MAX_DEPTH);
950 }
951
952 /* local $depth = $depth + 1 */
953 MY_CXT.depth++;
954
955 XCPT_TRY_START {
956 TX_RUNOPS(&st);
957 }
958 XCPT_TRY_END;
959
960 /* finally */
961 MY_CXT.depth--;
962
963 XCPT_CATCH {
964 I32 const start = base->current_frame;
965 /* unwind the stack frames */
966 while(st.current_frame > start) {
967 tx_pop_frame(aTHX_ &st, TRUE);
968 }
969 tx_pop_frame(aTHX_ base, FALSE); // pushed before tx_execute()
970 XCPT_RETHROW;
971 }
972 tx_pop_frame(aTHX_ base, FALSE); // pushed before tx_execute()
973
974 /* clear temporary buffers */
975 sv_setsv(st.targ, NULL);
976
977 /* store the current buffer size as a hint size */
978 base->hint_size = SvCUR(st.output);
979 }
980
981
982 static MAGIC*
mgx_find(pTHX_ SV * const sv,const MGVTBL * const vtbl)983 mgx_find(pTHX_ SV* const sv, const MGVTBL* const vtbl){
984 MAGIC* mg;
985
986 assert(sv != NULL);
987 assert(vtbl != NULL);
988
989 for(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic){
990 if(mg->mg_virtual == vtbl){
991 assert(mg->mg_type == PERL_MAGIC_ext);
992 return mg;
993 }
994 }
995
996 return NULL;
997 }
998
999 static int
tx_mg_free(pTHX_ SV * const sv,MAGIC * const mg)1000 tx_mg_free(pTHX_ SV* const sv, MAGIC* const mg){
1001 tx_state_t* const st = (tx_state_t*)mg->mg_ptr;
1002 tx_info_t* const info = st->info;
1003 tx_code_t* const code = st->code;
1004 I32 const len = st->code_len;
1005 I32 i;
1006
1007 // PerlIO_stdoutf("# tx_mg_free()\n");
1008 for(i = 0; i < len; i++) {
1009 /* opcode */
1010 if( tx_oparg[ info[i].optype ] & TXARGf_SV ) {
1011 SvREFCNT_dec(code[i].u_arg.sv);
1012 }
1013
1014 /* opinfo */
1015 SvREFCNT_dec(info[i].file);
1016 }
1017
1018 Safefree(code);
1019 Safefree(info);
1020
1021 SvREFCNT_dec(st->symbol);
1022 SvREFCNT_dec(st->frames);
1023 SvREFCNT_dec(st->targ);
1024 SvREFCNT_dec(st->engine);
1025
1026 PERL_UNUSED_ARG(sv);
1027
1028 return 0;
1029 }
1030
1031 #ifdef USE_ITHREADS
1032 static SV*
tx_sv_dup_inc(pTHX_ SV * const sv,CLONE_PARAMS * const param)1033 tx_sv_dup_inc(pTHX_ SV* const sv, CLONE_PARAMS* const param) {
1034 return SvREFCNT_inc( sv_dup(sv, param) );
1035 }
1036 #endif
1037
1038 static int
tx_mg_dup(pTHX_ MAGIC * const mg,CLONE_PARAMS * const param)1039 tx_mg_dup(pTHX_ MAGIC* const mg, CLONE_PARAMS* const param){
1040 #ifdef USE_ITHREADS /* single threaded perl has no "xxx_dup()" APIs */
1041 tx_state_t* st = (tx_state_t*)mg->mg_ptr;
1042 tx_info_t* const proto_info = st->info;
1043 tx_code_t* const proto_code = st->code;
1044 U32 const len = st->code_len;
1045 U32 i;
1046
1047 Newx(st->code, len, tx_code_t);
1048 Newx(st->info, len, tx_info_t);
1049
1050 for(i = 0; i < len; i++) {
1051 U8 const oparg = tx_oparg[ proto_info[i].optype ];
1052 /* opcode */
1053 st->code[i].exec_code = proto_code[i].exec_code;
1054 if( oparg & TXARGf_SV ) {
1055 st->code[i].u_arg.sv = tx_sv_dup_inc(aTHX_ proto_code[i].u_arg.sv, param);
1056 }
1057 else if ( oparg & TXARGf_INT ) {
1058 st->code[i].u_arg.iv = proto_code[i].u_arg.iv;
1059 }
1060 else if( oparg & TXARGf_PC ) {
1061 st->code[i].u_arg.pc = proto_code[i].u_arg.pc;
1062 }
1063
1064 /* opinfo */
1065 st->info[i].optype = proto_info[i].optype;
1066 st->info[i].line = proto_info[i].line;
1067 st->info[i].file = tx_sv_dup_inc(aTHX_ proto_info[i].file, param);
1068 }
1069
1070 st->symbol = (HV*)tx_sv_dup_inc(aTHX_ (SV*)st->symbol, param);
1071 st->frames = (AV*)tx_sv_dup_inc(aTHX_ (SV*)st->frames, param);
1072 st->targ = tx_sv_dup_inc(aTHX_ st->targ, param);
1073 st->engine = tx_sv_dup_inc(aTHX_ st->engine, param);
1074 #else
1075 PERL_UNUSED_ARG(mg);
1076 PERL_UNUSED_ARG(param);
1077 #endif
1078 return 0;
1079 }
1080
1081
1082 static MGVTBL xslate_vtbl = { /* for identity */
1083 NULL, /* get */
1084 NULL, /* set */
1085 NULL, /* len */
1086 NULL, /* clear */
1087 tx_mg_free, /* free */
1088 NULL, /* copy */
1089 tx_mg_dup, /* dup */
1090 #ifdef MGf_LOCAL
1091 NULL, /* local */
1092 #endif
1093 };
1094
1095
1096 static void
tx_invoke_load_file(pTHX_ SV * const self,SV * const name,SV * const mtime,bool const from_include)1097 tx_invoke_load_file(pTHX_ SV* const self, SV* const name, SV* const mtime, bool const from_include) {
1098 dSP;
1099 ENTER;
1100 SAVETMPS;
1101
1102 PUSHMARK(SP);
1103 EXTEND(SP, 3);
1104 PUSHs(self);
1105 PUSHs(name);
1106 PUSHs(mtime ? mtime : &PL_sv_undef);
1107 PUSHs(boolSV(from_include));
1108 PUTBACK;
1109
1110 call_method("load_file", G_EVAL | G_VOID | G_DISCARD);
1111 if(TX_CATCH_ERROR()){
1112 dMY_CXT;
1113 SV* const msg = PL_diehook == MY_CXT.die_handler
1114 ? sv_2mortal(newRV_inc(sv_mortalcopy(ERRSV)))
1115 : ERRSV;
1116 tx_call_error_handler(aTHX_ MY_CXT.die_handler, msg);
1117 /* not reached */
1118 }
1119
1120 FREETMPS;
1121 LEAVE;
1122 }
1123
1124 static bool
tx_all_deps_are_fresh(pTHX_ AV * const tmpl,Time_t const cache_mtime)1125 tx_all_deps_are_fresh(pTHX_ AV* const tmpl, Time_t const cache_mtime) {
1126 I32 const len = AvFILLp(tmpl) + 1;
1127 I32 i;
1128 Stat_t st;
1129
1130 for(i = TXo_FULLPATH; i < len; i++) {
1131 SV* const deppath = AvARRAY(tmpl)[i];
1132
1133 if(SvROK(deppath)) {
1134 continue;
1135 }
1136
1137 //PerlIO_stdoutf("check deps: %"SVf" ...\n", deppath); // */
1138 if(PerlLIO_stat(SvPV_nolen_const(deppath), &st) < 0
1139 || st.st_mtime > cache_mtime) {
1140 SV* const main_cache = AvARRAY(tmpl)[TXo_CACHEPATH];
1141 /* compiled caches are no longer fresh, so it must be discarded */
1142
1143 if(i != TXo_FULLPATH && SvOK(main_cache)) {
1144 PerlLIO_unlink(SvPV_nolen_const(main_cache));
1145 }
1146 //PerlLIO_unlink(SvPV_nolen_const(AvARRAY(tmpl);
1147
1148 if (dump_load) {
1149 PerlIO_printf(PerlIO_stderr(),
1150 "#[XS] %"SVf": too old (%d < %d)\n",
1151 deppath, (int)cache_mtime, (int)st.st_mtime);
1152 }
1153 return FALSE;
1154 }
1155 else {
1156 if (dump_load) {
1157 PerlIO_printf(PerlIO_stderr(),
1158 "#[XS] %"SVf": fresh enough (%d >= %d)\n",
1159 deppath, (int)cache_mtime, (int)st.st_mtime);
1160 }
1161 }
1162 }
1163 return TRUE;
1164 }
1165
1166 static tx_state_t*
tx_load_template(pTHX_ SV * const self,SV * const name,bool const from_include)1167 tx_load_template(pTHX_ SV* const self, SV* const name, bool const from_include) {
1168 HV* hv;
1169 const char* why = NULL;
1170 HE* he;
1171 SV** svp;
1172 SV* sv;
1173 HV* ttable;
1174 AV* tmpl;
1175 MAGIC* mg;
1176 SV* cache_mtime;
1177 int retried = 0;
1178
1179 if (dump_load) {
1180 PerlIO_printf(PerlIO_stderr(),
1181 "#[XS] load_template(%"SVf")\n", name);
1182 }
1183
1184 if(!SvOK(name)) {
1185 why = "template name is invalid";
1186 goto err;
1187 }
1188
1189 assert( SvROK(self) && SvTYPE(SvRV(self)) == SVt_PVHV );
1190
1191 hv = (HV*)SvRV(self);
1192
1193 retry:
1194 if(retried > 1) {
1195 why = "retried reloading, but failed";
1196 goto err;
1197 }
1198
1199 /* validation by modified time (mtime) */
1200
1201 /* my $ttable = $self->{template} */
1202 svp = hv_fetchs(hv, "template", FALSE);
1203 if(!svp) {
1204 why = "template table is not found";
1205 goto err;
1206 }
1207
1208 sv = *svp;
1209 if(!(SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVHV)) {
1210 why = "template table is not a HASH reference";
1211 goto err;
1212 }
1213
1214 ttable = (HV*)SvRV(sv);
1215
1216 /* $tmpl = $ttable->{$name} */
1217 he = hv_fetch_ent(ttable, name, FALSE, 0U);
1218 if(!he) {
1219 tx_invoke_load_file(aTHX_ self, name, NULL, from_include);
1220 retried++;
1221 goto retry;
1222 }
1223
1224 sv = hv_iterval(ttable, he);
1225 if(!(SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV)) {
1226 why = "template entry is invalid";
1227 goto err;
1228 }
1229
1230 tmpl = (AV*)SvRV(sv);
1231 if(AvFILLp(tmpl) < (TXo_least_size-1)) {
1232 why = form("template entry is broken (size: %d < %d)",
1233 (int)AvFILLp(tmpl)+1, (int)TXo_least_size);
1234 goto err;
1235 }
1236
1237 mg = mgx_find(aTHX_ (SV*)tmpl, &xslate_vtbl);
1238 if(!mg) {
1239 croak("Xslate: Invalid template holder was passed");
1240 }
1241 /* check mtime */
1242
1243 cache_mtime = AvARRAY(tmpl)[TXo_MTIME];
1244
1245 /* NOTE: Ensure the life of the template object */
1246 sv_2mortal( (SV*)SvREFCNT_inc_simple_NN(tmpl) );
1247
1248 if(!SvOK(cache_mtime)) { /* non-checking mode (i.e. release mode) */
1249
1250 return (tx_state_t*)mg->mg_ptr;
1251 }
1252
1253 if (dump_load) {
1254 PerlIO_printf(PerlIO_stderr(),
1255 "#[XS] %"SVf" (mtime=%"SVf")\n", name, cache_mtime);
1256 }
1257
1258 if(retried > 0 /* if already retried, it should be valid */
1259 || tx_all_deps_are_fresh(aTHX_ tmpl, SvIVX(cache_mtime))) {
1260 return (tx_state_t*)mg->mg_ptr;
1261 }
1262 else {
1263 tx_invoke_load_file(aTHX_ self, name, cache_mtime, from_include);
1264 retried++;
1265 goto retry;
1266 }
1267
1268 err:
1269 croak("Xslate: Cannot load template %s: %s", tx_neat(aTHX_ name), why);
1270 }
1271
1272 static int
tx_macro_free(pTHX_ SV * const sv PERL_UNUSED_DECL,MAGIC * const mg)1273 tx_macro_free(pTHX_ SV* const sv PERL_UNUSED_DECL, MAGIC* const mg){
1274 CV* const xsub = (CV*)mg->mg_obj;
1275
1276 assert(SvTYPE(xsub) == SVt_PVCV);
1277 assert(CvXSUB(xsub) != NULL);
1278
1279 CvXSUBANY(xsub).any_ptr = NULL;
1280 return 0;
1281 }
1282
1283 static MGVTBL macro_vtbl = { /* identity */
1284 NULL, /* get */
1285 NULL, /* set */
1286 NULL, /* len */
1287 NULL, /* clear */
1288 tx_macro_free, /* free */
1289 NULL, /* copy */
1290 NULL, /* dup */
1291 #ifdef MGf_LOCAL
1292 NULL, /* local */
1293 #endif
1294 };
1295
1296
1297 static void
tx_my_cxt_init(pTHX_ pMY_CXT_ bool const cloning PERL_UNUSED_DECL)1298 tx_my_cxt_init(pTHX_ pMY_CXT_ bool const cloning PERL_UNUSED_DECL) {
1299 MY_CXT.depth = 0;
1300 MY_CXT.raw_stash = gv_stashpvs(TX_RAW_CLASS, GV_ADDMULTI);
1301 MY_CXT.macro_stash = gv_stashpvs(TX_MACRO_CLASS, GV_ADDMULTI);
1302 MY_CXT.warn_handler = SvREFCNT_inc_NN(
1303 (SV*)get_cv("Text::Xslate::Engine::_warn", GV_ADD));
1304 MY_CXT.die_handler = SvREFCNT_inc_NN(
1305 (SV*)get_cv("Text::Xslate::Engine::_die", GV_ADD));
1306 MY_CXT.make_error = SvREFCNT_inc_NN(
1307 (SV*)get_cv("Text::Xslate::Engine::make_error", GV_ADD));
1308 }
1309
1310 /* Because overloading stuff of old xsubpp didn't work,
1311 we need to copy them. */
1312 XS(XS_Text__Xslate__fallback); /* prototype to pass -Wmissing-prototypes */
XS(XS_Text__Xslate__fallback)1313 XS(XS_Text__Xslate__fallback)
1314 {
1315 dXSARGS;
1316 PERL_UNUSED_VAR(cv);
1317 PERL_UNUSED_VAR(items);
1318 XSRETURN_EMPTY;
1319 }
1320
1321 EXTERN_C XS(boot_Text__Xslate__Methods);
1322
1323 MODULE = Text::Xslate PACKAGE = Text::Xslate::Engine
1324
1325 PROTOTYPES: DISABLE
1326
1327 BOOT:
1328 {
1329 HV* const ops = get_hv("Text::Xslate::OPS", GV_ADDMULTI);
1330 MY_CXT_INIT;
1331 tx_my_cxt_init(aTHX_ aMY_CXT_ FALSE);
1332 tx_init_ops(aTHX_ ops);
1333
1334 {
1335 PUSHMARK(SP);
1336 boot_Text__Xslate__Methods(aTHX_ cv);
1337 }
1338 }
1339
1340 #ifdef USE_ITHREADS
1341
1342 void
CLONE(...)1343 CLONE(...)
1344 CODE:
1345 {
1346 MY_CXT_CLONE;
1347 tx_my_cxt_init(aTHX_ aMY_CXT_ FALSE);
1348 PERL_UNUSED_VAR(items);
1349 }
1350
1351 #endif
1352
1353 void
_register_builtin_methods(self,HV * hv)1354 _register_builtin_methods(self, HV* hv)
1355 CODE:
1356 {
1357 tx_register_builtin_methods(aTHX_ hv);
1358 }
1359
1360 void
_assemble(HV * self,AV * proto,SV * name,SV * fullpath,SV * cachepath,SV * mtime)1361 _assemble(HV* self, AV* proto, SV* name, SV* fullpath, SV* cachepath, SV* mtime)
1362 CODE:
1363 {
1364 dMY_CXT;
1365 dTX_optable;
1366 MAGIC* mg;
1367 HV* hv;
1368 HV* const ops = get_hv("Text::Xslate::OPS", GV_ADD);
1369 U32 const len = av_len(proto) + 1;
1370 U32 i;
1371 U16 oi_line; /* opinfo.line */
1372 SV* oi_file;
1373 tx_state_t st;
1374 AV* tmpl;
1375 SV* tobj;
1376 SV** svp;
1377 AV* macro = NULL;
1378
1379 TAINT_NOT; /* All the SVs we'll create here are safe */
1380
1381 Zero(&st, 1, tx_state_t);
1382
1383 svp = hv_fetchs(self, "template", FALSE);
1384 if(!(svp && SvROK(*svp) && SvTYPE(SvRV(*svp)) == SVt_PVHV)) {
1385 croak("The xslate instance has no template table");
1386 }
1387 hv = (HV*)SvRV(*svp);
1388
1389 if(!SvOK(name)) {
1390 croak("Undefined template name is invalid");
1391 }
1392
1393 /* fetch the template object from $self->{template}{$name} */
1394 tobj = hv_iterval(hv, hv_fetch_ent(hv, name, TRUE, 0U));
1395
1396 tmpl = newAV();
1397 /* store the template object to $self->{template}{$name} */
1398 sv_setsv(tobj, sv_2mortal(newRV_noinc((SV*)tmpl)));
1399 av_extend(tmpl, TXo_least_size - 1);
1400
1401 sv_setsv(*av_fetch(tmpl, TXo_MTIME, TRUE), mtime);
1402 sv_setsv(*av_fetch(tmpl, TXo_CACHEPATH, TRUE), cachepath);
1403 sv_setsv(*av_fetch(tmpl, TXo_FULLPATH, TRUE), fullpath);
1404
1405 /* prepare function table */
1406 svp = hv_fetchs(self, "function", FALSE);
1407 TAINT_NOT;
1408
1409 if(!( SvROK(*svp) && SvTYPE(SvRV(*svp)) == SVt_PVHV )) {
1410 croak("Function table must be a HASH reference");
1411 }
1412 /* $self->{function} must be copied
1413 because it might be changed per templates */
1414 st.symbol = newHVhv( (HV*)SvRV(*svp) );
1415
1416 st.tmpl = tmpl;
1417 st.engine = newRV_inc((SV*)self);
1418 sv_rvweaken(st.engine);
1419
1420 st.hint_size = TX_HINT_SIZE;
1421
1422 st.sa = &PL_sv_undef;
1423 st.sb = &PL_sv_undef;
1424 st.targ = newSV(0);
1425
1426 /* stack frame */
1427 st.frames = newAV();
1428 st.current_frame = -1;
1429
1430 Newxz(st.info, len + 1, tx_info_t);
1431 st.info[len].line = (U16)-1; /* invalid value */
1432 st.info[len].file = SvREFCNT_inc_simple_NN(name);
1433
1434 Newxz(st.code, len, tx_code_t);
1435
1436 st.code_len = len;
1437 st.pc = &st.code[0];
1438
1439 mg = sv_magicext((SV*)tmpl, NULL, PERL_MAGIC_ext,
1440 &xslate_vtbl, (char*)&st, sizeof(st));
1441 mg->mg_flags |= MGf_DUP;
1442
1443 oi_line = 0;
1444 oi_file = name;
1445
1446 for(i = 0; i < len; i++) {
1447 SV* const code = *av_fetch(proto, i, TRUE);
1448 if(SvROK(code) && SvTYPE(SvRV(code)) == SVt_PVAV) {
1449 AV* const av = (AV*)SvRV(code);
1450 SV* const opname = *av_fetch(av, 0, TRUE);
1451 SV** const arg = av_fetch(av, 1, FALSE);
1452 SV** const line = av_fetch(av, 2, FALSE);
1453 SV** const file = av_fetch(av, 3, FALSE);
1454 HE* const he = hv_fetch_ent(ops, opname, FALSE, 0U);
1455 IV opnum;
1456
1457 if(!he){
1458 croak("Oops: Unknown opcode '%"SVf"' on [%d]", opname, (int)i);
1459 }
1460
1461 opnum = SvIVx(hv_iterval(ops, he));
1462 st.code[i].exec_code = tx_optable[opnum];
1463 if(tx_oparg[opnum] & TXARGf_SV) {
1464 if(!arg) {
1465 croak("Oops: Opcode %"SVf" must have an argument on [%d]", opname, (int)i);
1466 }
1467
1468 if(tx_oparg[opnum] & TXARGf_KEY) { /* shared sv */
1469 STRLEN len;
1470 const char* const pv = SvPV_const(*arg, len);
1471 st.code[i].u_arg.sv = newSVpvn_share(pv, SvUTF8(*arg) ? -len : len, 0U);
1472 }
1473 else if(tx_oparg[opnum] & TXARGf_INT) { /* sviv */
1474 SvIV_please(*arg);
1475 st.code[i].u_arg.sv = SvIsUV(*arg)
1476 ? newSVuv(SvUV(*arg))
1477 : newSViv(SvIV(*arg));
1478 }
1479 else { /* normal sv */
1480 st.code[i].u_arg.sv = newSVsv(*arg);
1481 }
1482 }
1483 else if(tx_oparg[opnum] & TXARGf_INT) {
1484 st.code[i].u_arg.iv = SvIV(*arg);
1485 }
1486 else if(tx_oparg[opnum] & TXARGf_PC) {
1487 /* calculate relational addresses to absolute addresses */
1488 UV const abs_pos = (UV)(i + SvIV(*arg));
1489
1490 if(abs_pos >= (UV)len) {
1491 croak("Oops: goto address %"IVdf" is out of range (must be 0 <= addr <= %"IVdf")",
1492 SvIV(*arg), (IV)len);
1493 }
1494 st.code[i].u_arg.pc = TX_POS2PC(&st, abs_pos);
1495 }
1496 else {
1497 if(arg && SvOK(*arg)) {
1498 croak("Oops: Opcode %"SVf" has an extra argument %s on [%d]",
1499 opname, tx_neat(aTHX_ *arg), (int)i);
1500 }
1501 }
1502
1503 /* setup opinfo */
1504 if(line && SvOK(*line)) {
1505 oi_line = (U16)SvUV(*line);
1506 }
1507 if(file && SvOK(*file) && !sv_eq(*file, oi_file)) {
1508 oi_file = sv_mortalcopy(*file);
1509 }
1510 st.info[i].optype = (U16)opnum;
1511 st.info[i].line = oi_line;
1512 st.info[i].file = SvREFCNT_inc_simple_NN(oi_file);
1513
1514 /* special cases */
1515 if(opnum == TXOP_macro_begin) {
1516 SV* const name = st.code[i].u_arg.sv;
1517 SV* const ent = hv_iterval(st.symbol,
1518 hv_fetch_ent(st.symbol, name, TRUE, 0U));
1519
1520 if(!sv_true(ent)) {
1521 SV* mref;
1522 macro = newAV();
1523 mref = sv_2mortal(newRV_noinc((SV*)macro));
1524 sv_bless(mref, MY_CXT.macro_stash);
1525 sv_setsv(ent, mref);
1526
1527 (void)av_store(macro, TXm_OUTER, newSViv(0));
1528 (void)av_store(macro, TXm_NARGS, newSViv(0));
1529 (void)av_store(macro, TXm_ADDR, newSVuv(PTR2UV(TX_POS2PC(&st, i))));
1530 (void)av_store(macro, TXm_NAME, name);
1531 st.code[i].u_arg.sv = NULL;
1532 }
1533 else { /* already defined */
1534 macro = NULL;
1535 }
1536 }
1537 else if(opnum == TXOP_macro_nargs) {
1538 if(macro) {
1539 /* the number of outer lexical variables */
1540 (void)av_store(macro, TXm_NARGS, st.code[i].u_arg.sv);
1541 st.code[i].u_arg.sv = NULL;
1542 }
1543 }
1544 else if(opnum == TXOP_macro_outer) {
1545 if(macro) {
1546 /* the number of outer lexical variables */
1547 (void)av_store(macro, TXm_OUTER, st.code[i].u_arg.sv);
1548 st.code[i].u_arg.sv = NULL;
1549 }
1550 }
1551 else if(opnum == TXOP_depend) {
1552 /* add a dependent file to the tmpl object */
1553 av_push(tmpl, st.code[i].u_arg.sv);
1554 st.code[i].u_arg.sv = NULL;
1555 }
1556 }
1557 else {
1558 croak("Oops: Broken code found on [%d]", (int)i);
1559 }
1560 } /* end for each code */
1561 }
1562
1563 void
1564 render(SV* self, SV* source, SV* vars = &PL_sv_undef)
1565 ALIAS:
1566 render = 0
1567 render_string = 1
1568 CODE:
1569 {
1570 dMY_CXT;
1571 tx_state_t* st;
1572
1573 TAINT_NOT; /* All the SVs we'll create here are safe */
1574
1575 /* $_[0]: engine */
1576 if(!(SvROK(self) && SvTYPE(SvRV(self)) == SVt_PVHV)) {
1577 croak("Xslate: Invalid xslate instance: %s",
1578 tx_neat(aTHX_ self));
1579 }
1580
1581 /* $_[1]: template source */
1582 if(ix == 1) { /* render_string() */
1583 dXSTARG;
1584 PUSHMARK(SP);
1585 EXTEND(SP, 2);
1586 PUSHs(self);
1587 PUSHs(source);
1588 PUTBACK;
1589 call_method("load_string", G_VOID | G_DISCARD);
1590 SPAGAIN;
1591 source = TARG;
1592 sv_setpvs(source, "<string>");
1593 }
1594
1595 SvGETMAGIC(source);
1596 if(!SvOK(source)) {
1597 croak("Xslate: Template name is not given");
1598 }
1599
1600 /* $_[2]: template variable */
1601 if(!SvOK(vars)) {
1602 vars = sv_2mortal(newRV_noinc((SV*)newHV()));
1603 }
1604 else if(!(SvROK(vars) && SvTYPE(SvRV(vars)) == SVt_PVHV)) {
1605 croak("Xslate: Template variables must be a HASH reference, not %s",
1606 tx_neat(aTHX_ vars));
1607 }
1608 if(SvOBJECT(SvRV(vars))) {
1609 Perl_warner(aTHX_ packWARN(WARN_MISC),
1610 "Xslate: Template variables must be a HASH reference, not %s",
1611 tx_neat(aTHX_ vars));
1612 }
1613
1614 st = tx_load_template(aTHX_ self, source, FALSE);
1615
1616 /* local $SIG{__WARN__} = \&warn_handler */
1617 if (PL_warnhook != MY_CXT.warn_handler) {
1618 SAVEGENERICSV(PL_warnhook);
1619 MY_CXT.orig_warn_handler = PL_warnhook;
1620 PL_warnhook = SvREFCNT_inc_NN(MY_CXT.warn_handler);
1621 }
1622
1623 /* local $SIG{__DIE__} = \&die_handler */
1624 if (PL_diehook != MY_CXT.die_handler) {
1625 SAVEGENERICSV(PL_diehook);
1626 MY_CXT.orig_die_handler = PL_diehook;
1627 PL_diehook = SvREFCNT_inc_NN(MY_CXT.die_handler);
1628 }
1629
1630 {
1631 AV* mainframe = tx_push_frame(aTHX_ st); // frame[0]
1632 SV* result = sv_newmortal();
1633 sv_grow(result, st->hint_size + TX_HINT_SIZE);
1634 SvPOK_on(result);
1635
1636 av_store(mainframe, TXframe_NAME, SvREFCNT_inc_simple_NN(source));
1637 av_store(mainframe, TXframe_RETADDR, newSVuv(st->code_len));
1638 tx_execute(aTHX_ aMY_CXT_ st, result, (HV*)SvRV(vars));
1639 ST(0) = result;
1640 }
1641 }
1642
1643 void
validate(SV * self,SV * source)1644 validate(SV* self, SV* source)
1645 CODE:
1646 {
1647 TAINT_NOT; /* All the SVs we'll create here are safe */
1648
1649 /* $_[0]: engine */
1650 if(!(SvROK(self) && SvTYPE(SvRV(self)) == SVt_PVHV)) {
1651 croak("Xslate: Invalid xslate instance: %s",
1652 tx_neat(aTHX_ self));
1653 }
1654
1655 SvGETMAGIC(source);
1656 if(!SvOK(source)) {
1657 croak("Xslate: Template name is not given");
1658 }
1659
1660 tx_load_template(aTHX_ self, source, FALSE);
1661 }
1662
1663 void
current_engine(klass)1664 current_engine(klass)
1665 CODE:
1666 {
1667 dMY_CXT;
1668 tx_state_t* const st = MY_CXT.current_st;
1669 SV* retval;
1670 if(st) {
1671 if(ix == 0) { /* current_engine */
1672 retval = st->engine;
1673 }
1674 else if(ix == 1) { /* current_vars */
1675 retval = sv_2mortal(newRV_inc((SV*)st->vars));
1676 }
1677 else { /* current_file / current_line */
1678 const tx_info_t* const info
1679 = &(st->info[ TX_PC2POS(st, st->pc) ]);
1680
1681 retval = (ix == 2)
1682 ? info->file
1683 : sv_2mortal(newSViv(info->line));
1684 }
1685 }
1686 else {
1687 retval = &PL_sv_undef;
1688 }
1689 ST(0) = retval;
1690 }
1691 ALIAS:
1692 current_engine = 0
1693 current_vars = 1
1694 current_file = 2
1695 current_line = 3
1696
1697 void
print(klass,...)1698 print(klass, ...)
1699 CODE:
1700 {
1701 dMY_CXT;
1702 int i;
1703 tx_state_t* const st = MY_CXT.current_st;
1704 if(!st) {
1705 croak("You cannot call print() method outside render()");
1706 }
1707
1708 for(i = 1; i < items; i++) {
1709 tx_print(aTHX_ st, ST(i));
1710 }
1711 XSRETURN_NO; /* return false as an empty string */
1712 }
1713
1714 void
_warn(SV * msg)1715 _warn(SV* msg)
1716 ALIAS:
1717 _warn = 0
1718 _die = 1
1719 CODE:
1720 {
1721 dMY_CXT;
1722 tx_state_t* const st = MY_CXT.current_st;
1723 SV* engine;
1724 AV* cframe;
1725 SV* name;
1726 SV* full_message;
1727 SV** svp;
1728 CV* handler;
1729 UV pc_pos;
1730 SV* file;
1731
1732
1733 /* restore error handlers to avoid recursion */
1734 SAVESPTR(PL_warnhook);
1735 SAVESPTR(PL_diehook);
1736 PL_warnhook = MY_CXT.orig_warn_handler;
1737 PL_diehook = MY_CXT.orig_die_handler;
1738 msg = sv_mortalcopy(msg);
1739
1740 if(!st) {
1741 croak("%"SVf, msg);
1742 }
1743
1744
1745 engine = st->engine;
1746 cframe = TX_current_framex(st);
1747 name = AvARRAY(cframe)[TXframe_NAME];
1748
1749 svp = (ix == 0)
1750 ? hv_fetchs((HV*)SvRV(engine), "warn_handler", FALSE)
1751 : hv_fetchs((HV*)SvRV(engine), "die_handler", FALSE);
1752
1753 if(svp && SvOK(*svp)) {
1754 HV* stash;
1755 GV* gv;
1756 handler = sv_2cv(*svp, &stash, &gv, 0);
1757 }
1758 else {
1759 handler = NULL;
1760 }
1761
1762 pc_pos = TX_PC2POS(st, st->pc);
1763 file = st->info[ pc_pos ].file;
1764 if(strEQ(SvPV_nolen_const(file), "<string>")) {
1765 svp = hv_fetchs((HV*)SvRV(engine), "string_buffer", FALSE);
1766 if(svp) {
1767 file = sv_2mortal(newRV_inc(*svp));
1768 }
1769 }
1770 /* TODO: append the stack info to msg */
1771 /* $full_message = make_error(engine, msg, file, line, vm_pos) */
1772 PUSHMARK(SP);
1773 EXTEND(SP, 6);
1774 PUSHs(sv_mortalcopy(engine)); /* XXX: avoid premature free */
1775 PUSHs(msg);
1776 PUSHs(file);
1777 mPUSHi(st->info[ pc_pos ].line);
1778 if(tx_verbose(aTHX_ st) >= 3) {
1779 if(!SvOK(name)) { // FIXME: something's wrong
1780 name = newSVpvs_flags("(oops)", SVs_TEMP);
1781 }
1782 mPUSHs(newSVpvf("&%"SVf"[%"UVuf"]", name, pc_pos));
1783 }
1784 PUTBACK;
1785 call_sv(MY_CXT.make_error, G_SCALAR);
1786 SPAGAIN;
1787 full_message = POPs;
1788 PUTBACK;
1789
1790 if(ix == 0) { /* warn */
1791 /* handler can ignore warnings */
1792 if(handler) {
1793 PUSHMARK(SP);
1794 XPUSHs(full_message);
1795 PUTBACK;
1796 call_sv((SV*)handler, G_VOID | G_DISCARD);
1797 /* handler can ignore errors */
1798 }
1799 else {
1800 warn("%"SVf, full_message);
1801 }
1802 }
1803 else {
1804 if(handler) {
1805 PUSHMARK(SP);
1806 XPUSHs(full_message);
1807 PUTBACK;
1808 call_sv((SV*)handler, G_VOID | G_DISCARD);
1809 /* handler cannot ignore errors */
1810 }
1811 croak("%"SVf, full_message); /* must die */
1812 /* not reached */
1813 }
1814 }
1815
1816 MODULE = Text::Xslate PACKAGE = Text::Xslate::Util
1817
1818 void
mark_raw(SV * str)1819 mark_raw(SV* str)
1820 CODE:
1821 {
1822 ST(0) = tx_mark_raw(aTHX_ str);
1823 }
1824
1825 void
unmark_raw(SV * str)1826 unmark_raw(SV* str)
1827 CODE:
1828 {
1829 ST(0) = tx_unmark_raw(aTHX_ str);
1830 }
1831
1832
1833 void
html_escape(SV * str)1834 html_escape(SV* str)
1835 CODE:
1836 {
1837 ST(0) = tx_html_escape(aTHX_ str);
1838 }
1839
1840 void
uri_escape(SV * str)1841 uri_escape(SV* str)
1842 CODE:
1843 {
1844 ST(0) = tx_uri_escape(aTHX_ str);
1845 }
1846
1847 void
is_array_ref(SV * sv)1848 is_array_ref(SV* sv)
1849 CODE:
1850 {
1851 ST(0) = boolSV( tx_sv_is_array_ref(aTHX_ sv));
1852 }
1853
1854 void
is_hash_ref(SV * sv)1855 is_hash_ref(SV* sv)
1856 CODE:
1857 {
1858 ST(0) = boolSV( tx_sv_is_hash_ref(aTHX_ sv));
1859 }
1860
1861 void
is_code_ref(SV * sv)1862 is_code_ref(SV* sv)
1863 CODE:
1864 {
1865 ST(0) = boolSV( tx_sv_is_code_ref(aTHX_ sv));
1866 }
1867
1868 void
merge_hash(SV * base,SV * value)1869 merge_hash(SV* base, SV* value)
1870 CODE:
1871 {
1872 ST(0) = tx_merge_hash(aTHX_ NULL, base, value);
1873 }
1874
1875 MODULE = Text::Xslate PACKAGE = Text::Xslate::Type::Raw
1876
1877 BOOT:
1878 {
1879 SV* as_string;
1880 /* overload stuff */
1881 PL_amagic_generation++;
1882 sv_setsv(
1883 get_sv( TX_RAW_CLASS "::()", TRUE ),
1884 &PL_sv_yes
1885 );
1886 (void)newXS( TX_RAW_CLASS "::()",
1887 XS_Text__Xslate__fallback, file);
1888
1889 /* *{'(""'} = \&as_string */
1890 as_string = sv_2mortal(newRV_inc(
1891 (SV*)get_cv( TX_RAW_CLASS "::as_string", GV_ADD)));
1892 sv_setsv_mg(
1893 (SV*)gv_fetchpvs( TX_RAW_CLASS "::(\"\"", GV_ADDMULTI, SVt_PVCV),
1894 as_string);
1895 }
1896
1897 void
new(SV * klass,SV * str)1898 new(SV* klass, SV* str)
1899 CODE:
1900 {
1901 if(SvROK(klass)) {
1902 croak("You cannot call %s->new() as an instance method", TX_RAW_CLASS);
1903 }
1904 if(strNE(SvPV_nolen_const(klass), TX_RAW_CLASS)) {
1905 croak("You cannot extend %s", TX_RAW_CLASS);
1906 }
1907 ST(0) = tx_mark_raw(aTHX_ tx_unmark_raw(aTHX_ str));
1908 }
1909
1910 void
as_string(SV * self,...)1911 as_string(SV* self, ...)
1912 CODE:
1913 {
1914 if(!SvROK(self)) {
1915 croak("You cannot call %s->as_string() as a class method", TX_RAW_CLASS);
1916 }
1917 ST(0) = tx_unmark_raw(aTHX_ self);
1918 }
1919
1920 MODULE = Text::Xslate PACKAGE = Text::Xslate::Type::Macro
1921
1922
1923 BOOT:
1924 {
1925 SV* code_ref;
1926 /* overload stuff */
1927 PL_amagic_generation++;
1928 sv_setsv(
1929 get_sv( TX_MACRO_CLASS "::()", TRUE ),
1930 &PL_sv_yes
1931 );
1932 (void)newXS( TX_MACRO_CLASS "::()",
1933 XS_Text__Xslate__fallback, file);
1934
1935 /* *{'(&{}'} = \&as_code_ref */
1936 code_ref = sv_2mortal(newRV_inc((SV*)get_cv( TX_MACRO_CLASS "::as_code_ref", GV_ADD)));
1937 sv_setsv_mg(
1938 (SV*)gv_fetchpvs( TX_MACRO_CLASS "::(&{}", GV_ADDMULTI, SVt_PVCV),
1939 code_ref);
1940
1941 // debug flag
1942 code_ref = sv_2mortal(newRV_inc((SV*)get_cv( "Text::Xslate::Engine::_DUMP_LOAD", GV_ADD)));
1943 {
1944 dSP;
1945 PUSHMARK(SP);
1946 call_sv(code_ref, G_SCALAR);
1947 SPAGAIN;
1948 dump_load = sv_true(POPs);
1949 PUTBACK;
1950 }
1951 }
1952
1953 CV*
as_code_ref(SV * self,...)1954 as_code_ref(SV* self, ...)
1955 CODE:
1956 {
1957 /* the macro object is responsible to its xsub's refcount */
1958 MAGIC* mg;
1959 CV* xsub;
1960
1961 if(!tx_sv_is_macro(aTHX_ self)) {
1962 croak("Not a macro object: %s", tx_neat(aTHX_ self));
1963 }
1964
1965 mg = mgx_find(aTHX_ SvRV(self), ¯o_vtbl);
1966 if(!mg) {
1967 xsub = newXS(NULL, XS_Text__Xslate__macrocall, __FILE__);
1968 sv_magicext(SvRV(self), (SV*)xsub, PERL_MAGIC_ext, ¯o_vtbl,
1969 NULL, 0);
1970 SvREFCNT_dec(xsub); /* refcnt++ in sv_magicext */
1971 CvXSUBANY(xsub).any_ptr = (void*)self;
1972 }
1973 else {
1974 xsub = (CV*)mg->mg_obj;
1975 assert(xsub);
1976 assert(SvTYPE(xsub) == SVt_PVCV);
1977 }
1978 RETVAL = xsub;
1979 }
1980 OUTPUT:
1981 RETVAL
1982