166 lines
4.8 KiB
Perl
166 lines
4.8 KiB
Perl
package Enum;
|
|
|
|
use utf8;
|
|
use strict;
|
|
use warnings;
|
|
|
|
BEGIN {
|
|
use Exporter ();
|
|
our $VERSION = 1.00;
|
|
our @ISA = qw(Exporter);
|
|
our @EXPORT = qw( &render_enum_core &render_enum_type );
|
|
our %EXPORT_TAGS = ( ); # eg: TAG => [ qw!name1 name2! ],
|
|
our @EXPORT_OK = qw( );
|
|
}
|
|
|
|
END { }
|
|
|
|
use XML::LibXML;
|
|
|
|
use Common;
|
|
|
|
sub render_enum_core($$) {
|
|
my ($name,$tag) = @_;
|
|
|
|
my $base = 0;
|
|
|
|
emit_block {
|
|
my @items = $tag->findnodes('child::enum-item');
|
|
my $idx = 0;
|
|
|
|
for my $item (@items) {
|
|
my $name = ensure_name $item->getAttribute('name');
|
|
my $value = $item->getAttribute('value');
|
|
|
|
$base = ($idx == 0) ? $value : undef if defined $value;
|
|
$idx++;
|
|
|
|
emit $name, (defined($value) ? ' = '.$value : ''), ',';
|
|
}
|
|
|
|
emit "_last_item_of_$name";
|
|
} "enum $name ", ";";
|
|
|
|
return $base;
|
|
}
|
|
|
|
sub render_enum_tables($$$) {
|
|
my ($name,$tag,$base) = @_;
|
|
|
|
# Enumerate enum attributes
|
|
|
|
my %aidx = ('key' => 0);
|
|
my @anames = ('key');
|
|
my @avals = ('NULL');
|
|
my @atypes = ('const char*');
|
|
my @atnames = (undef);
|
|
my @aprefix = ('');
|
|
|
|
for my $attr ($tag->findnodes('child::enum-attr')) {
|
|
my $name = $attr->getAttribute('name') or die "Unnamed enum-attr.\n";
|
|
my $type = decode_type_name_ref $attr;
|
|
my $def = $attr->getAttribute('default-value');
|
|
|
|
my $base_tname = ($type && $type =~ /::(.*)$/ ? $1 : '');
|
|
$type = $base_tname if $base_tname eq $typename;
|
|
|
|
die "Duplicate attribute $name.\n" if exists $aidx{$name};
|
|
|
|
check_name $name;
|
|
$aidx{$name} = scalar @anames;
|
|
push @anames, $name;
|
|
push @atnames, $type;
|
|
|
|
if ($type) {
|
|
push @atypes, $type;
|
|
push @aprefix, ($base_tname ? $base_tname."::" : '');
|
|
push @avals, (defined $def ? $aprefix[-1].$def : "($type)0");
|
|
} else {
|
|
push @atypes, 'const char*';
|
|
push @avals, (defined $def ? "\"$def\"" : 'NULL');
|
|
push @aprefix, '';
|
|
}
|
|
}
|
|
|
|
# Emit accessor function prototypes
|
|
|
|
emit "const $name _first_item_of_$name = ($name)$base;";
|
|
|
|
emit_block {
|
|
emit "return (value >= _first_item_of_$name && value < _last_item_of_$name);";
|
|
} "inline bool is_valid($name value) ";
|
|
|
|
for (my $i = 0; $i < @anames; $i++) {
|
|
emit "${export_prefix}$atypes[$i] get_$anames[$i]($name value);";
|
|
}
|
|
|
|
# Emit implementation
|
|
|
|
with_emit_static {
|
|
emit_block {
|
|
emit_block {
|
|
# Emit the entry type
|
|
emit_block {
|
|
for (my $i = 0; $i < @anames; $i++) {
|
|
emit "$atypes[$i] $anames[$i];";
|
|
}
|
|
} "struct _info_entry ", ";";
|
|
|
|
# Emit the info table
|
|
emit_block {
|
|
for my $item ($tag->findnodes('child::enum-item')) {
|
|
my $tag = $item->nodeName;
|
|
|
|
# Assemble item-specific attr values
|
|
my @evals = @avals;
|
|
my $name = $item->getAttribute('name');
|
|
$evals[0] = "\"$name\"" if $name;
|
|
|
|
for my $attr ($item->findnodes('child::item-attr')) {
|
|
my $name = $attr->getAttribute('name') or die "Unnamed item-attr.\n";
|
|
my $value = $attr->getAttribute('value') or die "No-value item-attr.\n";
|
|
my $idx = $aidx{$name} or die "Unknown item-attr: $name\n";
|
|
|
|
if ($atnames[$idx]) {
|
|
$evals[$idx] = $aprefix[$idx].$value;
|
|
} else {
|
|
$evals[$idx] = "\"$value\"";
|
|
}
|
|
}
|
|
|
|
emit "{ ",join(', ',@evals)," },";
|
|
}
|
|
|
|
emit "{ ",join(', ',@avals)," }";
|
|
} "static const _info_entry _info[] = ", ";";
|
|
|
|
for (my $i = 0; $i < @anames; $i++) {
|
|
emit_block {
|
|
emit "return is_valid(value) ? _info[value - $base].$anames[$i] : $avals[$i];";
|
|
} "$atypes[$i] get_$anames[$i]($name value) ";
|
|
}
|
|
} "namespace $name ";
|
|
} "namespace enums ";
|
|
} 'enums';
|
|
}
|
|
|
|
sub render_enum_type {
|
|
my ($tag) = @_;
|
|
|
|
emit_block {
|
|
emit_block {
|
|
my $base = render_enum_core($typename,$tag);
|
|
|
|
if (defined $base) {
|
|
render_enum_tables($typename,$tag,$base);
|
|
} else {
|
|
print STDERR "Warning: complex enum: $typename\n";
|
|
}
|
|
} "namespace $typename ";
|
|
} "namespace enums ";
|
|
|
|
emit "using enums::",$typename,"::",$typename,";";
|
|
}
|
|
|
|
1;
|