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