File Coverage

hax/lexer-additions.c.inc
Criterion Covered Total %
statement 44 55 80.0
branch 36 64 56.2
condition n/a
subroutine n/a
pod n/a
total 80 119 67.2


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