Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
optimize a few more variations of successive text lines
  • Loading branch information
kraih committed Sep 2, 2014
1 parent c046fd2 commit faf74b4
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 72 deletions.
1 change: 1 addition & 0 deletions Changes
@@ -1,5 +1,6 @@

5.37 2014-09-03
- Improved Mojo::Template performance slightly.

5.36 2014-09-02
- Improved Mojo::Template performance.
Expand Down
130 changes: 59 additions & 71 deletions lib/Mojo/Template.pm
Expand Up @@ -26,60 +26,56 @@ has tree => sub { [] };
sub build {
my $self = shift;

my (@blocks, $capture, $multi);
my @blocks = ('');
my ($capture, $multi);
my $escape = $self->auto_escape;
for my $block (@{$self->tree}) {
push @blocks, '';
for my $i (0 .. $#$block) {
my ($op, $value) = @{$block->[$i]};
my $newline = chomp($value //= '');

# Text (quote and fix line ending)
if ($op eq 'text') {
$value = join "\n", map { quotemeta $_ } split("\n", $value);
$value .= '\n' if $newline;
$blocks[-1] .= "\$_M .= \"" . $value . "\";" if length $value;
}

# Capture end
elsif ($op eq 'cpen') {
$blocks[-1] .= 'return Mojo::ByteStream->new($_M) }';
my $tree = $self->tree;
for my $i (0 .. $#$tree) {
my ($op, $value) = @{$tree->[$i]};
push @blocks, '' and next if $op eq 'line' && $tree->[$i + 1];
my $newline = chomp($value //= '');

# Text (quote and fix line ending)
if ($op eq 'text') {
$value = join "\n", map { quotemeta $_ } split("\n", $value);
$value .= '\n' if $newline;
$blocks[-1] .= "\$_M .= \"" . $value . "\";" if length $value;
}

# No following code
$blocks[-1] .= ';' if ($block->[$i + 1][1] // '') =~ /^\s*$/;
}
# Capture end
elsif ($op eq 'cpen') {
$blocks[-1] .= 'return Mojo::ByteStream->new($_M) }';

# Code or multiline expression
elsif ($op eq 'code' || $multi) { $blocks[-1] .= $value }
# No following code
$blocks[-1] .= ';' if ($tree->[$i + 1][1] // '') =~ /^\s*$/;
}

# Expression
if ($op eq 'expr' || $op eq 'escp') {
# Code or multiline expression
elsif ($op eq 'code' || $multi) { $blocks[-1] .= $value }

# Start
unless ($multi) {
# Expression
if ($op eq 'expr' || $op eq 'escp') {

# Escaped
if ($op eq 'escp' && !$escape || $op eq 'expr' && $escape) {
$blocks[-1] .= "\$_M .= _escape scalar $value";
}
# Escaped
if (!$multi && ($op eq 'escp' && !$escape || $op eq 'expr' && $escape)) {
$blocks[-1] .= "\$_M .= _escape scalar $value";
}

# Raw
else { $blocks[-1] .= "\$_M .= scalar $value" }
}
# Raw
elsif (!$multi) { $blocks[-1] .= "\$_M .= scalar $value" }

# Multiline
$multi = !$block->[$i + 1] || $block->[$i + 1][0] eq 'code';
# Multiline
$multi = !$tree->[$i + 1] || $tree->[$i + 1][0] ne 'text';

# Append semicolon
$blocks[-1] .= ';' unless $multi || $capture;
}
# Append semicolon
$blocks[-1] .= ';' unless $multi || $capture;
}

# Capture start
if ($op eq 'cpst') { $capture = 1 }
elsif ($capture) {
$blocks[-1] .= " sub { my \$_M = ''; ";
$capture = 0;
}
# Capture start
if ($op eq 'cpst') { $capture = 1 }
elsif ($capture) {
$blocks[-1] .= " sub { my \$_M = ''; ";
$capture = 0;
}
}

Expand Down Expand Up @@ -167,7 +163,6 @@ sub parse {
$line .= "\n" if $line !~ s/\\\\$/\\\n/ && $line !~ s/\\$//;

# Mixed line
my @block;
for my $token (split $token_re, $line) {

# Capture end
Expand All @@ -178,13 +173,13 @@ sub parse {
$op = 'text';

# Capture start
splice @block, -1, 0, ['cpst'] if $1;
splice @tree, -1, 0, ['cpst'] if $1;

# Trim left side
$self->_trim(\@block) if $trimming = $2;
_trim(\@tree) if ($trimming = $2) && @tree > 1;

# Hint at end
push @block, ['text', ''];
push @tree, ['text', ''];
}

# Code
Expand All @@ -207,20 +202,22 @@ sub parse {

# Trim right side (convert whitespace to line noise)
if ($trimming && $token =~ s/^(\s+)//) {
push @block, ['code', $1];
push @tree, ['code', $1];
$trimming = 0;
}

# Token (with optional capture end)
push @block, $capture ? ['cpen'] : (), [$op, $token];
push @tree, $capture ? ['cpen'] : (), [$op, $token];
$capture = 0;
}
}

# Optimize successive text lines ending with newlines
my $previous = $tree[-1] || [];
unless (_text($previous) && _text(\@block)) { push @tree, \@block }
else { $previous->[-1][1] .= $block[0][1] }
# Optimize successive text lines separated by a newline
push @tree, ['line'] and next
if $tree[-4] && $tree[-4][0] ne 'line'
|| (!$tree[-3] || $tree[-3][0] ne 'text' || $tree[-3][1] !~ /\n$/)
|| ($tree[-1][0] ne 'text' || $tree[-2][0] ne 'line');
$tree[-3][1] .= pop(@tree)->[1];
}

return $self;
Expand Down Expand Up @@ -249,26 +246,17 @@ sub _line {
return qq{#line @{[shift]} "$name"};
}

sub _text { @{$_[0]} == 1 && $_[0][0][0] eq 'text' && $_[0][0][1] =~ /\n$/ }

sub _trim {
my ($self, $block) = @_;

# Walk block backwards
for (my $i = @$block - 2; $i >= 0; $i -= 1) {
my $tree = shift;

# Skip captures
next if $block->[$i][0] eq 'cpst' || $block->[$i][0] eq 'cpen';
# Skip captures
my $i = $tree->[-2][0] eq 'cpst' || $tree->[-2][0] eq 'cpen' ? -3 : -2;

# Only trim text
return unless $block->[$i][0] eq 'text';
# Only trim text
return unless $tree->[$i][0] eq 'text';

# Convert whitespace text to line noise
splice @$block, $i, 0, ['code', $1] if $block->[$i][1] =~ s/(\s+)$//;

# Text left
return if length $block->[$i][1];
}
# Convert whitespace text to line noise
splice @$tree, $i, 0, ['code', $1] if $tree->[$i][1] =~ s/(\s+)$//;
}

sub _wrap {
Expand Down Expand Up @@ -602,7 +590,7 @@ Raw unparsed template.
=head2 tree
my $tree = $mt->tree;
$mt = $mt->tree([[['text', 'foo']]]);
$mt = $mt->tree([['text', 'foo']]);
Template in parsed form. Note that this structure should only be used very
carefully since it is very dynamic.
Expand Down
7 changes: 6 additions & 1 deletion t/mojo/template.t
Expand Up @@ -79,6 +79,11 @@ $mt = Mojo::Template->new;
$output = $mt->render(' <%= "one" =%><%= "two" %> three');
is $output, "onetwo three\n", 'expression tags trimmed';

# Nothing to trim
$mt = Mojo::Template->new;
$output = $mt->render("<% =%>");
is $output, '', 'nothing trimmed';

# Replace tag
$mt = Mojo::Template->new;
$output = $mt->render('<%% 1 + 1 %>');
Expand Down Expand Up @@ -1013,7 +1018,7 @@ test
654
321
EOF
is $mt->tree->[0][0][1], "test\n123\n", 'optimized text lines';
is $mt->tree->[0][1], "test\n123\n456", 'optimized text lines';
$output = $mt->build->compile || $mt->interpret;
is $output, "test\n123\n456789\\\n987\n654\n321\n", 'just text';

Expand Down

0 comments on commit faf74b4

Please sign in to comment.