chainlint: tighten accuracy when consuming input stream

To extract the next token in the input stream, Lexer::scan_token() finds the start of the token by skipping whitespace, then consumes characters belonging to the token until it encounters a non-token character, such as an operator, punctuation, or whitespace. In the case of an operator or punctuation which ends a token, before returning the just-scanned token, it pushes that operator or punctuation character back onto the input stream to ensure that it will be the first character consumed by the next call to scan_token(). However, scan_token() is intentionally lax when whitespace ends a token; it doesn't bother pushing the whitespace character back onto the token stream since it knows that the next call to scan_token() will, as its first step, skip over whitespace anyhow when looking for the start of the token. Although such laxity is harmless for the proper functioning of the lexical analyzer, it does make it difficult to precisely identify the token's end position in the input stream. Accurate token position information may be desirable, for instance, to annotate problems or highlight other interesting facets of the input found during the parsing phase. To accommodate such possibilities, tighten scan_token() by making it push the token-ending whitespace character back onto the input stream, just as it does for other token-ending characters. Signed-off-by: Eric Sunshine <sunshine@sunshineco.com> Signed-off-by: Taylor Blau <me@ttaylorr.com>

Eric Sunshine committed Nov 8, 2022 at 19:08 UTC ca748f518358448efa46f01539a8bdce5cfc710f
1 file changed +1 -1
t/chainlint.pl
+1 -1
@@ -179,7 +179,7 @@ RESTART:
179 # handle special characters
180 last unless $$b =~ /\G(.)/sgc;
181 my $c = $1;
182 - last if $c =~ /^[ \t]$/; # whitespace ends token
182 + pos($$b)--, last if $c =~ /^[ \t]$/; # whitespace ends token
183 pos($$b)--, last if length($token) && $c =~ /^[;&|<>(){}\n]$/;
184 $token .= $self->scan_sqstring(), next if $c eq "'";
185 $token .= $self->scan_dqstring(), next if $c eq '"';