From 9141d10ee498c43aa32db68446c5e86482244ea5 Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Tue, 6 Jan 2015 16:51:02 +0300 Subject: [PATCH] Add min and max functions --- VMXTemplate/Compiler.pm | 29 +++++++++++++++++---------- VMXTemplate/Utils.pm | 44 ++++++++++++++++++++++++++++++++++++++++- template.parser.php | 6 ++++++ 3 files changed, 68 insertions(+), 11 deletions(-) diff --git a/VMXTemplate/Compiler.pm b/VMXTemplate/Compiler.pm index cf57ddd..d69a114 100644 --- a/VMXTemplate/Compiler.pm +++ b/VMXTemplate/Compiler.pm @@ -91,6 +91,7 @@ use constant Q_ALWAYS => -1; # always safe use constant Q_IF_ALL => -2; # safe if all arguments are safe use constant Q_ALL_BUT_FIRST => -3; # safe if all arguments except first are safe; first may be safe or unsafe use constant Q_ALWAYS_NUM => -4; # always safe, returns numeric values +use constant Q_PASS => -5; # pass safeness to function my $functionSafeness = { int => Q_ALWAYS_NUM, @@ -115,6 +116,8 @@ my $functionSafeness = { mul => Q_ALWAYS_NUM, div => Q_ALWAYS_NUM, mod => Q_ALWAYS_NUM, + min => Q_IF_ALL_PASS, + max => Q_IF_ALL_PASS, log => Q_ALWAYS_NUM, even => Q_ALWAYS_NUM, odd => Q_ALWAYS_NUM, @@ -191,29 +194,30 @@ sub compile_function $fn = $functions->{$fn}; } # Calculate HTML safeness flag - my $q = $functionSafeness->{$fn}; - if ($q > 0) + my $fl = $functionSafeness->{$fn}; + my $q; + if ($fl > 0) { - $q = exists $args->[$q-1] ? $args->[$q-1]->[1] : 1; + $q = exists $args->[$fl-1] ? $args->[$fl-1]->[1] : 1; } - elsif ($q == Q_ALWAYS) + elsif ($fl == Q_ALWAYS) { $q = 1; } - elsif ($q == Q_ALWAYS_NUM) + elsif ($fl == Q_ALWAYS_NUM) { $q = 'i'; } - else + elsif ($fl != Q_PASS) { $q = 1; my $n = scalar @$args; - for (my $i = ($q == Q_ALL_BUT_FIRST ? 1 : 0); $i < $n; $i++) + for (my $i = ($fl == Q_ALL_BUT_FIRST ? 1 : 0); $i < $n; $i++) { $q = $q && $args->[$i]->[1]; } } - my $argv = [ map { $_->[0] } @$args ]; + my $argv = $fl == Q_PASS ? [ map { $_->[0] } @$args ] : $argv; my $r; if ($self->can(my $ffn = "function_$fn")) { @@ -228,9 +232,11 @@ sub compile_function else { $self->{lexer}->warn("Unknown function: '$fn'"); - $r = "''"; + $r = $fl == Q_PASS ? [ "''", 1 ] : "''"; } - return [ $r, $q, ($forceSubst->{$fn} ? 1 : ()) ]; + $r = [ $r, $q ] if $fl != Q_PASS; + push @$r, 1 if $forceSubst->{$fn}; + return $r; } # call operator on arguments @@ -269,6 +275,9 @@ sub function_sub { fmop('-', @_) } sub function_mul { fmop('*', @_) } sub function_div { fmop('/', @_) } sub function_mod { fmop('%', @_) } +# min, max +sub function_min { (grep { $_->[1] ne 'i' } @_ ? 'str_' : '')."min(".join(', ', map { $_->[0] } @_).")" } +sub function_max { (grep { $_->[1] ne 'i' } @_ ? 'str_' : '')."max(".join(', ', map { $_->[0] } @_).")" } # logarithm sub function_log { "log($_[1])" } # is the argument even/odd? diff --git a/VMXTemplate/Utils.pm b/VMXTemplate/Utils.pm index 190919e..de234cb 100644 --- a/VMXTemplate/Utils.pm +++ b/VMXTemplate/Utils.pm @@ -12,7 +12,7 @@ our @EXPORT = qw( timestamp plural_ru strlimit htmlspecialchars urlencode urldecode strip_tags strip_unsafe_tags addcslashes requote quotequote sql_quote regex_replace str_replace array_slice array_div encode_json trim html_pbr array_items utf8on - exec_subst exec_pairs exec_is_array exec_get exec_cmp var_dump + exec_subst exec_pairs exec_is_array exec_get exec_cmp min max str_min str_max var_dump ); use constant { @@ -364,6 +364,48 @@ sub exec_cmp return $n ? $a <=> $b : $a cmp $b; } +# min +sub min +{ + my $r = shift @_; + for (@_) + { + $r = $_ if $_ < $r; + } + return $r; +} + +sub str_min +{ + my $r = shift @_; + for (@_) + { + $r = $_ if $_ lt $r; + } + return $r; +} + +# max +sub max +{ + my $r = shift @_; + for (@_) + { + $r = $_ if $_ > $r; + } + return $r; +} + +sub str_max +{ + my $r = shift @_; + for (@_) + { + $r = $_ if $_ gt $r; + } + return $r; +} + # Quote strings without transforming UTF-8 to \x{...} sub _dumper_qquote { diff --git a/template.parser.php b/template.parser.php index 9e4211d..7c38a18 100644 --- a/template.parser.php +++ b/template.parser.php @@ -90,6 +90,8 @@ class VMXTemplateCompiler 'mul' => self::Q_ALWAYS, 'div' => self::Q_ALWAYS, 'mod' => self::Q_ALWAYS, + 'min' => self::Q_IF_ALL, + 'max' => self::Q_IF_ALL, 'log' => self::Q_ALWAYS, 'even' => self::Q_ALWAYS, 'odd' => self::Q_ALWAYS, @@ -285,6 +287,10 @@ $code function function_div() { $a = func_get_args(); return self::fmop('/', $a); } function function_mod($a,$b) { return "(($a) % ($b))"; } + /* минимум и максимум */ + function function_min() { $a = func_get_args(); return "min([ ".implode(', ', $a)." ])"; } + function function_max() { $a = func_get_args(); return "max([ ".implode(', ', $a)." ])"; } + /* логарифм */ function function_log($e) { return "log($e)"; }