File Coverage

QwComments.xs
Criterion Covered Total %
statement 88 91 96.7
branch 52 62 83.8
condition n/a
subroutine n/a
pod n/a
total 140 153 91.5


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5             #include "ppport.h"
6             #include "lex_read_unichar.inc.c"
7             #include "wrap_keyword_plugin.inc.c"
8              
9              
10             STATIC SV *hint_key_sv;
11              
12              
13             #define is_syntax_enabled() SvTRUE( cop_hints_fetch_sv( PL_curcop, hint_key_sv, 0, 0 ) )
14              
15              
16 5           STATIC void croak_missing_terminator( pTHX_ I32 edelim ) {
17             #define croak_missing_terminator( a ) croak_missing_terminator( aTHX_ a )
18             char buf[ 3 ];
19             char quote;
20              
21 5 50         if ( edelim == -1 )
22 0           Perl_croak( aTHX_ "qw not terminated anywhere before EOF" );
23              
24 5 50         if ( edelim >= 0x80 )
25             /* Suboptimal output format */
26 0           Perl_croak( aTHX_ "Can't find qw terminator U+%"UVXf" anywhere before EOF", (UV)edelim );
27              
28 5 50         if ( isCNTRL( edelim ) ) {
    100          
29 1           buf[ 0 ] = '^';
30 1 50         buf[ 1 ] = (char)toCTRL( edelim );
31 1           buf[ 2 ] = '\0';
32 1           quote = '"';
33             } else {
34 4           buf[ 0 ] = (char)edelim;
35 4           buf[ 1 ] = '\0';
36 4 50         quote = edelim == '"' ? '\'' : '"';
37             }
38              
39 5           Perl_croak( aTHX_ "Can't find qw terminator %c%s%c anywhere before EOF", quote, buf, quote );
40             }
41              
42              
43             /* sv is assumed to contain a string (and nothing else). */
44             /* sv is assumed to have no magic. */
45 328           STATIC void append_char_to_word( pTHX_ SV *word_sv, UV c ) {
46             #define append_char_to_word( a, b ) append_char_to_word( aTHX_ a, b )
47             char buf[ UTF8_MAXBYTES + 1 ]; /* I wonder why the "+ 1". */
48             STRLEN len;
49 328 50         if ( SvUTF8( word_sv ) || c > 255 ) {
    100          
50 1           len = (char*)uvchr_to_utf8( (U8*)buf, c ) - buf;
51 1           sv_utf8_upgrade_flags_grow( word_sv, 0, len+1 );
52             } else {
53 327           len = 1;
54 327           buf[ 0 ] = (char)c;
55             }
56              
57 328           sv_catpvn_nomg( word_sv, buf, len );
58 328           }
59              
60              
61             /* sv is assumed to contain a string (and nothing else). */
62             /* sv is assumed to have no magic. */
63             /* The sv's length is reduced to zero length and the UTF8 flag is turned off. */
64 203           STATIC void append_word_to_list( pTHX_ OP **list_op_ptr, SV *word_sv ) {
65             #define append_word_to_list( a, b ) append_word_to_list( aTHX_ a, b )
66 203           STRLEN len = SvCUR( word_sv );
67 203 100         if ( len ) {
68 86           SV* sv_copy = newSV( len );
69 86           sv_copypv( sv_copy, word_sv );
70 86           *list_op_ptr = op_append_elem( OP_LIST, *list_op_ptr, newSVOP( OP_CONST, 0, sv_copy ) );
71              
72 86           SvCUR_set( word_sv, 0 );
73 86           SvUTF8_off( word_sv );
74             }
75 203           }
76              
77              
78 63           STATIC OP* parse_qw( pTHX ) {
79             #define parse_qw() parse_qw( aTHX )
80             I32 sdelim;
81             I32 edelim;
82             IV depth;
83 63           OP *list_op = NULL;
84 63           SV *word_sv = newSVpvn( "", 0 );
85 63           int warned_comma = !ckWARN( WARN_QW );
86              
87 63           lex_read_space( 0 );
88              
89 63           sdelim = lex_read_unichar( 0 );
90 63 50         if ( sdelim == -1 )
91 0           croak_missing_terminator( -1 );
92              
93             { // Find corresponding closing delimiter.
94             char *p;
95 63 50         if ( sdelim && ( p = strchr( "([{< )]}> )]}>", sdelim ) ) )
    100          
96 56           edelim = *( p + 5 );
97             else
98 7           edelim = sdelim;
99             }
100              
101 63           depth = 1;
102 471           for (;;) {
103 534           I32 c = lex_peek_unichar( 0 );
104              
105 536           REDO:
106 536 100         if ( c == -1 )
107 5           croak_missing_terminator( edelim );
108              
109 531 100         if ( c == edelim ) {
110 63           lex_read_unichar( 0 );
111 63 100         if ( --depth ) {
112 5           append_char_to_word( word_sv, c );
113             } else {
114 58           append_word_to_list( &list_op, word_sv );
115 58           break;
116             }
117             }
118 468 100         else if ( c == sdelim ) {
119 5           lex_read_unichar( 0 );
120 5           ++depth;
121 5           append_char_to_word( word_sv, c );
122             }
123 463 100         else if ( c == '\\' ) {
124 7           lex_read_unichar( 0 );
125 7           c = lex_peek_unichar( 0 );
126 7 100         if ( c != sdelim && c != edelim && c != '\\' && c != '#' ) {
    100          
    100          
    100          
127 2           append_char_to_word( word_sv, '\\' );
128 2           goto REDO;
129             }
130              
131 5           lex_read_unichar( 0 );
132 5           append_char_to_word( word_sv, c );
133             }
134 456 50         else if ( c == '#' || isSPACE( c ) ) {
    100          
    100          
135 145           append_word_to_list( &list_op, word_sv );
136 145           lex_read_space( 0 );
137             }
138             else {
139 311 100         if ( c == ',' && !warned_comma ) {
    100          
140 2           Perl_warner( aTHX_ packWARN( WARN_QW ), "Possible attempt to separate words with commas" );
141 2           ++warned_comma;
142             }
143              
144 311           lex_read_unichar( 0 );
145 311           append_char_to_word( word_sv, c );
146             }
147             }
148              
149 58           SvREFCNT_dec( word_sv );
150              
151 58 100         if ( !list_op )
152 3           list_op = newNULLLIST();
153              
154 58           list_op->op_flags |= OPf_PARENS;
155 58           return list_op;
156             }
157              
158              
159             STATIC Perl_keyword_plugin_t next_keyword_plugin = NULL;
160             #define next_keyword_plugin( a, b, c ) next_keyword_plugin( aTHX_ a, b, c )
161              
162              
163 37724           STATIC int my_keyword_plugin( pTHX_ char *keyword_ptr, STRLEN keyword_len, OP **op_ptr ) {
164 37724 100         if ( is_syntax_enabled() ) {
165 258 100         if ( memEQs( keyword_ptr, keyword_len, "qw" ) ) {
    100          
166 63           *op_ptr = parse_qw();
167 58           return KEYWORD_PLUGIN_EXPR;
168             }
169             }
170              
171 37661           return next_keyword_plugin( keyword_ptr, keyword_len, op_ptr );
172             }
173              
174              
175             /* ======================================== */
176              
177             MODULE = Syntax::Feature::QwComments PACKAGE = Syntax::Feature::QwComments
178              
179              
180             void
181             hint_key()
182             PPCODE:
183 28           SvREFCNT_inc( hint_key_sv );
184 28 50         XPUSHs( hint_key_sv );
185 28           XSRETURN( 1 );
186              
187              
188             BOOT:
189             {
190 7           wrap_keyword_plugin( my_keyword_plugin, &next_keyword_plugin );
191              
192 7           hint_key_sv = newSVpvs( "Syntax::Feature::QwComments::qw" );
193 7           SvREADONLY_on( hint_key_sv );
194             }