blob: d1f0ef17f09c2ae06ff8ab6d4b125c5220ac7886 [file] [log] [blame]
package ANTLR::Runtime::DFA;
use Params::Validate qw( :types );
use Error qw( try finally );
use Moose;
has 'eot' => (
is => 'rw',
isa => 'ArrayRef[Int]',
);
has 'eof' => (
is => 'rw',
isa => 'ArrayRef[Int]',
);
has 'min' => (
is => 'rw',
isa => 'ArrayRef[Str]',
);
has 'max' => (
is => 'rw',
isa => 'ArrayRef[Str]',
);
has 'accept' => (
is => 'rw',
isa => 'ArrayRef[Int]',
);
has 'special' => (
is => 'rw',
isa => 'ArrayRef[Int]',
);
has 'transition' => (
is => 'rw',
isa => 'ArrayRef[ArrayRef[Int]]',
);
has 'decision_number' => (
is => 'rw',
isa => 'Int',
);
# Which recognizer encloses this DFA? Needed to check backtracking
has 'recognizer' => (
is => 'rw',
isa => 'ANTLR::Runtime::BaseRecognizer',
);
sub get_description {
return "n/a";
}
# From the input stream, predict what alternative will succeed
# using this DFA (representing the covering regular approximation
# to the underlying CFL). Return an alternative number 1..n. Throw
# an exception upon error.
sub predict {
my ($self, $input) = @_;
my $mark = $input->mark(); # remember where decision started in input
my $s = 0; # we always start at s0
try {
while (1) {
my $special_state = $self->special->[$s];
if ($special_state >= 0) {
$s = $self->special_state_transition($special_state, $input);
if ($s == -1) {
$self->no_viable_alt($s, $input);
return 0;
}
$input->consume();
next;
}
if ($self->accept->[$s] >= 1) {
return $self->accept->[$s];
}
# look for a normal char transition
my $c = $input->LA(1); # -1 == \uFFFF, all tokens fit in 65000 space
if ($c >= $self->min->[$s] && $c <= $self->max->[$s]) {
my $next_s = $self->transition->[$s][$c - $self->min->[$s]]; # move to next state
if ($next_s < 0) {
# was in range but not a normal transition
# must check EOT, which is like the else clause.
# eot[s]>=0 indicates that an EOT edge goes to another
# state.
if ($self->eot->[$s] >= 0) { # EOT Transition to accept state?
$s = $self->eot->[$s];
$input->consume();
# TODO: I had this as return accept[eot[s]]
# which assumed here that the EOT edge always
#went to an accept...faster to do this, but
# what about predicated edges coming from EOT
# target?
next;
}
$self->no_viable_alt($s, $input);
return 0;
}
$s = $next_s;
$input->consume();
next;
}
if ($self->eot->[$s] >= 0) { # EOT Transition?
$s = $self->eot->[$s];
$input->consume();
next;
}
if ($c == ANTLR::Runtime::Token->EOF && $self->eof->[$s] >= 0) { # EOF Transition to accept state?
return $self->accept->[$self->eof->[$s]];
}
# not in range and not EOF/EOT, must be invalid symbol
$self->no_viable_alt($s, $input);
return 0;
}
}
finally {
$input->rewind();
};
}
sub no_viable_alt {
my ($self, $s, $input) = @_;
if ($self->recognizer->state->backtracking > 0) {
$self->recognizer->state->failed = 1;
return;
}
my $nvae = ANTLR::Runtime::NoViableAltException({
grammar_decision_description => $self->get_description(),
decision_number => $self->decision_number,
state_number => $self->state_number,
input => $input
});
$self->error($nvae);
$nvae->throw();
}
# A hook for debugging interface
sub error {
my ($self, $nvae) = @_;
}
sub special_state_transition {
my ($self, $s, $input) = @_;
return -1;
}
# Given a String that has a run-length-encoding of some unsigned shorts
# like "\1\2\3\9", convert to short[] {2,9,9,9}. We do this to avoid
# static short[] which generates so much init code that the class won't
# compile. :(
sub unpack_encoded_string {
my ($self, $encoded_string) = @_;
my $data = [];
while ($encoded_string =~ /(.)(.)/gxms) {
my ($n, $v) = ($1, $2);
push @$data, $v x $n;
}
return $data;
}
sub unpack_encoded_string_to_unsigned_chars {
my ($self, $encoded_string) = @_;
return $self->unpack_encoded_string($encoded_string);
}
no Moose;
__PACKAGE__->meta->make_immutable();
1;
__END__