Skip to content

Commit f9565bd

Browse files
committed
Perl: skip string literals when collecting heredoc markers
Close #3588. Signed-off-by: Masatake YAMATO <[email protected]>
1 parent 5e874f6 commit f9565bd

File tree

4 files changed

+146
-0
lines changed

4 files changed

+146
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
--sort=no
2+
--kinds-Perl=+{heredoc}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
f0tag input.pl /^sub f0tag() {}$/;" s
2+
f1tag input.pl /^sub f1tag() {}$/;" s
3+
f2tag input.pl /^sub f2tag() {}$/;" s
4+
f3tag input.pl /^sub f3tag() {}$/;" s
5+
hereodc0tag input.pl /^print 'cat <<<heredoct0notag' . <<hereodc0tag;$/;" h
6+
f4tag input.pl /^sub f4tag() {}$/;" s
7+
hereodc1tag input.pl /^print "cat <<<heredoct1notag" . <<hereodc1tag;$/;" h
8+
f5tag input.pl /^sub f5tag() {}$/;" s
9+
hereodc2tag input.pl /^print `cat <<<heredoct1notag` . <<hereodc2tag;$/;" h
10+
f6tag input.pl /^sub f6tag() {}$/;" s
11+
heredoc3tag input.pl /^print "abc" . <<heredoc3tag . 'efg' . << "heredoc4tag" . `ls` . '<<hereodc5notag';$/;" h
12+
heredoc4tag input.pl /^print "abc" . <<heredoc3tag . 'efg' . << "heredoc4tag" . `ls` . '<<hereodc5notag';$/;" h
13+
f7tag input.pl /^sub f7tag() {}$/;" s
14+
f8tag input.pl /^sub f8tag() {}$/;" s
15+
f9tag input.pl /^sub f9tag() {}$/;" s
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Derrived from #3588 submitted by @petdance
2+
3+
sub f0tag() {}
4+
5+
my $x = '<<NOT_A_HEREDOC0';
6+
7+
sub f1tag() {}
8+
9+
print "<<NOT_A_HEREDOC0\n";
10+
11+
sub f2tag() {}
12+
13+
print `cat <<<BASH_HERE_STRING`;
14+
15+
sub f3tag() {}
16+
17+
print 'cat <<<heredoct0notag' . <<hereodc0tag;
18+
sub f0notag() {}
19+
hereodc0tag
20+
21+
sub f4tag() {}
22+
23+
print "cat <<<heredoct1notag" . <<hereodc1tag;
24+
sub f1notag() {}
25+
hereodc1tag
26+
27+
sub f5tag() {}
28+
29+
print `cat <<<heredoct1notag` . <<hereodc2tag;
30+
sub f2notag() {}
31+
hereodc2tag
32+
33+
sub f6tag() {}
34+
35+
print "abc" . <<heredoc3tag . 'efg' . << "heredoc4tag" . `ls` . '<<hereodc5notag';
36+
sub f3notag() {}
37+
heredoc3tag
38+
sub f4notag() {}
39+
heredoc4tag
40+
sub f7tag() {}
41+
42+
sub f8tag() {}
43+
44+
my $i = 1;
45+
print "a" . 3 << $i;
46+
47+
sub f9tag() {}

parsers/perl.c

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,84 @@ static unsigned char *readHereDocMarker (unsigned char *line,
441441
return cp;
442442
}
443443

444+
enum stringType {
445+
STRING_TYPE_NONE = '\0',
446+
STRING_TYPE_SINGLEQ = '\'',
447+
STRING_TYPE_DOUBLEQ = '"',
448+
STRING_TYPE_BACKQ = '`',
449+
};
450+
451+
452+
static const unsigned char *escapeFromString (const unsigned char *line,
453+
const unsigned char *end,
454+
enum stringType stype)
455+
{
456+
bool in_escape = false;
457+
const unsigned char *cp = line;
458+
459+
switch (stype)
460+
{
461+
case STRING_TYPE_NONE:
462+
return line;
463+
case STRING_TYPE_SINGLEQ:
464+
case STRING_TYPE_DOUBLEQ:
465+
case STRING_TYPE_BACKQ:
466+
while ((end && cp < end) || (end == NULL && *cp != '\0'))
467+
{
468+
if (in_escape)
469+
{
470+
cp++;
471+
in_escape = false;
472+
}
473+
else if (*cp == '\\')
474+
{
475+
cp++;
476+
in_escape = true;
477+
}
478+
else if (*cp == (unsigned char)stype)
479+
{
480+
cp++;
481+
return cp;
482+
}
483+
else
484+
cp++;
485+
}
486+
return NULL;
487+
default:
488+
AssertNotReached ();
489+
return NULL;
490+
}
491+
}
492+
493+
static enum stringType isInString (const unsigned char *line,
494+
const unsigned char *end)
495+
{
496+
const unsigned char *cp = line;
497+
enum stringType t = STRING_TYPE_NONE;
498+
499+
while (cp && cp < end)
500+
{
501+
switch (*cp)
502+
{
503+
case '\'':
504+
case '\"':
505+
case '`':
506+
t = *cp;
507+
break;
508+
default:
509+
t = STRING_TYPE_NONE;
510+
break;
511+
}
512+
513+
cp++;
514+
if (t != STRING_TYPE_NONE)
515+
cp = escapeFromString (cp, end, t);
516+
}
517+
518+
return (cp == NULL)? t: STRING_TYPE_NONE;
519+
}
520+
521+
444522
static const unsigned char *collectHereDocMarker (struct hereDocMarkerManager *mgr,
445523
const unsigned char *line)
446524
{
@@ -452,6 +530,10 @@ static const unsigned char *collectHereDocMarker (struct hereDocMarkerManager *m
452530
if (starter == NULL)
453531
return NULL;
454532

533+
enum stringType stype;
534+
if ((stype = isInString(line, starter)) != STRING_TYPE_NONE)
535+
return escapeFromString (starter + 2, NULL, stype);
536+
455537
cp = starter + 2;
456538
while (isspace (*cp))
457539
cp++;

0 commit comments

Comments
 (0)