File Coverage

blib/lib/HOI/Match.pm
Criterion Covered Total %
statement 69 70 98.5
branch 25 28 89.2
condition 8 12 66.6
subroutine 11 11 100.0
pod 1 4 25.0
total 114 125 91.2


line stmt bran cond sub pod time code
1             package HOI::Match;
2              
3             require Exporter;
4              
5 2     2   33835 use Parse::Lex;
  2         38784  
  2         60  
6 2     2   894 use HOI::typeparser;
  2         14  
  2         1486  
7              
8             our @ISA = qw( Exporter );
9             our @EXPORT_OK = qw( pmatch );
10             our $VERSION = '0.071';
11              
12             my @tokens = (
13             qw (
14             LPAREN [\(]
15             RPAREN [\)]
16             CONCAT ::
17             NIL nil
18             IDENT [A-Za-z_][A-Za-z0-9_]*
19             CONST (?:0(?:\.[0-9]+)?)|(?:[1-9][0-9]*(?:\.[0-9]+)?)|(?:\".+\")|(?:\'.+\')
20             ),
21             COMMA => q/,/
22             );
23              
24             my $lexer = Parse::Lex->new(@tokens);
25             $lexer->skip('\s+');
26             my $parser = HOI::typeparser->new();
27              
28             sub lexana {
29 90     90 0 3652 my $token = $lexer->next;
30 90 100       4417 if (not $lexer->eoi) {
31 66         305 return ($token->name, $token->text);
32             } else {
33 24         121 return ('', undef);
34             }
35             }
36              
37             my %compiled_patterns;
38              
39             sub pcompile {
40 24     24 0 95 $lexer->from(shift);
41 24         12500 $parser->YYParse(yylex => \&lexana)
42             }
43              
44             sub astmatch {
45 208     208 0 186 my ($ast, $args) = @_;
46 208 50       154 return (0, {}) if ($#{$ast} ne $#{$args});
  208         225  
  208         470  
47             my %switches = (
48             "const" =>
49             sub {
50 64     64   88 my ($sym, $val) = @_;
51 64 100 66     339 if( (substr($sym, 0, 1) eq '\'') or (substr($sym, 0, 1) eq '"') ) {
52 52         68 my $quote = substr($sym, 0, 1);
53 52 100       160 return ($sym eq $quote.$val.$quote) ? (1, {}) : (0, {});
54             } else {
55 12 100       45 return ($sym == $val) ? (1, {}) : (0, {});
56             }
57             },
58             "any" =>
59             sub {
60 116     116   148 my ($sym, $val) = @_;
61 116 100       350 (1, ((substr($sym, 0, 1) ne '_') ? { $sym => $val } : {}))
62             },
63             "list" =>
64             sub {
65 28     28   26 my ($l, $val) = @_;
66 28 100 100     25 if (($#{$l} >= 0) and ($#{$val} >= 0)) {
  28 100 66     59  
  24         62  
  8         22  
67 20         52 my ($s1, $r1) = astmatch([ $l->[0] ], [ $val->[0] ]);
68 20         39 my ($s2, $r2) = astmatch([ $l->[1] ], [ [ @$val[1..$#{$val}] ] ]);
  20         46  
69 20         83 return ($s1 * $s2, { %$r1, %$r2 });
70 4         10 } elsif (($#{$l} < 0) and ($#{$val} < 0)) {
71 4         7 return (1, {});
72             } else {
73 4         8 return (0, {});
74             }
75             },
76             "adt" =>
77             sub {
78 12     12   13 my ($adt, $val) = @_;
79 12 50 33     38 return (0, {}) if ((not defined $val->{"type"}) or (not defined $val->{"val"}));
80 12         25 my ($sym, $typelist) = ($adt->[0], $adt->[1]);
81 12 50       24 return (0, {}) if ($adt->[0] ne $val->{"type"});
82 12 100       11 return (0, {}) if ($#{$adt->[1]} != $#{$val->{"val"}});
  12         17  
  12         24  
83 10         22 astmatch($adt->[1], $val->{"val"})
84             }
85 208         1647 );
86 208         253 my $ret = {};
87 208         1266 for (my $idx = 0; $idx <= $#{$ast}; $idx++) {
  362         641  
88 220         2693 my ($status, $result) = $switches{$ast->[$idx]->{"kind"}}->($ast->[$idx]->{"val"}, $args->[$idx]);
89 220 100       298 if ($status) {
90 154         520 $ret = { %$ret, %$result };
91             } else {
92 66         1156 return (0, {})
93             }
94             }
95 142         1492 (1, $ret)
96             }
97              
98             sub pmatch {
99 92     92 1 7832 my $patterns = \@_;
100             sub {
101 92     92   114 my $args = \@_;
102 92         228 while (@$patterns) {
103 158         185 my $pattern = shift @$patterns;
104 158         157 my $handler = shift @$patterns;
105 158         603 my $pattern_sig = (caller(1))[3].$pattern;
106 158 100       475 $compiled_patterns{$pattern_sig} = pcompile($pattern) if (not defined $compiled_patterns{$pattern_sig});
107 158         1800 my $pattern_ast = $compiled_patterns{$pattern_sig};
108 158         263 my ($status, $results) = astmatch($pattern_ast, $args);
109 158 100       343 if ($status) {
110 92         283 my ($package) = caller(1);
111 92         158 local $AttrPrefix = $package.'::';
112             #attr $results;
113 92         74 my $evalstr = '';
114 92         200 for my $key (keys %$results) {
115 104         310 $evalstr .= 'local $'."$AttrPrefix"."$key".' = $results->{'."$key".'}; ';
116             }
117 92         6233 return eval "{ $evalstr ".'$handler->(%$results); }';
118             }
119             }
120             0
121 0           }
122 92         424 }
123              
124             1;
125             __END__