Home | History | Annotate | Download | only in Runtime
      1 package ANTLR::Runtime::CommonTokenStream;
      2 
      3 use Carp;
      4 use Readonly;
      5 use UNIVERSAL qw( isa );
      6 
      7 use ANTLR::Runtime::CharStream;
      8 use ANTLR::Runtime::Token;
      9 use ANTLR::Runtime::TokenSource;
     10 
     11 use Moose;
     12 
     13 use overload
     14     '""' => \&str
     15     ;
     16 
     17 with 'ANTLR::Runtime::IntStream',
     18      'ANTLR::Runtime::TokenStream';
     19 
     20 has 'token_source' => (
     21     is  => 'rw',
     22     does => 'ANTLR::Runtime::TokenSource',
     23 );
     24 
     25 has 'tokens' => (
     26     is  => 'rw',
     27     isa => 'ArrayRef[ANTLR::Runtime::Token]',
     28     default => sub { [] },
     29 );
     30 
     31 has 'channel_override_map' => (
     32     is  => 'rw',
     33     isa => 'HashRef[Int]',
     34 );
     35 
     36 has 'discard_set' => (
     37     is  => 'rw',
     38     isa => 'HashRef[Int]',
     39 );
     40 
     41 has 'channel' => (
     42     is  => 'rw',
     43     isa => 'Int',
     44     default => ANTLR::Runtime::Token->DEFAULT_CHANNEL,
     45 );
     46 
     47 has 'discard_off_channel_tokens' => (
     48     is  => 'rw',
     49     isa => 'Bool',
     50     default => 0,
     51 );
     52 
     53 has 'last_marker' => (
     54     is  => 'rw',
     55     isa => 'Int',
     56     default => 0,
     57 );
     58 
     59 has 'p' => (
     60     is  => 'rw',
     61     isa => 'Int',
     62     default => -1,
     63 );
     64 
     65 sub 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 
     74 sub 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 
    109 sub 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 
    118 sub 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 
    129 sub 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 
    139 sub 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 
    149 sub 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 
    159 sub 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 
    210 sub 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 
    242 sub 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 
    269 sub get {
    270     my ($self, $i) = @_;
    271 
    272     return $self->tokens->[$i];
    273 }
    274 
    275 sub LA {
    276     my ($self, $i) = @_;
    277 
    278     return $self->LT($i)->get_type();
    279 }
    280 
    281 sub 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 
    291 sub release {
    292     my ($self, $marker) = @_;
    293 
    294     # no resources to release
    295 }
    296 
    297 sub size {
    298     my ($self) = @_;
    299 
    300     return scalar @{$self->tokens};
    301 }
    302 
    303 sub index {
    304     my ($self) = @_;
    305 
    306     return $self->p;
    307 }
    308 
    309 sub 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 
    322 sub seek {
    323     my ($self, $index) = @_;
    324 
    325     $self->p($index);
    326 }
    327 
    328 sub get_token_source {
    329     my ($self) = @_;
    330 
    331     return $self->token_source;
    332 }
    333 
    334 sub get_source_name {
    335     my ($self) = @_;
    336     return $self->get_token_source()->get_source_name();
    337 }
    338 
    339 sub str {
    340     my ($self) = @_;
    341     return $self->to_string();
    342 }
    343 
    344 sub 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 
    389 no Moose;
    390 __PACKAGE__->meta->make_immutable();
    391 1;
    392 __END__
    393