2 # A really simple template engine
3 # (c) 2004 Martin Mares <mj@ucw.cz>
15 my ($r,$left,$right) = @_;
20 if ($$r =~ /\G([^$left$right]+)/cgs) {
21 } elsif ($$r =~ /\G([$left])/cgs) {
23 } elsif ($$r =~ /\G([$right])/cgs) {
26 die "File ended when looking for matching $right";
37 return $res unless $@;
38 die "Error evaluating $x: $@";
46 if ($f =~ /^(if|fi|else|elif)$/) {
48 $a ne "()" or die "\@if requires an argument";
50 unshift @cond, (eval_if_ok($a) ? 1 : -1);
54 } elsif ($f eq "fi") {
55 $a eq "()" or die "\@fi takes no arguments";
56 $#cond or die "\@fi without \@if";
58 } elsif ($f eq "else") {
59 $a eq "()" or die "\@else takes no arguments";
60 $#cond or die "\@else without \@if";
62 } elsif ($f eq "elif") {
63 $a ne "()" or die "\@elif requires an argument";
64 $#cond or die "\@elif without \@if";
67 } elsif ($cond[0] < 0) {
69 $cond[0] = (eval_if_ok($a) ? 1 : -1);
72 # print "Cond stack: @cond\n";
78 sub process_string($) {
82 if ($t =~ /\G([^\@]+)/cgs) {
83 print $1 if $cond[0] > 0;
84 } elsif ($t =~ /\G\@\s*\n/cgs) {
85 # @ at end of line is ignored and eats the end of line
86 } elsif ($t =~ /\G\@#[^\n]*\n/cgs) {
87 # a comment, which is ignored
88 } elsif ($t =~ /\G\@\@/cgs) {
90 } elsif ($t =~ /\G\@{/cgs) {
91 my $x = get_nested(\$t, "{", "}");
93 } elsif ($t =~ /\G\@\[/cgs) {
94 my $x = get_nested(\$t, '\[', '\]');
98 } elsif ($t =~ /\G\@(\w+)\(/cgs) {
100 my $args = get_nested(\$t, '(', ')');
101 eval_func($func, $args);
102 } elsif ($t =~ /\G\@(\w+)([^\n]*)\n/cgs) {
103 eval_func($1, "($2)");
104 } elsif ($t =~ /\G\@(\$\w+)/cgs) {
105 print eval_if_ok($1);
106 } elsif ($t =~ /\G(\@[^\n]*)/cgs) {
107 die "Unknown control sequence $1";
108 } elsif ($t =~ /\G$/cgs) {
110 } elsif ($t =~ /\G([^\n]*)/cgs) {
111 die "Internal parser error at $1 (pos " . pos($t) . ")";
116 sub process_file($) {
118 my $fh = new IO::File $name;
119 die "Unable to open $name: $!" unless defined $fh;
121 { local $/; undef $/; $text = <$fh>; }
123 process_string($text);
131 eval_if_ok("\$$v = \$temp");
138 (!defined $f || @_) and die "\@load requires only one argument";
149 $#cond and die "Unterminated \@if (depth $#cond)";
153 die "Usage: temple <in> <out>";
156 open STDOUT, ">$ARGV[1]" or die "Cannot open $ARGV[1]: $!";
158 process_file($ARGV[0]);