summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2012-09-26 17:52:53 -0500
committerJesse Luehrs <doy@tozt.net>2012-09-26 17:55:14 -0500
commit636dbb830883090f23a566d7fa82024429a937ab (patch)
tree849699b4050055d18076b73da034a336c186c74b /lib
parent580c50ba568ebf3e50cd063a86559493487d2675 (diff)
downloadtext-handlebars-636dbb830883090f23a566d7fa82024429a937ab.tar.gz
text-handlebars-636dbb830883090f23a566d7fa82024429a937ab.zip
sketch out the preprocessor
Diffstat (limited to 'lib')
-rw-r--r--lib/Text/Xslate/Syntax/Handlebars.pm134
1 files changed, 134 insertions, 0 deletions
diff --git a/lib/Text/Xslate/Syntax/Handlebars.pm b/lib/Text/Xslate/Syntax/Handlebars.pm
index e69de29..2d8f79d 100644
--- a/lib/Text/Xslate/Syntax/Handlebars.pm
+++ b/lib/Text/Xslate/Syntax/Handlebars.pm
@@ -0,0 +1,134 @@
+package Text::Xslate::Syntax::Handlebars;
+use Any::Moose;
+
+use Carp 'confess';
+use Text::Xslate::Util qw($STRING neat p);
+
+extends 'Text::Xslate::Syntax';
+
+sub _build_identity_pattern { qr/[A-Za-z_][A-Za-z0-9_]*/ }
+sub _build_comment_pattern { qr/\![^;]*/ }
+
+sub _build_line_start { undef }
+sub _build_tag_start { '{{' } # XXX needs to be modifiable
+sub _build_tag_end { '}}' } # XXX needs to be modifiable
+
+sub _build_shortcut_table { +{} }
+
+sub split_tags {
+ my $self = shift;
+ my ($input) = @_;
+
+ my $tag_start = $self->tag_start;
+ my $tag_end = $self->tag_end;
+
+ # 'text' is a something without newlines
+ # follwoing a newline, $tag_start, or end of the input
+ my $lex_text = qr/\A ( [^\n]*? (?: \n | (?= \Q$tag_start\E ) | \z ) ) /xms;
+
+ my $lex_comment = $parser->comment_pattern;
+ my $lex_code = qr/(?: $lex_comment | (?: $STRING | [^'"] ) )/xms;
+
+ my @chunks;
+
+ my $close_tag;
+ while ($input) {
+ if ($close_tag) {
+ my $start = 0;
+ my $pos;
+ while(($pos = index $input, $close_tag, $start) >= 0) {
+ my $code = substr $input, 0, $pos;
+ $code =~ s/$lex_code//g;
+ if(length($code) == 0) {
+ last;
+ }
+ $start = $pos + 1;
+ }
+
+ if ($pos >= 0) {
+ my $code = substr $_, 0, $pos, '';
+ $input =~ s/\A\Q$tag_end//
+ or die "Oops!";
+
+ push @chunks, [
+ ($close_tag eq '}}}' ? 'raw_code' : 'code'),
+ $code
+ ];
+
+ undef $close_tag;
+ }
+ else {
+ last; # the end tag is not found
+ }
+ }
+ elsif ($input =~ s/\A\Q$tag_start//) {
+ if ($tag_start eq '{{' && $input =~ s/\A\{//) {
+ $close_tag = '}}}';
+ }
+ else {
+ $close_tag = $tag_end;
+ }
+ }
+ elsif ($input =~ s/\A$lex_text//) {
+ push @chunks, [ text => $1 ];
+ }
+ else {
+ confess "Oops: unreached code, near " . p($input);
+ }
+ }
+
+ if ($close_tag) {
+ # calculate line number
+ my $orig_src = $_[0];
+ substr $orig_src, -length($input), length($input), '';
+ my $line = ($orig_src =~ tr/\n/\n/);
+ $self->_error("Malformed templates detected",
+ neat((split /\n/, $input)[0]), ++$line,
+ );
+ }
+
+ return @chunks;
+}
+
+sub preprocess {
+ my $self = shift;
+ my ($input) = @_;
+
+ my @chunks = $self->split_tags($input);
+
+ my $code = '';
+ for my $chunk (@chunks) {
+ my ($type, $content) = @$chunk;
+ if ($type eq 'text') {
+ $content =~ s/(["\\])/\\$1/g;
+ $code .= qq{print_raw "$content";\n};
+ }
+ elsif ($type eq 'code') {
+ $code .= qq{$content;\n};
+ }
+ elsif ($type eq 'raw_code') {
+ $code .= qq{& $content;\n};
+ }
+ else {
+ $parser->_error("Oops: Unknown token: $s ($type)");
+ }
+ }
+
+ return $code;
+}
+
+sub tokenize {
+}
+
+# XXX advance has some syntax special cases in it, probably need to override
+# it too eventually
+# sub advance {
+# }
+
+sub init_symbols {
+}
+
+__PACKAGE__->meta->make_immutable;
+no Any::Moose;
+
+1;