diff --git a/template.yp b/template.yp index 43f71ef..d9d6633 100644 --- a/template.yp +++ b/template.yp @@ -1,15 +1,5 @@ # Контекстно-свободная Parse::Yapp-грамматика шаблонизатора # -# Для корректной работы нужен патченый LIME со следующими изменениями: -# (*) Подменой лексемы 'lit' на 'str' в метаграмматике. -# Это нужно, чтобы можно было юзать строковые лексемы типа '' 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); - } + $r = [ 'literal', "'".addcslashes($self->eat($subst_pos), "'\\")."'" ]; + } + else + { + $r = [ '{{', $self->{options}->{begin_subst} ]; + $self->{last_start} = length $self->{eaten}; + $self->{last_start_line} = $self->{lineno}; + $self->eat(length $self->{options}->{begin_subst}); + $self->{in_subst} = 1; } - // Unknown character - $this->skip_error( - "Unexpected character '".$this->code{$this->pos}."'" - ); - return array('error', false); } + return @$r; + } + # Skip whitespace + if ($self->{code} =~ /^(\s+)/) + { + $self->eat(length $1); + } + if (!length $self->{code}) + { + # End of code + return; + } + if ($self->{code} =~ /^([a-z_][a-z0-9_]*)/is) + { + my $l = $1; + $self->eat(length $l); + if (exists $self->{keywords}->{uc $l}) + { + # Keyword + return (uc $l, $l); + } + # Identifier + return ('name', $l); + } + elsif ($self->{code} =~ /^( + (\")(?:[^\"\\\\]+|\\\\.)*\" | + \'(?:[^\'\\\\]+|\\\\.)*\' | + 0\d+ | \d+(\.\d+)? | 0x\d+)/xis) + { + # String or numeric non-negative literal + my $t = $1; + $self->eat(length $t); + if ($2) + { + $t =~ s/\$/\\\$/gso; + } + return ('literal', $t); + } + else + { + # Special characters + foreach my $l (@{$self->{lens}}) + { + my $a = $self->{nchar}->{$l}; + my $t = substr($self->{code}, 0, $l); + if (exists $a->{$t}) + { + $self->eat($l); + if ($self->{in_code}) + { + $self->{in_code}++ if $t eq $self->{options}->{begin_code}; + $self->{in_code}-- if $t eq $self->{options}->{end_code}; + if (!$self->{in_code}) + { + if ($self->{options}->{eat_code_line} && + $self->{code} =~ /^([ \t\r]+\n\r?)/so) + { + $self->eat(length $1); + } + return ('-->', $t); + } + } + elsif ($self->{in_subst}) + { + $self->{in_subst}++ if $t eq $self->{options}->{begin_subst}; + $self->{in_subst}-- if $t eq $self->{options}->{end_subst}; + if (!$self->{in_subst}) + { + return ('}}', $t); + } + } + return ($t, undef); + } + } + # Unknown character + $self->warn("Unexpected character '".substr($self->{code}, 0, 1)."'"); + return ('error', undef); } } + +sub errorinfo +{ + my $self = shift; + my $linestart = rindex($self->{eaten}, "\n"); + my $lineend = index($self->{code}, "\n"); + $lineend = length($self->{code}) if $lineend < 0; + my $line = substr($self->{eaten}, $linestart+1) . '^^^' . substr($self->{code}, 0, $lineend); + my $charpos; + { + use bytes; + $charpos = length $self->{eaten}; + } + return ' in '.$self->{options}->{input_filename}.', line '.($self->{lineno}+1). + ', character '.$charpos.', marked by ^^^ in '.$line; +} + +sub warn +{ + my $self = shift; + my ($text) = @_; + $self->{options}->error($text.$self->errorinfo()); +}