1package ANTLR::Runtime::DFA;
2
3use Params::Validate qw( :types );
4use Error qw( try finally );
5
6use Moose;
7
8has 'eot' => (
9    is  => 'rw',
10    isa => 'ArrayRef[Int]',
11);
12
13has 'eof' => (
14    is  => 'rw',
15    isa => 'ArrayRef[Int]',
16);
17
18has 'min' => (
19    is  => 'rw',
20    isa => 'ArrayRef[Str]',
21);
22
23has 'max' => (
24    is  => 'rw',
25    isa => 'ArrayRef[Str]',
26);
27
28has 'accept' => (
29    is  => 'rw',
30    isa => 'ArrayRef[Int]',
31);
32
33has 'special' => (
34    is  => 'rw',
35    isa => 'ArrayRef[Int]',
36);
37
38has 'transition' => (
39    is  => 'rw',
40    isa => 'ArrayRef[ArrayRef[Int]]',
41);
42
43has 'decision_number' => (
44    is  => 'rw',
45    isa => 'Int',
46);
47
48
49# Which recognizer encloses this DFA?  Needed to check backtracking
50has 'recognizer' => (
51    is  => 'rw',
52    isa => 'ANTLR::Runtime::BaseRecognizer',
53);
54
55
56sub get_description {
57    return "n/a";
58}
59
60# From the input stream, predict what alternative will succeed
61# using this DFA (representing the covering regular approximation
62# to the underlying CFL).  Return an alternative number 1..n.  Throw
63# an exception upon error.
64sub predict {
65    my ($self, $input) = @_;
66
67    my $mark = $input->mark();  # remember where decision started in input
68    my $s = 0; # we always start at s0
69
70    try {
71        while (1) {
72            my $special_state = $self->special->[$s];
73            if ($special_state >= 0) {
74                $s = $self->special_state_transition($special_state, $input);
75                if ($s == -1) {
76                    $self->no_viable_alt($s, $input);
77                    return 0;
78                }
79                $input->consume();
80                next;
81            }
82
83            if ($self->accept->[$s] >= 1) {
84                return $self->accept->[$s];
85            }
86
87	    # look for a normal char transition
88            my $c = $input->LA(1);  # -1 == \uFFFF, all tokens fit in 65000 space
89
90            if ($c >= $self->min->[$s] && $c <= $self->max->[$s]) {
91                my $next_s = $self->transition->[$s][$c - $self->min->[$s]];  # move to next state
92
93                if ($next_s < 0) {
94                    # was in range but not a normal transition
95                    # must check EOT, which is like the else clause.
96                    # eot[s]>=0 indicates that an EOT edge goes to another
97                    # state.
98                    if ($self->eot->[$s] >= 0) {  # EOT Transition to accept state?
99                        $s = $self->eot->[$s];
100                        $input->consume();
101                        # TODO: I had this as return accept[eot[s]]
102                        # which assumed here that the EOT edge always
103                        #went to an accept...faster to do this, but
104                        # what about predicated edges coming from EOT
105                        # target?
106                        next;
107                    }
108
109                    $self->no_viable_alt($s, $input);
110                    return 0;
111                }
112
113                $s = $next_s;
114                $input->consume();
115                next;
116            }
117
118	    if ($self->eot->[$s] >= 0) {  # EOT Transition?
119		$s = $self->eot->[$s];
120		$input->consume();
121		next;
122	    }
123
124	    if ($c == ANTLR::Runtime::Token->EOF && $self->eof->[$s] >= 0) {  # EOF Transition to accept state?
125		return $self->accept->[$self->eof->[$s]];
126	    }
127
128	    # not in range and not EOF/EOT, must be invalid symbol
129	    $self->no_viable_alt($s, $input);
130	    return 0;
131        }
132    }
133    finally {
134	$input->rewind();
135    };
136}
137
138sub no_viable_alt {
139    my ($self, $s, $input) = @_;
140
141    if ($self->recognizer->state->backtracking > 0) {
142	$self->recognizer->state->failed = 1;
143	return;
144    }
145    my $nvae = ANTLR::Runtime::NoViableAltException({
146	grammar_decision_description => $self->get_description(),
147	decision_number => $self->decision_number,
148	state_number => $self->state_number,
149	input => $input
150    });
151    $self->error($nvae);
152    $nvae->throw();
153}
154
155# A hook for debugging interface
156sub error {
157    my ($self, $nvae) = @_;
158}
159
160sub special_state_transition {
161    my ($self, $s, $input) = @_;
162
163    return -1;
164}
165
166# Given a String that has a run-length-encoding of some unsigned shorts
167# like "\1\2\3\9", convert to short[] {2,9,9,9}.  We do this to avoid
168# static short[] which generates so much init code that the class won't
169# compile. :(
170sub unpack_encoded_string {
171    my ($self, $encoded_string) = @_;
172
173    my $data = [];
174    while ($encoded_string =~ /(.)(.)/gxms) {
175        my ($n, $v) = ($1, $2);
176
177        push @$data, $v x $n;
178    }
179
180    return $data;
181}
182
183sub unpack_encoded_string_to_unsigned_chars {
184    my ($self, $encoded_string) = @_;
185
186    return $self->unpack_encoded_string($encoded_string);
187}
188
189no Moose;
190__PACKAGE__->meta->make_immutable();
1911;
192__END__
193