diff --git a/template.lime b/template.lime index fffd2d9..c82ec57 100644 --- a/template.lime +++ b/template.lime @@ -311,9 +311,7 @@ hash: pair/$ $$ = ''; } . -gthash: gtpair/p { - $$ = $p; - } +gthash: gtpair/$ | gtpair/p ',' gthash/h { $$ = $p . ', ' . $h; } diff --git a/template.yp b/template.yp new file mode 100644 index 0000000..43f71ef --- /dev/null +++ b/template.yp @@ -0,0 +1,652 @@ +# Контекстно-свободная Parse::Yapp-грамматика шаблонизатора +# +# Для корректной работы нужен патченый LIME со следующими изменениями: +# (*) Подменой лексемы 'lit' на 'str' в метаграмматике. +# Это нужно, чтобы можно было юзать строковые лексемы типа '' +%token '{{' +%token '}}' + +%left '..' +%left '||' 'OR' 'XOR' +%left '&&' 'AND' +%nonassoc '==' '!=' '<' '>' '<=' '>=' +%left '+' '-' +%left '&' +%left '*' '/' '%' + +# Директивы + +%% + +template: chunks { + $_[0]->{template}->{st}->{functions}->{main}->{body} = "sub fn_main() {\nmy \$stack = [];\nmy \$t = '';\n".$_[1]."\nreturn \$t;\n}\n"; + ''; + } +; +chunks: { + ''; + } +| chunks chunk { + $_[1] . $_[2]; + } +; +chunk: literal { + '$t .= ' . $_[1] . ";\n"; + } +| '' { + $_[2]; + } +| '{{' exp '}}' { + '$t .= ' . ($_[2][1] || !$_[0]->{template}->{options}->{auto_escape} ? $_[2][0] : $_[0]->{template}->compile_function($_[0]->{template}->{options}->{auto_escape}, [ $_[2] ])[0]) . ";\n"; + } +| error { + ''; + } +; +code_chunk: c_if | c_set | c_fn | c_for | exp { + '$t .= ' . ($_[1][1] || !$_[0]->{template}->{options}->{auto_escape} ? $_[1][0] : $_[0]->{template}->compile_function($_[0]->{template}->{options}->{auto_escape}, [ $_[1] ])[0]) . ";\n"; + } +; +c_if: 'IF' exp '-->' chunks '' chunks '' chunks '' chunks c_elseifs chunks '' chunks c_elseifs chunks '' chunks '' { + #{ + "} elsif (" . $_[3][0] . ") {\n"; + #} + } +| c_elseifs chunks '' { + #{ + $_[1] . $_[2] . "} elsif (" . $_[5][0] . ") {\n"; + #} + } +; +c_set: 'SET' varref '=' exp { + $_[2][0] . ' = ' . $_[4][0] . ";\n"; + } +| 'SET' varref '-->' chunks '' chunks '' chunks '', $t); + } + } + elseif ($this->in_subst) + { + $this->in_subst += ($t === $this->options->begin_subst); + $this->in_subst -= ($t === $this->options->end_subst); + if (!$this->in_subst) + { + return array('}}', $t); + } + } + return array($t, false); + } + } + // Unknown character + $this->skip_error( + "Unexpected character '".$this->code{$this->pos}."'" + ); + return array('error', false); + } + } +}