File Coverage

blib/lib/HOI/Match.pm
Criterion Covered Total %
statement 73 75 97.3
branch 26 30 86.6
condition 8 12 66.6
subroutine 12 12 100.0
pod 1 4 25.0
total 120 133 90.2


line stmt bran cond sub pod time code
1             package HOI::Match;
2              
3             require Exporter;
4              
5 2     2   40706 use Parse::Lex;
  2         39495  
  2         61  
6 2     2   1126 use HOI::typeparser;
  2         16  
  2         1782  
7              
8             our @ISA = qw( Exporter );
9             our @EXPORT_OK = qw( pmatch );
10             our $VERSION = '0.072';
11              
12             my @tokens = (
13             qw (
14             LPAREN [\(]
15             RPAREN [\)]
16             CONCAT ::
17             STRCONCAT [:]
18             NIL nil
19             IDENT [A-Za-z_][A-Za-z0-9_]*
20             CONST (?:0(?:\.[0-9]+)?)|(?:[1-9][0-9]*(?:\.[0-9]+)?)|(?:\".*\")|(?:\'.*\')
21             ),
22             COMMA => q/,/
23             );
24              
25             my $lexer = Parse::Lex->new(@tokens);
26             $lexer->skip('\s+');
27             my $parser = HOI::typeparser->new();
28              
29             sub lexana {
30 102     102 0 3985 my $token = $lexer->next;
31 102 100       4926 if (not $lexer->eoi) {
32 74         335 return ($token->name, $token->text);
33             } else {
34 28         131 return ('', undef);
35             }
36             }
37              
38             my %compiled_patterns;
39              
40             sub pcompile {
41 28     28 0 115 $lexer->from(shift);
42 28         14141 $parser->YYParse(yylex => \&lexana)
43             }
44              
45             sub astmatch {
46 230     230 0 232 my ($ast, $args) = @_;
47 230 50       172 return (0, {}) if ($#{$ast} ne $#{$args});
  230         263  
  230         466  
48             my %switches = (
49             "const" =>
50             sub {
51 76     76   109 my ($sym, $val) = @_;
52 76 100 66     350 if( (substr($sym, 0, 1) eq '\'') or (substr($sym, 0, 1) eq '"') ) {
53 64         85 my $quote = substr($sym, 0, 1);
54 64 100       219 return ($sym eq $quote.$val.$quote) ? (1, {}) : (0, {});
55             } else {
56 12 100       39 return ($sym == $val) ? (1, {}) : (0, {});
57             }
58             },
59             "any" =>
60             sub {
61 116     116   156 my ($sym, $val) = @_;
62 116 100       356 (1, ((substr($sym, 0, 1) ne '_') ? { $sym => $val } : {}))
63             },
64             "list" =>
65             sub {
66 28     28   31 my ($l, $val) = @_;
67 28 100 100     23 if (($#{$l} >= 0) and ($#{$val} >= 0)) {
  28 100 66     62  
  24         73  
  8         27  
68 20         56 my ($s1, $r1) = astmatch([ $l->[0] ], [ $val->[0] ]);
69 20         40 my ($s2, $r2) = astmatch([ $l->[1] ], [ [ @$val[1..$#{$val}] ] ]);
  20         50  
70 20         80 return ($s1 * $s2, { %$r1, %$r2 });
71 4         11 } elsif (($#{$l} < 0) and ($#{$val} < 0)) {
72 4         8 return (1, {});
73             } else {
74 4         7 return (0, {});
75             }
76             },
77             "adt" =>
78             sub {
79 12     12   15 my ($adt, $val) = @_;
80 12 50 33     42 return (0, {}) if ((not defined $val->{"type"}) or (not defined $val->{"val"}));
81 12         19 my ($sym, $typelist) = ($adt->[0], $adt->[1]);
82 12 50       28 return (0, {}) if ($adt->[0] ne $val->{"type"});
83 12 100       8 return (0, {}) if ($#{$adt->[1]} != $#{$val->{"val"}});
  12         16  
  12         25  
84 10         27 astmatch($adt->[1], $val->{"val"})
85             },
86             "strspl" =>
87             sub {
88 10     10   10 my ($idents, $val) = @_;
89 10         12 my ($x, $xs);
90 10 50       47 if ( ($x, $xs) = ($val =~ /(.)(.*)/s) ) {
91 10         31 return (1, { $idents->[0] => $x, $idents->[1] => $xs });
92             } else {
93 0         0 return (0, {});
94             }
95             }
96 230         2216 );
97 230         288 my $ret = {};
98 230         240 for (my $idx = 0; $idx <= $#{$ast}; $idx++) {
  396         714  
99 242         546 my ($status, $result) = $switches{$ast->[$idx]->{"kind"}}->($ast->[$idx]->{"val"}, $args->[$idx]);
100 242 100       325 if ($status) {
101 166         585 $ret = { %$ret, %$result };
102             } else {
103 76         1114 return (0, {})
104             }
105             }
106 154         1824 (1, $ret)
107             }
108              
109             sub pmatch {
110 104     104 1 8512 my $patterns = \@_;
111             sub {
112 104     104   125 my $args = \@_;
113 104         241 while (@$patterns) {
114 180         219 my $pattern = shift @$patterns;
115 180         176 my $handler = shift @$patterns;
116 180         787 my $pattern_sig = (caller(1))[3].$pattern;
117 180 100       469 $compiled_patterns{$pattern_sig} = pcompile($pattern) if (not defined $compiled_patterns{$pattern_sig});
118 180         1998 my $pattern_ast = $compiled_patterns{$pattern_sig};
119 180         327 my ($status, $results) = astmatch($pattern_ast, $args);
120 180 100       409 if ($status) {
121 104         309 my ($package) = caller(1);
122 104         169 local $AttrPrefix = $package.'::';
123             #attr $results;
124 104         89 my $evalstr = '';
125 104         224 for my $key (keys %$results) {
126 124         370 $evalstr .= 'local $'."$AttrPrefix"."$key".' = $results->{'."$key".'}; ';
127             }
128 104         7027 return eval "{ $evalstr ".'$handler->(%$results); }';
129             }
130             }
131             0
132 0           }
133 104         432 }
134              
135             1;
136             __END__