Affix
view release on metacpan or search on metacpan
lib/Affix.pm view on Meta::CPAN
sub signature { shift->{name} }
}
package #
Affix::Type::Bitfield {
our @ISA = qw[Affix::Type];
sub signature { my $self = shift; $self->{type}->signature . ':' . $self->{width} }
}
package #
Affix::Type::Enum {
our @ISA = qw[Affix::Type];
use Carp;
sub signature { 'e:' . shift->{type} }
sub resolve {
my $self = shift;
return ( $self->{const_map}, $self->{values_map} ) if defined $self->{values_map};
$self->{const_map} = {};
$self->{values_map} = {};
my $counter = 0;
for my $item ( @{ $self->{elements} } ) {
my ( $name, $final_val );
if ( !ref $item ) {
$name = $item;
$final_val = $counter;
}
elsif ( ref $item eq 'ARRAY' ) {
my $raw_val;
( $name, $raw_val ) = @$item;
if ( $raw_val =~ /^-?\d+$/ ) {
$final_val = $raw_val;
}
elsif ( $raw_val =~ /^0x[0-9a-fA-F]+$/ ) {
$final_val = hex($raw_val);
}
else {
$final_val = $self->_calculate_expr( $raw_val, $self->{const_map} );
}
}
else {
Carp::croak("Enum elements must be Strings or [Name => Value] ArrayRefs");
}
$self->{const_map}->{$name} = $final_val;
$self->{values_map}->{$final_val} //= $name;
$counter = $final_val + 1;
}
return ( $self->{const_map}, $self->{values_map} );
}
sub _calculate_expr {
my ( $self, $expr, $lookup ) = @_;
use integer;
my @tokens = $expr =~ /(0x[0-9a-fA-F]+|\d+|[a-zA-Z_]\w*|<<|>>|&&|\|\||==|!=|<=|>=|[+\-*\/%|&^~!?:()<>])/g;
for my $t (@tokens) {
next if $t =~ /^(?:<<|>>|&&|\|\||==|!=|<=|>=|[+\-*\/%|&^~!?:()<>])$/;
next if $t =~ /^\d+$/;
next if $t =~ /^0x/;
if ( exists $lookup->{$t} ) {
$t = $lookup->{$t};
}
else {
Carp::croak("Enum definition error: Unknown symbol '$t' in expression '$expr'");
}
$t = hex($t) if $t =~ /^0x/;
}
my @output_queue;
my @op_stack;
my %prec = (
'*' => [ 13, 1 ],
'/' => [ 13, 1 ],
'%' => [ 13, 1 ],
'+' => [ 12, 1 ],
'-' => [ 12, 1 ],
'<<' => [ 11, 1 ],
'>>' => [ 11, 1 ],
'<' => [ 10, 1 ],
'<=' => [ 10, 1 ],
'>' => [ 10, 1 ],
'>=' => [ 10, 1 ],
'==' => [ 9, 1 ],
'!=' => [ 9, 1 ],
'&' => [ 8, 1 ],
'^' => [ 7, 1 ],
'|' => [ 6, 1 ],
'&&' => [ 5, 1 ],
'||' => [ 4, 1 ],
'?' => [ 3, 0 ],
':' => [ 3, 0 ],
'unary_plus' => [ 14, 0 ],
'unary_minus' => [ 14, 0 ],
'!' => [ 14, 0 ],
'~' => [ 14, 0 ],
'(' => [ -1, 0 ],
);
my $expect_unary = 1;
for my $token (@tokens) {
if ( $token =~ /^\d+$/ ) { push @output_queue, $token; $expect_unary = 0; }
elsif ( $token eq '(' ) { push @op_stack, $token; $expect_unary = 1; }
elsif ( $token eq ')' ) {
while ( @op_stack && $op_stack[-1] ne '(' ) { push @output_queue, pop @op_stack; }
pop @op_stack;
$expect_unary = 0;
}
elsif ( $token eq '?' ) {
while ( @op_stack && $op_stack[-1] ne '(' && $prec{ $op_stack[-1] }[0] > $prec{$token}[0] ) { push @output_queue, pop @op_stack; }
push @op_stack, $token;
$expect_unary = 1;
}
elsif ( $token eq ':' ) {
while ( @op_stack && $op_stack[-1] ne '?' ) { push @output_queue, pop @op_stack; }
$expect_unary = 1;
}
else {
if ( $expect_unary && ( $token eq '+' || $token eq '-' || $token eq '!' || $token eq '~' ) ) {
$token = $token eq '+' ? 'unary_plus' : $token eq '-' ? 'unary_minus' : $token;
}
elsif ( !exists $prec{$token} ) { Carp::croak("Unknown token '$token'"); }
my $p1 = $prec{$token}[0];
my $assoc = $prec{$token}[1];
while (@op_stack) {
my $top = $op_stack[-1];
last if $top eq '(';
( run in 0.719 second using v1.01-cache-2.11-cpan-39bf76dae61 )