| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 1 | package Krawfish::Koral::Query::Class; |
| 2 | use parent 'Krawfish::Koral::Query'; |
| 3 | use Krawfish::Query::Class; |
| Akron | b8aa4f7 | 2017-10-22 12:35:04 +0200 | [diff] [blame] | 4 | use Krawfish::Log; |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 5 | use strict; |
| 6 | use warnings; |
| Akron | 1fe979b | 2017-07-25 14:58:47 +0200 | [diff] [blame] | 7 | use Memoize; |
| 8 | memoize('min_span'); |
| 9 | memoize('max_span'); |
| 10 | |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 11 | |
| Akron | b8aa4f7 | 2017-10-22 12:35:04 +0200 | [diff] [blame] | 12 | use constant DEBUG => 0; |
| Akron | 5b6264f | 2017-07-19 01:14:01 +0200 | [diff] [blame] | 13 | |
| Akron | b8aa4f7 | 2017-10-22 12:35:04 +0200 | [diff] [blame] | 14 | |
| 15 | # Constructor |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 16 | sub new { |
| 17 | my $class = shift; |
| 18 | bless { |
| Akron | 5b6264f | 2017-07-19 01:14:01 +0200 | [diff] [blame] | 19 | operands => [shift], |
| Akron | d6d4dc5 | 2017-07-25 20:09:35 +0200 | [diff] [blame] | 20 | number => shift // 1 |
| Akron | 15fc197 | 2017-07-20 22:53:00 +0200 | [diff] [blame] | 21 | }, $class; |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 22 | }; |
| 23 | |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 24 | |
| 25 | sub type { 'class' }; |
| 26 | |
| Akron | 617871f | 2017-05-27 02:05:31 +0200 | [diff] [blame] | 27 | |
| Akron | 5ddc38f | 2017-07-18 00:16:22 +0200 | [diff] [blame] | 28 | # Remove classes passed as an array references |
| 29 | sub remove_classes { |
| 30 | my ($self, $keep) = @_; |
| 31 | unless ($keep) { |
| 32 | $keep = []; |
| 33 | }; |
| Akron | 617871f | 2017-05-27 02:05:31 +0200 | [diff] [blame] | 34 | |
| Akron | b8aa4f7 | 2017-10-22 12:35:04 +0200 | [diff] [blame] | 35 | if (DEBUG) { |
| 36 | print_log('kq_q_class', 'Remove classes from ' . $self->to_string); |
| 37 | }; |
| 38 | |
| Akron | 5b6264f | 2017-07-19 01:14:01 +0200 | [diff] [blame] | 39 | $self->{operand}->[0] = $self->{operands}->[0]->remove_classes($keep); |
| Akron | 5ddc38f | 2017-07-18 00:16:22 +0200 | [diff] [blame] | 40 | |
| Akron | b8aa4f7 | 2017-10-22 12:35:04 +0200 | [diff] [blame] | 41 | # Check the keep operand |
| Akron | 5ddc38f | 2017-07-18 00:16:22 +0200 | [diff] [blame] | 42 | foreach (@$keep) { |
| Akron | b8aa4f7 | 2017-10-22 12:35:04 +0200 | [diff] [blame] | 43 | if ($_ eq $self->number) { |
| Akron | 5ddc38f | 2017-07-18 00:16:22 +0200 | [diff] [blame] | 44 | return $self; |
| 45 | }; |
| 46 | }; |
| 47 | |
| Akron | b8aa4f7 | 2017-10-22 12:35:04 +0200 | [diff] [blame] | 48 | if (DEBUG) { |
| 49 | print_log('kq_q_class', 'Remove own class ' . $self->number); |
| 50 | }; |
| 51 | |
| Akron | 5ddc38f | 2017-07-18 00:16:22 +0200 | [diff] [blame] | 52 | # Return the span only |
| Akron | b8aa4f7 | 2017-10-22 12:35:04 +0200 | [diff] [blame] | 53 | return $self->operand; |
| Akron | 5ddc38f | 2017-07-18 00:16:22 +0200 | [diff] [blame] | 54 | }; |
| 55 | |
| Akron | 704ec06 | 2017-07-24 15:46:21 +0200 | [diff] [blame] | 56 | # A class always spans its operand span |
| 57 | sub min_span { |
| 58 | $_[0]->operand->min_span; |
| 59 | }; |
| 60 | |
| 61 | |
| 62 | # A class always spans its operand span |
| 63 | sub max_span { |
| 64 | $_[0]->operand->max_span; |
| 65 | }; |
| 66 | |
| Akron | 5ddc38f | 2017-07-18 00:16:22 +0200 | [diff] [blame] | 67 | |
| 68 | # Normalize the class query |
| Akron | 6d0c8d8 | 2017-06-10 14:48:53 +0200 | [diff] [blame] | 69 | sub normalize { |
| 70 | my $self = shift; |
| 71 | |
| Akron | 5ddc38f | 2017-07-18 00:16:22 +0200 | [diff] [blame] | 72 | # Normalize the span |
| Akron | 6d0c8d8 | 2017-06-10 14:48:53 +0200 | [diff] [blame] | 73 | my $span; |
| Akron | 5b6264f | 2017-07-19 01:14:01 +0200 | [diff] [blame] | 74 | unless ($span = $self->operand->normalize) { |
| 75 | $self->copy_info_from($self->operand); |
| Akron | 6d0c8d8 | 2017-06-10 14:48:53 +0200 | [diff] [blame] | 76 | return; |
| 77 | }; |
| 78 | |
| Akron | 852ce87 | 2017-06-26 21:29:51 +0200 | [diff] [blame] | 79 | # Ignore class if span is negative |
| 80 | return $span if $span->is_negative; |
| 81 | |
| Akron | 5ddc38f | 2017-07-18 00:16:22 +0200 | [diff] [blame] | 82 | # Readd the span |
| Akron | 5b6264f | 2017-07-19 01:14:01 +0200 | [diff] [blame] | 83 | $self->operand($span); |
| Akron | 6d0c8d8 | 2017-06-10 14:48:53 +0200 | [diff] [blame] | 84 | return $self; |
| 85 | }; |
| 86 | |
| 87 | |
| Akron | 5ddc38f | 2017-07-18 00:16:22 +0200 | [diff] [blame] | 88 | # Treat the query as if it is root |
| Akron | c552937 | 2017-06-21 15:56:18 +0200 | [diff] [blame] | 89 | sub finalize { |
| 90 | my $self = shift; |
| 91 | |
| 92 | my $span; |
| Akron | 5b6264f | 2017-07-19 01:14:01 +0200 | [diff] [blame] | 93 | unless ($span = $self->operand->finalize) { |
| 94 | $self->copy_info_from($self->operand); |
| Akron | c552937 | 2017-06-21 15:56:18 +0200 | [diff] [blame] | 95 | return; |
| 96 | }; |
| 97 | |
| Akron | 5b6264f | 2017-07-19 01:14:01 +0200 | [diff] [blame] | 98 | $self->operand($span); |
| Akron | c552937 | 2017-06-21 15:56:18 +0200 | [diff] [blame] | 99 | return $self; |
| 100 | }; |
| 101 | |
| 102 | |
| Akron | 48fabe5 | 2017-08-07 16:48:12 +0200 | [diff] [blame] | 103 | # Optimize on segment |
| Akron | 6d0c8d8 | 2017-06-10 14:48:53 +0200 | [diff] [blame] | 104 | sub optimize { |
| Akron | 48fabe5 | 2017-08-07 16:48:12 +0200 | [diff] [blame] | 105 | my ($self, $segment) = @_; |
| Akron | 6d0c8d8 | 2017-06-10 14:48:53 +0200 | [diff] [blame] | 106 | |
| Akron | 48fabe5 | 2017-08-07 16:48:12 +0200 | [diff] [blame] | 107 | my $span = $self->operand->optimize($segment); |
| Akron | 6d0c8d8 | 2017-06-10 14:48:53 +0200 | [diff] [blame] | 108 | |
| 109 | # Span has no match |
| Akron | faf7685 | 2017-07-19 17:37:07 +0200 | [diff] [blame] | 110 | if ($span->max_freq == 0) { |
| Akron | 5a5595b | 2017-09-10 13:00:57 +0200 | [diff] [blame] | 111 | return $self->builder->nowhere; |
| Akron | 6d0c8d8 | 2017-06-10 14:48:53 +0200 | [diff] [blame] | 112 | }; |
| 113 | |
| 114 | return Krawfish::Query::Class->new( |
| 115 | $span, |
| 116 | $self->number |
| 117 | ); |
| 118 | }; |
| 119 | |
| 120 | |
| Akron | 965f5d9 | 2017-01-20 18:38:08 +0100 | [diff] [blame] | 121 | # Iterate over all subqueries and replace them |
| 122 | # if necessary |
| Akron | 6ff7b48 | 2017-02-09 01:29:29 +0100 | [diff] [blame] | 123 | #sub replace_subqueries { |
| 124 | # my ($self, $cb) = @_; |
| 125 | # |
| 126 | # # Check if the subspan should be replaced |
| Akron | 5b6264f | 2017-07-19 01:14:01 +0200 | [diff] [blame] | 127 | # if (my $replace = $cb->($self->operand)) { |
| Akron | 6ff7b48 | 2017-02-09 01:29:29 +0100 | [diff] [blame] | 128 | # |
| 129 | # # Replace |
| 130 | # $self->{span} = $replace; |
| 131 | # }; |
| 132 | #}; |
| Akron | 965f5d9 | 2017-01-20 18:38:08 +0100 | [diff] [blame] | 133 | |
| 134 | |
| Akron | 965f5d9 | 2017-01-20 18:38:08 +0100 | [diff] [blame] | 135 | |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 136 | sub to_string { |
| 137 | my $self = shift; |
| 138 | my $str = '{'; |
| 139 | $str .= $self->number . ':' if $self->number; |
| Akron | 5b6264f | 2017-07-19 01:14:01 +0200 | [diff] [blame] | 140 | return $str . $self->operand->to_string . '}'; |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 141 | }; |
| 142 | |
| Akron | 965f5d9 | 2017-01-20 18:38:08 +0100 | [diff] [blame] | 143 | |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 144 | sub number { |
| 145 | $_[0]->{number}; |
| 146 | }; |
| 147 | |
| Akron | 965f5d9 | 2017-01-20 18:38:08 +0100 | [diff] [blame] | 148 | |
| Akron | 655a10a | 2017-09-11 14:13:18 +0200 | [diff] [blame] | 149 | sub is_anywhere { |
| 150 | $_[0]->operand->is_anywhere; |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 151 | }; |
| 152 | |
| Akron | 965f5d9 | 2017-01-20 18:38:08 +0100 | [diff] [blame] | 153 | |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 154 | sub is_optional { |
| Akron | 5b6264f | 2017-07-19 01:14:01 +0200 | [diff] [blame] | 155 | $_[0]->operand->is_optional; |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 156 | }; |
| 157 | |
| Akron | 965f5d9 | 2017-01-20 18:38:08 +0100 | [diff] [blame] | 158 | |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 159 | sub is_null { |
| Akron | 5b6264f | 2017-07-19 01:14:01 +0200 | [diff] [blame] | 160 | $_[0]->operand->is_null; |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 161 | }; |
| 162 | |
| Akron | 965f5d9 | 2017-01-20 18:38:08 +0100 | [diff] [blame] | 163 | |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 164 | sub is_negative { |
| Akron | 5ddc38f | 2017-07-18 00:16:22 +0200 | [diff] [blame] | 165 | my $self = shift; |
| Akron | 5b6264f | 2017-07-19 01:14:01 +0200 | [diff] [blame] | 166 | my $span = $self->operand; |
| Akron | 5ddc38f | 2017-07-18 00:16:22 +0200 | [diff] [blame] | 167 | if (@_) { |
| 168 | $span->is_negative(@_); |
| 169 | return $self; |
| 170 | }; |
| 171 | return $span->is_negative; |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 172 | }; |
| 173 | |
| Akron | 965f5d9 | 2017-01-20 18:38:08 +0100 | [diff] [blame] | 174 | |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 175 | sub is_extended { |
| Akron | 5b6264f | 2017-07-19 01:14:01 +0200 | [diff] [blame] | 176 | $_[0]->operand->is_extended; |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 177 | }; |
| 178 | |
| Akron | 965f5d9 | 2017-01-20 18:38:08 +0100 | [diff] [blame] | 179 | |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 180 | sub is_extended_right { |
| Akron | 5b6264f | 2017-07-19 01:14:01 +0200 | [diff] [blame] | 181 | $_[0]->operand->is_extended_right; |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 182 | }; |
| 183 | |
| Akron | 965f5d9 | 2017-01-20 18:38:08 +0100 | [diff] [blame] | 184 | |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 185 | sub is_extended_left { |
| Akron | 5b6264f | 2017-07-19 01:14:01 +0200 | [diff] [blame] | 186 | $_[0]->operand->is_extended_left; |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 187 | }; |
| 188 | |
| Akron | 965f5d9 | 2017-01-20 18:38:08 +0100 | [diff] [blame] | 189 | |
| Akron | 1b09c5b | 2016-11-20 15:59:34 +0100 | [diff] [blame] | 190 | sub maybe_unsorded { |
| Akron | 5b6264f | 2017-07-19 01:14:01 +0200 | [diff] [blame] | 191 | $_[0]->operand->maybe_unsorted; |
| Akron | 1b09c5b | 2016-11-20 15:59:34 +0100 | [diff] [blame] | 192 | }; |
| 193 | |
| Akron | 965f5d9 | 2017-01-20 18:38:08 +0100 | [diff] [blame] | 194 | |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 195 | sub is_classed { 1 }; |
| 196 | |
| Akron | 944091b | 2016-11-24 16:40:58 +0100 | [diff] [blame] | 197 | |
| 198 | sub from_koral { |
| 199 | my ($class, $kq) = @_; |
| 200 | my $importer = $class->importer; |
| 201 | |
| 202 | my $nr = $kq->{'classOut'} or warn 'No class defined'; |
| 203 | |
| 204 | # Import operand |
| 205 | my $op = $importer->all($kq->{operands}->[0]); |
| 206 | |
| 207 | return $class->new($op, $nr); |
| 208 | }; |
| 209 | |
| Akron | 965f5d9 | 2017-01-20 18:38:08 +0100 | [diff] [blame] | 210 | |
| Akron | b8aa4f7 | 2017-10-22 12:35:04 +0200 | [diff] [blame] | 211 | # Serialize to KoralQuery |
| 212 | sub to_koral_fragment { |
| 213 | my $self = shift; |
| 214 | return { |
| 215 | '@type' => 'koral:group', |
| 216 | 'operation' => 'operation:class', |
| 217 | 'classOut' => $self->number, |
| 218 | 'operands' => [ |
| 219 | $self->operand->to_koral_fragment |
| 220 | ] |
| 221 | }; |
| 222 | }; |
| 223 | |
| 224 | |
| Akron | e274446 | 2016-11-15 00:21:43 +0100 | [diff] [blame] | 225 | 1; |