App-Mowyw
view release on metacpan or search on metacpan
lib/App/Mowyw.pm view on Meta::CPAN
my $tokens = shift;
my $meta = shift;
# print Dumper $meta;
my $key = strip_ws(p_expect($tokens, "UNMATCHED", $meta));
my @words = split /\s+/, $key;
p_expect($tokens, "TAG_END", $meta);
my $menu_fn = shift @words;
# print "\nMenu: '$menu_fn'\n";
$menu_fn = get_include_filename('menu', $menu_fn, $meta->{FILES}->[-1]);
# print "Menu after frobbing: '$menu_fn'\n";
my $m = my_dclone($meta);
push @{$m->{ITEMS}}, @words;
unshift @{$m->{FILES}}, $menu_fn;
return parse_file($menu_fn, $m);
}
# parse sub: parse an 'option' statement
sub p_option {
my $tokens = shift;
my $meta = shift;
my $key = strip_ws(p_expect($tokens, "UNMATCHED", $meta));
my @words = split /\s+/, $key;
my $option_key = shift @words;
my $option_val = join " ", @words;
$meta->{OPTIONS}->{$option_key} = $option_val;
p_expect($tokens, "TAG_END", $meta);
return "";
}
#parse sub: parse an "item" statement
sub p_item {
my $tokens = shift;
my $meta = shift;
my $content = p_expect($tokens, "UNMATCHED", $meta);
$content =~ s/^\s+//;
$content =~ m/^(\S+)/;
my $key = $1;
$content =~ s/^\S+//;
my $m = my_dclone($meta);
# print Data::Dumper->Dump([$m]);
if ($meta->{ITEMS}->[0] and $meta->{ITEMS}->[0] eq $key){
shift @{$m->{ITEMS}};
$m->{CURRENT_ITEM} = $key;
} else {
$m->{ITEMS} = [];
$m->{CURRENT_ITEM} = undef;
}
$m->{INSIDE_ITEM} = 1;
my $str = $content . parse_tokens($tokens, $m);
p_expect($tokens, "TAG_END", $meta);
return $str;
}
sub p_bind {
my ($tokens, $meta) = @_;
my $contents = strip_ws(slurp_upto_token($tokens, 'TAG_END', $meta));
my ($var, $rest) = split m/\s+/, $contents, 2;
my $string = qr{(
'[^'\\]*(?>\\.[^'\\]*)*'
|"[^"\\]*(?>\\.[^"\\]*)*'
|[^"']\S*
)}x;
my %options = parse_hash($rest, 'bind', $meta);
if ($options{file}){
$options{file} = get_include_filename('include', $options{file}, $meta->{FILES}->[-1]);
}
$meta->{VARS}{$var} = App::Mowyw::Datasource->new(\%options);
return '';
}
sub p_for {
my ($tokens, $meta) = @_;
my $contents = strip_ws(slurp_upto_token($tokens, 'TAG_END', $meta));
my ($iter, $in, $datasource) = split m/\s+/, $contents;
if (!defined $datasource || lc $in ne 'in' ){
parse_error(
q{Can't parse for statement. Syntax is [% for iterator_var in datasource %] ... [% endfor %]},
$meta->{FILES},
$tokens->[0],
);
}
my $ds = $meta->{VARS}{$datasource};
if (!$ds || !blessed($ds)){
confess "'$datasource' is not defined or not a valid data source\n";
}
my @bck_tokens = @$tokens;
my $str = '';
$ds->reset();
while (!$ds->is_exhausted){
local $meta->{VARS}{$iter} = $ds->get();
local $meta->{PARSE_UPTO} = 'endfor';
@$tokens = @bck_tokens;
# print "Iterating over '$datasource'\n";
$str .= parse_tokens($tokens, $meta);
$ds->next();
}
return $str;
}
sub p_ifvar {
my ($tokens, $meta) = @_;
my $contents = strip_ws(slurp_upto_token($tokens, 'TAG_END', $meta));
if ($contents =~ m/\s/){
parse_error(
q{Parse error in 'ifvar' tag. Syntax is [% ifvar variable %] .. [% endifvar %]},
$meta->{FILES},
$tokens->[0],
);
}
my $c = do {
local $meta->{NO_VAR_WARN} = 1;
resolve_var($contents, $meta);
};
local $meta->{PARSE_UPTO} = 'endifvar';
if (defined $c){
# warn "Variable '$contents' is defined\n";
return parse_tokens($tokens, $meta);
} else {
# warn "Variable '$contents' is NOT defined\n";
local $meta->{NO_VAR_WARN} = 1;
parse_tokens($tokens, $meta);
return '';
}
}
sub p_verbatim {
my $tokens = shift;
my $meta = shift;
my $str = "";
my $key = strip_ws(slurp_upto_token($tokens, 'TAG_END', $meta));
# print Dumper $tokens;
while (@$tokens){
if ( $tokens->[0]->[0] eq "TAG_START"
and $tokens->[1]->[0] eq "KEYWORD"
and $tokens->[1]->[1] eq "endverbatim"
and $tokens->[2]->[1] =~ m/\s*\Q$key\E\s*/
and $tokens->[3]->[0] eq "TAG_END"){
# found end of verbatim section
shift @$tokens for 1 .. 4;
return $str;
} else {
$str .= $tokens->[0]->[1];
shift @$tokens;
}
}
die "[[[verbatim $key]]] opened but not closed until end of file\n";
}
sub p_comment {
my $tokens = shift;
my $meta = shift;
slurp_upto_token($tokens, 'TAG_END', $meta);
return "";
}
sub resolve_var {
my ($name, $meta) = @_;
if ($name =~ m/\./){
my @parts = split m/\./, $name;
my $var = $meta->{VARS};
for (@parts){
if (!defined $var || !ref $var || reftype($var) ne 'HASH'){
unless ($meta->{NO_VAR_WARN}){
warn "\nCan't dereference '$name' at level '$_': not defined or not a hash\n";
}
return undef;
}
$var = $var->{$_};
}
return $var;
}
if (exists $meta->{VARS}->{$name}){
return $meta->{VARS}->{$name};
} else {
unless ($meta->{NO_VAR_WARN} || $config{quiet}){
print STDERR "Trying to access variable '$name' which is not defined\n";
}
return undef;
}
}
sub encode_entities {
my $str = shift;
return '' unless defined $str;
$str =~ s{&}{&}g;
$str =~ s{<}{<}g;
$str =~ s{>}{>}g;
$str =~ s{"}{"}g;
return $str;
}
sub slurp_upto_token {
my ($tokens, $expected_token, $meta) = @_;
my $str = '';
while (@$tokens && $tokens->[0][0] ne $expected_token){
$str .= $tokens->[0][1];
shift @$tokens;
}
p_expect($tokens, $expected_token, $meta);
return $str;
}
sub parse_hash {
my ($str, $statement_name, $meta) = @_;
return unless defined $str;
my $del_string = qr{(
'[^'\\]*(?>\\.[^'\\]*)*'
|"[^"\\]*(?>\\.[^"\\]*)*'
|[^"']\S*
)}x;
my %options;
pos($str) = 0;
while ($str =~ m/\G\s*(\w+):$del_string\s*/gc){
my $key = $1;
my $val = $2;
$val =~ s/^['"]//;
$val =~ s/['"]$//;
$val =~ s{\\(.)}{$1}g;
lib/App/Mowyw.pm view on Meta::CPAN
# becase DBI objects from App::Mowyw::Datasource::DBI hold code refs.
# so we don't clone blessed objects at all, but pass a reference instead.
my $meta = shift;
my %result;
for (keys %$meta){
if ($_ eq 'VARS'){
my %vs = %{$meta->{VARS}};
for my $v (keys %vs){
if (blessed $vs{$v}){
$result{VARS}{$v} = $vs{$v};
} else {
$result{VARS}{$v} = ref $vs{$v} ? dclone($vs{$v}) : $vs{$v};
}
}
} else {
$result{$_} = ref $meta->{$_} ? dclone($meta->{$_}) : $meta->{$_};
}
}
return \%result;
}
sub p_braces {
my $tokens = shift;
my $meta = shift;
my $str = "";
p_expect($tokens,"BRACES_START", $meta);
if ($meta->{CURRENT_ITEM}){
# print "using text inside braces\n";
$str .= parse_tokens($tokens, $meta);
} else {
# discard the text between opening {{ and closing }} braces
# print "discarding text inside braces\n";
parse_tokens($tokens, $meta);
}
p_expect($tokens, "BRACES_END", $meta);
return $str;
}
sub p_setvar {
my $tokens = shift;
my $meta = shift;
my $str = "";
while ($tokens->[0]->[0] ne "TAG_END"){
$str .= $tokens->[0]->[1];
shift @$tokens;
}
p_expect($tokens, "TAG_END", $meta);
$str = strip_ws($str);
$str =~ m#^(\S+)\s#;
my $name = $1;
my $value = $str;
$value =~ s/^\S+\s+//;
$meta->{VARS}->{$name} = $value;
return "";
}
sub p_readvar {
my ($tokens, $meta) = @_;
my $str = strip_ws(slurp_upto_token($tokens, 'TAG_END', $meta));
my ($name, $rest) = split m/\s+/, $str, 2;
my %options = parse_hash($rest, 'readvar', $meta);
my $c = resolve_var($name, $meta);
if (defined $options{escape} && lc $options{escape} eq 'html'){
return encode_entities($c);
}
return $c if defined $c;
return '';
}
sub p_syntaxfile {
my $tokens = shift;
my $meta = shift;
my $tag_content = shift @$tokens;
$tag_content = strip_ws($tag_content->[1]);
p_expect($tokens, "TAG_END", $meta);
my @t = split m/\s+/, $tag_content;
if (scalar @t != 2){
parse_error(
"Usage of syntaxfile tag: [[[syntaxfile <filename> <language>",
$meta->{FILES},
$tokens->[0],
);
}
}
sub p_syntax {
my $tokens = shift;
my $meta = shift;
my $lang = shift @$tokens;
$lang = strip_ws($lang->[1]);
p_expect($tokens, "TAG_END", $meta);
my $str = "";
while ($tokens->[0] and not ($tokens->[0]->[0] eq "TAG_START" and $tokens->[1]->[1] eq "endsyntax" and $tokens->[2]->[0] eq "TAG_END")){
$str .= $tokens->[0]->[1];
shift @$tokens;
}
p_expect($tokens, "TAG_START", $meta);
p_expect($tokens, "KEYWORD", $meta);
p_expect($tokens, "TAG_END", $meta);
return do_hilight($str, $lang, $meta);
}
sub do_hilight {
my ($str, $lang, $meta) = @_;
if ($lang eq 'escape'){
return encode_entities($str);
}
eval {
no warnings "all";
require Text::VimColor;
};
if ($@){
# require was not successfull
print STDERR " Not syntax hilighting, Text::VimColor not found\n" unless $config{quiet};
# encode at least some special chars "by hand"
return encode_entities($str);
} else {
print STDERR "." unless $config{quiet};
# any encoding will do if vim automatically detects it
my $vim_encoding = 'utf-8';
my $BOM = "\x{feff}";
my $syn = Text::VimColor->new(
filetype => $lang,
string => encode($vim_encoding, $BOM . $str),
);
$str = decode($vim_encoding, $syn->html);
$str =~ s/^$BOM//;
return $str;
}
}
# parse sub: expect a specific token, return its content or die if the
# expectation was not met.
sub p_expect {
( run in 2.308 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )