1package ANTLR::Runtime::CommonTokenStream; 2 3use Carp; 4use Readonly; 5use UNIVERSAL qw( isa ); 6 7use ANTLR::Runtime::CharStream; 8use ANTLR::Runtime::Token; 9use ANTLR::Runtime::TokenSource; 10 11use Moose; 12 13use overload 14 '""' => \&str 15 ; 16 17with 'ANTLR::Runtime::IntStream', 18 'ANTLR::Runtime::TokenStream'; 19 20has 'token_source' => ( 21 is => 'rw', 22 does => 'ANTLR::Runtime::TokenSource', 23); 24 25has 'tokens' => ( 26 is => 'rw', 27 isa => 'ArrayRef[ANTLR::Runtime::Token]', 28 default => sub { [] }, 29); 30 31has 'channel_override_map' => ( 32 is => 'rw', 33 isa => 'HashRef[Int]', 34); 35 36has 'discard_set' => ( 37 is => 'rw', 38 isa => 'HashRef[Int]', 39); 40 41has 'channel' => ( 42 is => 'rw', 43 isa => 'Int', 44 default => ANTLR::Runtime::Token->DEFAULT_CHANNEL, 45); 46 47has 'discard_off_channel_tokens' => ( 48 is => 'rw', 49 isa => 'Bool', 50 default => 0, 51); 52 53has 'last_marker' => ( 54 is => 'rw', 55 isa => 'Int', 56 default => 0, 57); 58 59has 'p' => ( 60 is => 'rw', 61 isa => 'Int', 62 default => -1, 63); 64 65sub set_token_source { 66 my ($self, $token_source) = @_; 67 68 $self->token_source($token_source); 69 $self->tokens([]); 70 $self->p(-1); 71 $self->channel(ANTLR::Runtime::Token->DEFAULT_CHANNEL); 72} 73 74sub fill_buffer { 75 my ($self) = @_; 76 77 my $index = 0; 78 my $t = $self->token_source->next_token(); 79 while (defined $t && $t->get_type() != ANTLR::Runtime::CharStream->EOF) { 80 my $discard = 0; 81 # is there a channel override for token type? 82 if (defined $self->channel_override_map) { 83 my $channel = $self->channel_override_map->{$t->get_type()}; 84 if (defined $channel) { 85 $t->set_channel($channel); 86 } 87 } 88 89 if (defined $self->discard_set && $self->discard_set->contains($t->get_type())) { 90 $discard = 1; 91 } elsif ($self->discard_off_channel_tokens && $t->get_channel() != $self->channel) { 92 $discard = 1; 93 } 94 95 if (!$discard) { 96 $t->set_token_index($index); 97 push @{$self->tokens}, $t; 98 ++$index; 99 } 100 } continue { 101 $t = $self->token_source->next_token(); 102 } 103 104 # leave p pointing at first token on channel 105 $self->p(0); 106 $self->skip_off_token_channels($self->p); 107} 108 109sub consume { 110 my ($self) = @_; 111 112 if ($self->p < @{$self->tokens}) { 113 $self->p($self->p + 1); 114 $self->p($self->skip_off_token_channels($self->p)); # leave p on valid token 115 } 116} 117 118sub skip_off_token_channels { 119 my ($self, $i) = @_; 120 121 my $n = @{$self->tokens}; 122 while ($i < $n && $self->tokens->[$i]->get_channel() != $self->channel) { 123 ++$i; 124 } 125 126 return $i; 127} 128 129sub skip_off_token_channels_reverse { 130 my ($self, $i) = @_; 131 132 while ($i >= 0 && $self->tokens->[$i]->get_channel() != $self->channel) { 133 --$i; 134 } 135 136 return $i; 137} 138 139sub set_token_type_channel { 140 my ($self, $ttype, $channel) = @_; 141 142 if (!defined $self->channel_override_map) { 143 $self->channel_override_map({}); 144 } 145 146 $self->channel_override_map->{$ttype} = $channel; 147} 148 149sub discard_token_type { 150 my ($self, $ttype) = @_; 151 152 if (!defined $self->discard_set) { 153 $self->discard_set({}); 154 } 155 156 $self->discard_set->{$ttype} = 1; 157} 158 159sub get_tokens { 160 my ($self, $args) = @_; 161 162 if ($self->p == -1) { 163 $self->fill_buffer(); 164 } 165 if (!defined $args) { 166 return $self->tokens; 167 } 168 169 my $start = $args->{start}; 170 my $stop = $args->{stop}; 171 172 my $types; 173 if (exists $args->{types}) { 174 if (ref $args->{types} eq 'ARRAY') { 175 $types = ANTLR::Runtime::BitSet->new($args->{types}); 176 } else { 177 $types = $args->{types}; 178 } 179 } else { 180 my $ttype = $args->{ttype}; 181 $types = ANTLR::Runtime::BitSet->of($ttype); 182 } 183 184 185 if ($stop >= @{$self->tokens}) { 186 $stop = $#{$self->tokens}; 187 } 188 if ($start < 0) { 189 $start = 0; 190 } 191 192 if ($start > $stop) { 193 return undef; 194 } 195 196 my $filtered_tokens = []; 197 foreach my $t (@{$self->tokens}[$start..$stop]) { 198 if (!defined $types || $types->member($t->get_type())) { 199 push @$filtered_tokens, $t; 200 } 201 } 202 203 if (!@{$filtered_tokens}) { 204 $filtered_tokens = undef; 205 } 206 207 return $filtered_tokens; 208} 209 210sub LT { 211 my ($self, $k) = @_; 212 213 if ($self->p == -1) { 214 $self->fill_buffer(); 215 } 216 if ($k == 0) { 217 return undef; 218 } 219 if ($k < 0) { 220 return $self->LB(-$k); 221 } 222 223 if ($self->p + $k - 1 >= @{$self->tokens}) { 224 return ANTLR::Runtime::Token->EOF_TOKEN; 225 } 226 227 my $i = $self->p; 228 my $n = 1; 229 230 while ($n < $k) { 231 $i = $self->skip_off_token_channels($i+1); 232 ++$n; 233 } 234 235 if ($i >= @{$self->tokens}) { 236 return ANTLR::Runtime::Token->EOF_TOKEN; 237 } 238 239 return $self->tokens->[$i]; 240} 241 242sub LB { 243 my ($self, $k) = @_; 244 245 if ($self->p == -1) { 246 $self->fill_buffer(); 247 } 248 if ($k == 0) { 249 return undef; 250 } 251 if ($self->p - $k < 0) { 252 return undef; 253 } 254 255 my $i = $self->p; 256 my $n = 1; 257 while ($n <= $k) { 258 $k = $self->skip_off_token_channels_reverse($i - 1); 259 ++$n; 260 } 261 262 if ($i < 0) { 263 return undef; 264 } 265 266 return $self->tokens->[$i]; 267} 268 269sub get { 270 my ($self, $i) = @_; 271 272 return $self->tokens->[$i]; 273} 274 275sub LA { 276 my ($self, $i) = @_; 277 278 return $self->LT($i)->get_type(); 279} 280 281sub mark { 282 my ($self) = @_; 283 284 if ($self->p == -1) { 285 $self->fill_buffer(); 286 } 287 $self->last_marker($self->index()); 288 return $self->last_marker; 289} 290 291sub release { 292 my ($self, $marker) = @_; 293 294 # no resources to release 295} 296 297sub size { 298 my ($self) = @_; 299 300 return scalar @{$self->tokens}; 301} 302 303sub index { 304 my ($self) = @_; 305 306 return $self->p; 307} 308 309sub rewind { 310 Readonly my $usage => 'void rewind(int marker) | void rewind()'; 311 croak $usage if @_ != 1 && @_ != 2; 312 313 if (@_ == 1) { 314 my ($self) = @_; 315 $self->seek($self->last_marker); 316 } else { 317 my ($self, $marker) = @_; 318 $self->seek($marker); 319 } 320} 321 322sub seek { 323 my ($self, $index) = @_; 324 325 $self->p($index); 326} 327 328sub get_token_source { 329 my ($self) = @_; 330 331 return $self->token_source; 332} 333 334sub get_source_name { 335 my ($self) = @_; 336 return $self->get_token_source()->get_source_name(); 337} 338 339sub str { 340 my ($self) = @_; 341 return $self->to_string(); 342} 343 344sub to_string { 345 Readonly my $usage => 'String to_string() | String to_string(int start, int stop | String to_string(Token start, Token stop)'; 346 croak $usage if @_ != 1 && @_ != 3; 347 348 if (@_ == 1) { 349 my ($self) = @_; 350 351 if ($self->p == -1) { 352 $self->fill_buffer(); 353 } 354 return $self->to_string(0, $#{$self->tokens}); 355 } else { 356 my ($self, $start, $stop) = @_; 357 358 if (defined $start && defined $stop) { 359 if (ref($start) && $start->isa('ANTLR::Runtime::Token')) { 360 $start = $start->get_token_index(); 361 } 362 363 if (ref($start) && $stop->isa('ANTLR::Runtime::Token')) { 364 $stop = $stop->get_token_index(); 365 } 366 367 if ($start < 0 || $stop < 0) { 368 return undef; 369 } 370 if ($self->p == -1) { 371 $self->fill_buffer(); 372 } 373 if ($stop >= @{$self->tokens}) { 374 $stop = $#{$self->tokens}; 375 } 376 377 my $buf = ''; 378 foreach my $t (@{$self->tokens}[$start..$stop]) { 379 $buf .= $t->get_text(); 380 } 381 382 return $buf; 383 } else { 384 return undef; 385 } 386 } 387} 388 389no Moose; 390__PACKAGE__->meta->make_immutable(); 3911; 392__END__ 393