Skip to content

Commit bf42f0a

Browse files
sunshinecottaylorr
authored andcommitted
chainlint: latch line numbers at which each token starts and ends
When chainlint detects problems in a test, it prints out the name of the test script, the name of the problematic test, and a copy of the test definition with "?!FOO?!" annotations inserted at the locations where problems were detected. Taken together this information is sufficient for the test author to identify the problematic code in the original test definition. However, in a lengthy script or a lengthy test definition, the author may still end up using the editor's search feature to home in on the exact problem location. To further assist the test author, an upcoming change will display line numbers along with the annotated test definition, thus allowing the author to jump directly to each problematic line. As preparation, upgrade Lexer to latch the line numbers at which each token starts and ends, and return that information with the token itself. Signed-off-by: Eric Sunshine <[email protected]> Signed-off-by: Taylor Blau <[email protected]>
1 parent 5451877 commit bf42f0a

File tree

1 file changed

+17
-8
lines changed

1 file changed

+17
-8
lines changed

t/chainlint.pl

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ sub new {
6767
bless {
6868
parser => $parser,
6969
buff => $s,
70+
lineno => 1,
7071
heretags => []
7172
} => $class;
7273
}
@@ -97,7 +98,9 @@ sub scan_op {
9798
sub scan_sqstring {
9899
my $self = shift @_;
99100
${$self->{buff}} =~ /\G([^']*'|.*\z)/sgc;
100-
return "'" . $1;
101+
my $s = $1;
102+
$self->{lineno} += () = $s =~ /\n/sg;
103+
return "'" . $s;
101104
}
102105

103106
sub scan_dqstring {
@@ -115,14 +118,15 @@ sub scan_dqstring {
115118
if ($c eq '\\') {
116119
$s .= '\\', last unless $$b =~ /\G(.)/sgc;
117120
$c = $1;
118-
next if $c eq "\n"; # line splice
121+
$self->{lineno}++, next if $c eq "\n"; # line splice
119122
# backslash escapes only $, `, ", \ in dq-string
120123
$s .= '\\' unless $c =~ /^[\$`"\\]$/;
121124
$s .= $c;
122125
next;
123126
}
124127
die("internal error scanning dq-string '$c'\n");
125128
}
129+
$self->{lineno} += () = $s =~ /\n/sg;
126130
return $s;
127131
}
128132

@@ -137,6 +141,7 @@ sub scan_balanced {
137141
$depth--;
138142
last if $depth == 0;
139143
}
144+
$self->{lineno} += () = $s =~ /\n/sg;
140145
return $s;
141146
}
142147

@@ -163,20 +168,24 @@ sub swallow_heredocs {
163168
my $b = $self->{buff};
164169
my $tags = $self->{heretags};
165170
while (my $tag = shift @$tags) {
171+
my $start = pos($$b);
166172
my $indent = $tag =~ s/^\t// ? '\\s*' : '';
167173
$$b =~ /(?:\G|\n)$indent\Q$tag\E(?:\n|\z)/gc;
174+
my $body = substr($$b, $start, pos($$b) - $start);
175+
$self->{lineno} += () = $body =~ /\n/sg;
168176
}
169177
}
170178

171179
sub scan_token {
172180
my $self = shift @_;
173181
my $b = $self->{buff};
174182
my $token = '';
175-
my $start;
183+
my ($start, $startln);
176184
RESTART:
185+
$startln = $self->{lineno};
177186
$$b =~ /\G[ \t]+/gc; # skip whitespace (but not newline)
178187
$start = pos($$b) || 0;
179-
return ["\n", $start, pos($$b)] if $$b =~ /\G#[^\n]*(?:\n|\z)/gc; # comment
188+
$self->{lineno}++, return ["\n", $start, pos($$b), $startln, $startln] if $$b =~ /\G#[^\n]*(?:\n|\z)/gc; # comment
180189
while (1) {
181190
# slurp up non-special characters
182191
$token .= $1 if $$b =~ /\G([^\\;&|<>(){}'"\$\s]+)/gc;
@@ -188,20 +197,20 @@ sub scan_token {
188197
$token .= $self->scan_sqstring(), next if $c eq "'";
189198
$token .= $self->scan_dqstring(), next if $c eq '"';
190199
$token .= $c . $self->scan_dollar(), next if $c eq '$';
191-
$self->swallow_heredocs(), $token = $c, last if $c eq "\n";
200+
$self->{lineno}++, $self->swallow_heredocs(), $token = $c, last if $c eq "\n";
192201
$token = $self->scan_op($c), last if $c =~ /^[;&|<>]$/;
193202
$token = $c, last if $c =~ /^[(){}]$/;
194203
if ($c eq '\\') {
195204
$token .= '\\', last unless $$b =~ /\G(.)/sgc;
196205
$c = $1;
197-
next if $c eq "\n" && length($token); # line splice
198-
goto RESTART if $c eq "\n"; # line splice
206+
$self->{lineno}++, next if $c eq "\n" && length($token); # line splice
207+
$self->{lineno}++, goto RESTART if $c eq "\n"; # line splice
199208
$token .= '\\' . $c;
200209
next;
201210
}
202211
die("internal error scanning character '$c'\n");
203212
}
204-
return length($token) ? [$token, $start, pos($$b)] : undef;
213+
return length($token) ? [$token, $start, pos($$b), $startln, $self->{lineno}] : undef;
205214
}
206215

207216
# ShellParser parses POSIX shell scripts (with minor extensions for Bash). It

0 commit comments

Comments
 (0)