File Coverage

blib/lib/Pugs/Emitter/Grammar/Perl5.pm
Criterion Covered Total %
statement 9 52 17.3
branch 0 28 0.0
condition 0 17 0.0
subroutine 3 5 60.0
pod 1 1 100.0
total 13 103 12.6


line stmt bran cond sub pod time code
1             package Pugs::Emitter::Grammar::Perl5;
2              
3             our $VERSION = '0.28';
4              
5             #use Smart::Comments;
6 1     1   4 use strict;
  1         2  
  1         36  
7 1     1   5 use warnings;
  1         2  
  1         27  
8 1     1   674 use Pugs::Emitter::Rule::Perl5::Ratchet;
  1         4  
  1         620  
9              
10             # for safe mode
11             sub _prune_actions {
12 0     0     my ($ast) = @_;
13 0           while (my ($key, $node) = each %$ast) {
14 0 0 0       next if $key =~ /^_/ or !ref $node;
15             #warn $key;
16 0 0         if ($key eq 'closure') {
17             #die "Found closures!";
18 0 0         next if ref $node ne 'HASH';
19 0           my $code = $node->{closure};
20 0 0 0       if ($code and !ref $code and $code =~ /\w+/) {
      0        
21 0           die "ERROR: code blocks not allowed in safe mode: \"$code\"\n";
22             }
23             }
24 0 0         if (ref $node) {
25 0           my $ref = ref $node;
26 0 0         if ($ref eq 'HASH') {
    0          
27 0           _prune_actions($node);
28             } elsif ($ref eq 'ARRAY') {
29 0           for my $child (@$node) {
30 0 0 0       if (ref $child and ref $child eq 'HASH') {
31 0           _prune_actions($child);
32             }
33             }
34             }
35             }
36             }
37             }
38              
39             sub emit {
40 0     0 1   my $ast = shift;
41 0           my $opts = shift;
42 0   0       $opts ||= {};
43             ## $ast
44 0           my ($name, $stmts) = each %$ast;
45 0           my $p5_methods = '';
46             ### $name
47 0           for my $stmt (@$stmts) {
48 0           my $regex = $stmt->();
49 0           my $type = $regex->{type};
50             ## $regex
51 0 0         if ($type eq 'block') {
52 0           my $code = $regex->{value};
53 0 0 0       if ($opts->{safe_mode} && $code =~ /\w+/) {
54 0           die "ERROR: verbatim Perl 5 blocks not allowed in safe mode: \"$code\"\n";
55             }
56 0           $p5_methods .= <<"_EOC_";
57             # Code block from grammar spec
58             $code
59              
60             _EOC_
61 0           next;
62             }
63             ### struct: $regex->{name}
64             ## regex AST: $regex->{ast}
65 0           my $params = {};
66 0 0         if ($type eq 'rule') {
67 0           $params->{sigspace} = 1;
68             }
69 0           my $body;
70              
71 0           my $ast = $regex->{ast};
72 0 0         if ($opts->{safe_mode}) {
73 0           _prune_actions($ast);
74             }
75              
76 0 0         if ($type eq 'regex') {
77 0           $body = Pugs::Emitter::Rule::Perl5::emit(
78             'Pugs::Grammar::Rule',
79             $ast,
80             )
81             } else {
82 0           $body = Pugs::Emitter::Rule::Perl5::Ratchet::emit(
83             'Pugs::Grammar::Rule',
84             $ast,
85             $params,
86             );
87             }
88 0           $body =~ s/^/ /gm;
89 0           $p5_methods .= <<_EOC_;
90             # $regex->{type} $regex->{name}
91             *$regex->{name} =
92             $body;
93              
94             _EOC_
95             }
96             # bootstrap the regex parser itself:
97 0 0         my $prefix = $name eq 'Pugs::Grammar::Rule' ?
98             "#" : '';
99 0           return <<"_EOC_";
100             package $name;
101              
102             ${prefix}use base 'Pugs::Grammar::Base';
103              
104             use Pugs::Runtime::Match;
105             use Pugs::Runtime::Regex;
106             use Pugs::Runtime::Tracer ();
107              
108             $p5_methods
109              
110             1;
111             _EOC_
112             }
113              
114             1;
115             __END__