File Coverage

hax/lexer-additions.c.inc
Criterion Covered Total %
statement 59 69 85.5
branch 52 74 70.2
condition n/a
subroutine n/a
pod n/a
total 111 143 77.6


line stmt bran cond sub pod time code
1             /* vi: set ft=c : */
2              
3             /* Perls before 5.18 lack isIDCONT_uni, but baring minor differences of weird
4             * Unicode characters, isALNUM_uni is close enough
5             */
6             #ifndef isIDCONT_uni
7             #define isIDCONT_uni(c) isALNUM_uni(c)
8             #endif
9              
10             #define sv_cat_c(sv, c) MY_sv_cat_c(aTHX_ sv, c)
11 18           static void MY_sv_cat_c(pTHX_ SV *sv, U32 c)
12             {
13             char ds[UTF8_MAXBYTES + 1], *d;
14 18           d = (char *)uvchr_to_utf8((U8 *)ds, c);
15 18 50         if (d - ds > 1) {
16 0           sv_utf8_upgrade(sv);
17             }
18 18           sv_catpvn(sv, ds, d - ds);
19 18           }
20              
21             #define lex_consume(s) MY_lex_consume(aTHX_ s)
22             static int MY_lex_consume(pTHX_ char *s)
23             {
24             /* I want strprefix() */
25             size_t i;
26             for(i = 0; s[i]; i++) {
27             if(s[i] != PL_parser->bufptr[i])
28             return 0;
29             }
30              
31             lex_read_to(PL_parser->bufptr + i);
32             return i;
33             }
34              
35             enum {
36             LEX_IDENT_PACKAGENAME = (1<<0),
37             };
38              
39             #define lex_scan_ident( ) MY_lex_scan_ident(aTHX_ 0)
40             #define lex_scan_packagename() MY_lex_scan_ident(aTHX_ LEX_IDENT_PACKAGENAME)
41 34           static SV *MY_lex_scan_ident(pTHX_ int flags)
42             {
43             I32 c;
44             bool at_start = TRUE;
45              
46 34           char *ident = PL_parser->bufptr;
47              
48 127 50         while((c = lex_peek_unichar(0))) {
49 127 100         if(at_start ? isIDFIRST_uni(c) : isALNUM_uni(c))
    50          
    50          
    100          
    50          
    50          
    100          
    100          
50             at_start = FALSE;
51             /* TODO: This sucks in the case of a false Foo:Bar match */
52 36 100         else if((flags & LEX_IDENT_PACKAGENAME) && (c == ':')) {
    100          
53 2           lex_read_unichar(0);
54 2 50         if(lex_read_unichar(0) != ':')
55 0           croak("Expected colon to be followed by another in package name");
56             }
57             else
58             break;
59              
60 93           lex_read_unichar(0);
61             }
62              
63 34           STRLEN len = PL_parser->bufptr - ident;
64 34 100         if(!len)
65             return NULL;
66              
67 25           SV *ret = newSVpvn(ident, len);
68 25 50         if(lex_bufutf8())
69 0           SvUTF8_on(ret);
70              
71             return ret;
72             }
73              
74             #define lex_scan_attrval_into(name, val) MY_lex_scan_attrval_into(aTHX_ name, val)
75 10           static bool MY_lex_scan_attrval_into(pTHX_ SV *name, SV *val)
76             {
77             /* TODO: really want lex_scan_ident_into() */
78 10           SV *n = lex_scan_ident();
79 10 100         if(!n)
80             return FALSE;
81              
82 7           sv_setsv(name, n);
83             SvREFCNT_dec(n);
84              
85 7 50         if(name != val)
86 7           SvPOK_off(val);
87              
88             /* Do not read space here as space is not allowed between NAME(ARGS) */
89              
90 7 100         if(lex_peek_unichar(0) != '(')
91             return TRUE;
92              
93 2           lex_read_unichar(0);
94 2 50         if(name == val)
95 0           sv_cat_c(val, '(');
96             else
97 2           sv_setpvs(val, "");
98              
99             int count = 1;
100 2           I32 c = lex_peek_unichar(0);
101 6 100         while(count && c != -1) {
102 4 50         if(c == '(')
103 0           count++;
104 4 100         if(c == ')')
105 2           count--;
106 4 50         if(c == '\\') {
107             /* The next char does not bump count even if it is ( or );
108             * the \\ is still captured
109             */
110 0           sv_cat_c(val, lex_read_unichar(0));
111 0           c = lex_peek_unichar(0);
112 0 0         if(c == -1)
113             goto unterminated;
114             }
115              
116             /* Don't append final closing ')' on split name/val */
117 4 100         if(count || (name == val))
118 2           sv_cat_c(val, c);
119 4           lex_read_unichar(0);
120              
121 4           c = lex_peek_unichar(0);
122             }
123              
124 2 50         if(c == -1)
125             return FALSE;
126              
127 2           return TRUE;
128              
129             unterminated:
130 0           croak("Unterminated attribute parameter in attribute list");
131             }
132              
133             #define lex_scan_attr() MY_lex_scan_attr(aTHX)
134             static SV *MY_lex_scan_attr(pTHX)
135             {
136             SV *ret = newSV(0);
137             if(MY_lex_scan_attrval_into(aTHX_ ret, ret))
138             return ret;
139              
140             SvREFCNT_dec(ret);
141             return NULL;
142             }
143              
144             #define lex_scan_attrs(compcv) MY_lex_scan_attrs(aTHX_ compcv)
145             static OP *MY_lex_scan_attrs(pTHX_ CV *compcv)
146             {
147             /* Attributes are supplied to newATTRSUB() as an OP_LIST containing
148             * OP_CONSTs, one attribute in each as a plain SV. Note that we don't have
149             * to parse inside the contents of the parens; that is handled by the
150             * attribute handlers themselves
151             */
152             OP *attrs = NULL;
153             SV *attr;
154              
155             lex_read_space(0);
156             while((attr = lex_scan_attr())) {
157             lex_read_space(0);
158              
159             if(compcv && strEQ(SvPV_nolen(attr), "lvalue")) {
160             CvLVALUE_on(compcv);
161             }
162              
163             if(!attrs)
164             attrs = newLISTOP(OP_LIST, 0, NULL, NULL);
165              
166             attrs = op_append_elem(OP_LIST, attrs, newSVOP(OP_CONST, 0, attr));
167              
168             /* Accept additional colons to prefix additional attrs */
169             if(lex_peek_unichar(0) == ':') {
170             lex_read_unichar(0);
171             lex_read_space(0);
172             }
173             }
174              
175             return attrs;
176             }
177              
178             #define lex_scan_lexvar() MY_lex_scan_lexvar(aTHX)
179 5           static SV *MY_lex_scan_lexvar(pTHX)
180             {
181 5 50         int sigil = lex_peek_unichar(0);
    50          
182             switch(sigil) {
183             case '$':
184             case '@':
185             case '%':
186 5           lex_read_unichar(0);
187             break;
188              
189             default:
190 0           croak("Expected a lexical variable");
191             }
192              
193 5           SV *ret = lex_scan_ident();
194 5 50         if(!ret)
195             return NULL;
196              
197             /* prepend sigil - which we know to be a single byte */
198 5 50         SvGROW(ret, SvCUR(ret) + 1);
    50          
199 5           Move(SvPVX(ret), SvPVX(ret) + 1, SvCUR(ret), char);
200 5           SvPVX(ret)[0] = sigil;
201 5           SvCUR(ret)++;
202              
203 5           SvPVX(ret)[SvCUR(ret)] = 0;
204              
205 5           return ret;
206             }
207              
208             #define lex_scan_parenthesized() MY_lex_scan_parenthesized(aTHX)
209             static SV *MY_lex_scan_parenthesized(pTHX)
210             {
211             I32 c;
212             int parencount = 0;
213             SV *ret = newSVpvs("");
214             if(lex_bufutf8())
215             SvUTF8_on(ret);
216              
217             c = lex_peek_unichar(0);
218              
219             while(c != -1) {
220             sv_cat_c(ret, lex_read_unichar(0));
221              
222             switch(c) {
223             case '(': parencount++; break;
224             case ')': parencount--; break;
225             }
226             if(!parencount)
227             break;
228              
229             c = lex_peek_unichar(0);
230             }
231              
232             if(SvCUR(ret))
233             return ret;
234              
235             SvREFCNT_dec(ret);
236             return NULL;
237             }
238              
239             #define lex_scan_version(flags) MY_lex_scan_version(aTHX_ flags)
240 5           static SV *MY_lex_scan_version(pTHX_ int flags)
241             {
242             I32 c;
243 5           SV *tmpsv = sv_2mortal(newSVpvs(""));
244              
245             /* scan_version() expects a version to end in linefeed, semicolon or
246             * openbrace; gets confused if other keywords are fine. We'll have to
247             * extract it first.
248             * https://rt.cpan.org/Ticket/Display.html?id=132903
249             */
250              
251 21 50         while((c = lex_peek_unichar(0))) {
252             /* Allow a single leading v before accepting only digits, dot, underscore */
253 21 100         if((!SvCUR(tmpsv) && (c == 'v')) || strchr("0123456789._", c))
    100          
    100          
254 16           sv_cat_c(tmpsv, lex_read_unichar(0));
255             else
256             break;
257             }
258              
259 5 100         if(!SvCUR(tmpsv) && (flags & PARSE_OPTIONAL))
    50          
260             return NULL;
261              
262 3           SV *ret = newSV(0);
263 3           scan_version(SvPVX(tmpsv), ret, FALSE);
264              
265 3           return ret;
266             }
267              
268             #define parse_lexvar() MY_parse_lexvar(aTHX)
269             static PADOFFSET MY_parse_lexvar(pTHX)
270             {
271             /* TODO: Rewrite this in terms of using lex_scan_lexvar()
272             */
273             char *lexname = PL_parser->bufptr;
274              
275             if(lex_read_unichar(0) != '$')
276             croak("Expected a lexical scalar at %s", lexname);
277              
278             if(!isIDFIRST_uni(lex_peek_unichar(0)))
279             croak("Expected a lexical scalar at %s", lexname);
280             lex_read_unichar(0);
281             while(isIDCONT_uni(lex_peek_unichar(0)))
282             lex_read_unichar(0);
283              
284             /* Forbid $_ */
285             if(PL_parser->bufptr - lexname == 2 && lexname[1] == '_')
286             croak("Can't use global $_ in \"my\"");
287              
288             return pad_add_name_pvn(lexname, PL_parser->bufptr - lexname, 0, NULL, NULL);
289             }
290              
291             #define parse_scoped_block(flags) MY_parse_scoped_block(aTHX_ flags)
292             static OP *MY_parse_scoped_block(pTHX_ int flags)
293             {
294             OP *ret;
295             I32 save_ix = block_start(TRUE);
296             ret = parse_block(flags);
297             return block_end(save_ix, ret);
298             }