Skip to content

Commit

Permalink
Fix backtracking issues, add string interpolation in Perl lexer (#1161)
Browse files Browse the repository at this point in the history
The previous rules for strings used a regular expression that combined
different elements of the string. This could, in a pathological case,
cause Rouge to get stuck trying to lex the code. This problem can be
fixed by lexing a quoted string in a separate state to `:root`.

In addition to adding states for quoted string, this commit also adds
support for basic string interpolation. The basic code is lifted from
the Ruby lexer. This fixes #974.
  • Loading branch information
pyrmont authored Jun 9, 2019
1 parent a8dc029 commit 6cad1b9
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 3 deletions.
37 changes: 34 additions & 3 deletions lib/rouge/lexers/perl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,9 @@ def self.detect?(text)
rule /\d+(_\d*)*e[+-]?\d+(_\d*)*/i, Num::Float
rule /\d+(_\d+)*/, Num::Integer

rule /'(\\\\|\\'|[^'])*'/, Str
rule /"(\\\\|\\"|[^"])*"/, Str
rule /`(\\\\|\\`|[^`])*`/, Str::Backtick
rule /'/, Punctuation, :sq
rule /"/, Punctuation, :dq
rule /`/, Punctuation, :bq
rule /<([^\s>]+)>/, re_tok
rule /(q|qq|qw|qr|qx)\{/, Str::Other, :cb_string
rule /(q|qq|qw|qr|qx)\(/, Str::Other, :rb_string
Expand Down Expand Up @@ -179,6 +179,26 @@ def self.detect?(text)
rule /;/, Punctuation, :pop!
end

state :sq do
rule /\\[']/, Str::Escape
rule /[^\\']+/, Str::Single
rule /'/, Punctuation, :pop!
end

state :dq do
mixin :string_intp
rule /\\[\\tnr"]/, Str::Escape
rule /[^\\"]+?/, Str::Double
rule /"/, Punctuation, :pop!
end

state :bq do
mixin :string_intp
rule /\\[\\tnr`]/, Str::Escape
rule /[^\\`]+?/, Str::Backtick
rule /`/, Punctuation, :pop!
end

[[:cb, '\{', '\}'],
[:rb, '\(', '\)'],
[:sb, '\[', '\]'],
Expand All @@ -193,6 +213,17 @@ def self.detect?(text)
end
end

state :in_interp do
rule /}/, Str::Interpol, :pop!
rule /\s+/, Text
rule /[a-z_]\w*/i, Str::Interpol
end

state :string_intp do
rule /[$@][{]/, Str::Interpol, :in_interp
rule /[$@][a-z_]\w*/i, Str::Interpol
end

state :end_part do
# eat the rest of the stream
rule /.+/m, Comment::Preproc, :pop!
Expand Down
6 changes: 6 additions & 0 deletions spec/visual/samples/perl
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,12 @@ $p =~ s%
%bar%x;
print $p, "\n";

my $str1 = "This is a ${ string } with fancy interpolation."
my $cmd1 = `So is @{ this } one.`
my $str2 = "This is a $string with plain interpolation."
my $cmd2 = `So is @this one.`
my $str3 = 'A boring $string.'

###### perl_misc ########

# from http://gist.github.com/485595
Expand Down

0 comments on commit 6cad1b9

Please sign in to comment.