summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/Text/Handlebars.pm23
-rw-r--r--lib/Text/Handlebars/Compiler.pm154
2 files changed, 149 insertions, 28 deletions
diff --git a/lib/Text/Handlebars.pm b/lib/Text/Handlebars.pm
index 154a78b..787ac22 100644
--- a/lib/Text/Handlebars.pm
+++ b/lib/Text/Handlebars.pm
@@ -124,26 +124,9 @@ sub default_functions {
return {
%{ $class->SUPER::default_functions(@_) },
%{ $class->default_helpers },
- '(new_vars_for)' => sub {
- my ($vars, $value, $i) = @_;
-
- if (ref($value) eq 'ARRAY') {
- $value = ref($value->[$i]) eq 'HASH'
- ? { '.' => $value->[$i], %{ $value->[$i] } }
- : { '.' => $value->[$i] };
- }
-
- if (ref($value) eq 'HASH') {
- return {
- '@index' => $i,
- %$vars,
- %$value,
- '..' => $vars,
- };
- }
- else {
- return $vars;
- }
+ '(merge_hash)' => sub {
+ my ($left, $right) = @_;
+ return { %$left, %$right };
},
};
}
diff --git a/lib/Text/Handlebars/Compiler.pm b/lib/Text/Handlebars/Compiler.pm
index 251050b..6be89e7 100644
--- a/lib/Text/Handlebars/Compiler.pm
+++ b/lib/Text/Handlebars/Compiler.pm
@@ -148,13 +148,7 @@ sub _generate_block {
$name->clone(
arity => 'block_body',
first => [
- $self->call(
- $node,
- '(new_vars_for)',
- $self->vars,
- $name->clone,
- $self->iterator_index,
- ),
+ $self->new_vars($name->clone, $self->iterator_index),
],
second => [ $block{if}{body} ],
),
@@ -207,7 +201,8 @@ sub is_unary {
my ($id) = @_;
my %unary = (
- map { $_ => 1 } qw(builtin_is_array_ref is_code_ref render_string)
+ map { $_ => 1 } qw(builtin_is_array_ref builtin_is_hash_ref is_code_ref
+ render_string)
);
return $unary{$id};
@@ -259,6 +254,96 @@ sub _generate_run_code {
return $self->compile_ast($render_string);
}
+sub _generate_new_vars {
+ my $self = shift;
+ my ($node) = @_;
+
+ my ($vars, $value, $i) = ($node->first, $node->second, $node->third);
+
+ my $value_at_index = $value->clone(
+ arity => 'field',
+ first => $value->clone,
+ second => $i->clone,
+ );
+
+ my $lvar_id = $self->lvar_id;
+ local $self->{lvar_id} = $self->lvar_use(1);
+
+ my @code;
+
+ push @code, $self->compile_ast($value);
+ push @code, $self->opcode('save_to_lvar', $lvar_id);
+ my $lvar_value = $value->clone(arity => 'lvar', id => $lvar_id);
+
+ push @code, $self->compile_ast(
+ $self->make_ternary(
+ $self->is_array_ref($lvar_value->clone),
+ $self->save_lvar(
+ $lvar_id,
+ $self->make_ternary(
+ $self->is_hash_ref($value_at_index->clone),
+ $self->merge_hash(
+ $self->make_hash(
+ $self->parser->literal('.'),
+ $value_at_index->clone,
+ ),
+ $value_at_index->clone,
+ ),
+ $self->make_hash(
+ $self->parser->literal('.'),
+ $value_at_index->clone,
+ ),
+ ),
+ ),
+ ),
+ );
+
+ push @code, $self->compile_ast(
+ $self->save_lvar(
+ $lvar_id,
+ $self->make_ternary(
+ $self->is_hash_ref($lvar_value->clone),
+ $self->merge_hash(
+ $self->make_hash(
+ $self->parser->literal('@index'),
+ $i->clone,
+ ),
+ $vars->clone,
+ $lvar_value->clone,
+ $self->make_hash(
+ $self->parser->literal('..'),
+ $vars->clone,
+ ),
+ ),
+ $vars->clone,
+ ),
+ ),
+ );
+
+ push @code, $self->opcode('load_lvar', $lvar_id);
+
+ return @code;
+}
+
+sub _generate_lvar {
+ my $self = shift;
+ my ($node) = @_;
+
+ return (
+ $self->opcode('load_lvar', $node->id),
+ );
+}
+
+sub _generate_save_lvar {
+ my $self = shift;
+ my ($node) = @_;
+
+ return (
+ $self->compile_ast($node->first),
+ $self->opcode('save_to_lvar', $node->id),
+ );
+}
+
sub join {
my $self = shift;
my (@args) = @_;
@@ -346,6 +431,17 @@ sub is_array_ref {
);
}
+sub is_hash_ref {
+ my $self = shift;
+ my ($var) = @_;
+
+ return $self->parser->symbol('(is_hash_ref)')->clone(
+ id => 'builtin_is_hash_ref',
+ arity => 'unary',
+ first => $var,
+ );
+}
+
sub is_code_ref {
my $self = shift;
my ($var) = @_;
@@ -423,6 +519,48 @@ sub run_code {
);
}
+sub new_vars {
+ my $self = shift;
+ my ($value, $i) = @_;
+
+ return $value->clone(
+ arity => 'new_vars',
+ first => $self->vars,
+ second => $value,
+ third => $i,
+ );
+}
+
+sub save_lvar {
+ my $self = shift;
+ my ($id, $value) = @_;
+
+ return $value->clone(
+ arity => 'save_lvar',
+ id => $id,
+ first => $value,
+ );
+}
+
+sub merge_hash {
+ my $self = shift;
+ my (@hashes) = @_;
+
+ my $merged = shift @hashes;
+ for my $hash (@hashes) {
+ $merged = $self->merge_single_hash($merged, $hash);
+ }
+
+ return $merged;
+}
+
+sub merge_single_hash {
+ my $self = shift;
+ my ($left, $right) = @_;
+
+ return $self->call($left, '(merge_hash)', $left, $right);
+}
+
__PACKAGE__->meta->make_immutable;
no Any::Moose;