in meta/parse.pl [545:800]
sub ProcessEnumSection
{
my $section = shift;
for my $memberdef (@{ $section->{memberdef} })
{
next if not $memberdef->{kind} eq "enum";
my $enumtypename = $memberdef->{name}[0];
$enumtypename =~ s/^_//;
if (not $enumtypename =~ /^(sai_\w+_)t$/)
{
LogWarning "enum $enumtypename is not prefixed sai_";
next;
}
my $enumprefix = uc $1;
if ($enumtypename =~ /_extensions_t$/)
{
LogDebug "removing extension prefix from $enumtypename";
# remove extensions suffix on all extensions since they will be merged together
$enumprefix =~ s/EXTENSIONS_$//;
$EXTENSIONS_ENUMS{$enumtypename} = "${enumprefix}_t";
}
if (defined $SAI_ENUMS{$enumtypename})
{
LogError "duplicated enum $enumtypename";
next;
}
my $ed = ExtractDescription($enumtypename, $enumtypename, $memberdef->{detaileddescription}[0]);
if ($ed =~ /\@\@flags/s and not $ed =~ /\@\@flags\s+(\w+)/s)
{
LogWarning "expected flags type $ENUM_FLAGS_TYPES not specified on $enumtypename";
}
$SAI_ENUMS{$enumtypename}{flagsenum} = ($ed =~ /\@\@flags/s) ? "true" : "false";
$SAI_ENUMS{$enumtypename}{flagstype} = ($ed =~ /\@\@flags\s+(\w+)/s) ? $1 : "none";
my @arr = ();
my @initializers = ();
$SAI_ENUMS{$enumtypename}{values} = \@arr;
for my $ev (@{ $memberdef->{enumvalue} })
{
my $enumvaluename = $ev->{name}[0];
my $eitemd = ExtractDescription($enumtypename, $enumvaluename, $ev->{detaileddescription}[0]);
my $initializer = $ev->{initializer}[0];
$initializer = "" if not defined $initializer;
if ($eitemd =~ /\@ignore/)
{
LogInfo "Ignoring $enumvaluename";
if ($initializer =~ /^= (SAI_\w+)$/)
{
LogError "initializer $1 not defined in $enumtypename before $enumvaluename" if not grep (/^$1$/, @arr);
}
else
{
LogWarning "Enum $enumvaluename is ignored, but initializer is '$initializer' not in form '= SAI_\\w+'";
}
# process ignore attributes
if (not defined $SAI_ENUMS{$enumtypename}{ignoreval})
{
my @ignoreval = ();
$SAI_ENUMS{$enumtypename}{ignoreval} = \@ignoreval;
}
my $ref = $SAI_ENUMS{$enumtypename}{ignoreval};
push @$ref, $enumvaluename;
next;
}
LogDebug "$enumtypename $enumvaluename";
push@arr,$enumvaluename;
push@initializers,$initializer;
LogWarning "Value $enumvaluename of $enumtypename is not prefixed as $enumprefix" if not $enumvaluename =~ /^$enumprefix/;
if (not $enumvaluename =~ /^[A-Z0-9_]+$/)
{
LogError "enum $enumvaluename uses characters outside [A-Z0-9_]+";
}
}
ProcessEnumInitializers(\@arr,\@initializers, $enumtypename, \%SAI_DEFINES);
# TODO stable sort values based on calculated values from initializer (https://perldoc.perl.org/sort)
# TODO add param to disable this
# remove unnecessary attributes
my @values = @{ $SAI_ENUMS{$enumtypename}{values} };
push @ALL_ENUMS, @values;
my @ranges = grep(/^SAI_\w+(RANGE_BASE)$/, @values);
$SAI_ENUMS{$enumtypename}{ranges} = \@ranges;
my @custom = grep(/^SAI_\w+_CUSTOM_RANGE_(START|END)$/, @values);
$SAI_ENUMS_CUSTOM_RANGES{$enumtypename}{customranges} = \@custom;
@values = grep(!/^SAI_\w+_(START|END)$/, @values);
@values = grep(!/^SAI_\w+(RANGE_BASE)$/, @values);
if ($enumtypename =~ /^(sai_\w+)_t$/)
{
my $valuescount = @values;
# allow empty enum on extensions
if ($valuescount == 0 and not $enumtypename =~ /_extensions_t$/)
{
LogError "enum $enumtypename is empty, after removing suffixed entries _START/_END/_RANGE_BASE";
LogError " those suffixes are reserved for range markers and are removed by metadata parser, don't use them";
LogError " as actual part of valid enum name, take a look at sai_udf_group_type_t for valid usage";
next;
}
if ($valuescount > 0)
{
my $last = $values[$#values];
if ($last eq "${enumprefix}MAX")
{
$last = pop @values;
LogInfo "Removing last element $last";
}
}
}
else
{
LogError "NON sai Enum $enumtypename";
}
$SAI_ENUMS{$enumtypename}{values} = \@values;
if (not $enumtypename =~ /^(sai_(\w+)_attr_(extensions_)?)t$/)
{
for my $ev (@{ $memberdef->{enumvalue} })
{
my $enumvaluename = $ev->{name}[0];
my $eitemd = ExtractDescription($enumtypename, $enumvaluename, $ev->{detaileddescription}[0]);
ProcessEnumItemDescription($enumtypename, $enumvaluename, $eitemd);
}
next;
}
# ENUM ATTRIBUTES PROCESSED BELOW
# TODO put to SAI_ATTR_ENUMS
my $prefix = uc$1;
# remove unnecessary attributes
@values = @{ $SAI_ENUMS{$enumtypename}{values} };
@values = grep(!/^${prefix}(CUSTOM_RANGE_|FIELD_|ACTION_)?(START|END)$/, @values);
$SAI_ENUMS{$enumtypename}{values} = \@values;
# this is attribute
for my $ev (@{ $memberdef->{enumvalue} })
{
my $enumvaluename = $ev->{name}[0];
my $desc = ExtractDescription($enumtypename, $enumvaluename, $ev->{detaileddescription}[0]);
my $brief = ExtractDescription($enumtypename, $enumvaluename, $ev->{briefdescription}[0]);
ProcessDescription($enumtypename, $enumvaluename, $desc, $brief);
# remove ignored attributes from enums from list
# since enum must match attribute list size
if (defined $METADATA{$enumtypename}{$enumvaluename}{ignore})
{
@values = grep(!/^$enumvaluename$/, @values);
$SAI_ENUMS{$enumtypename}{values} = \@values;
next;
}
if ($enumvaluename =~ /^(SAI_\w+_)MIN$/)
{
my $prefix = $1;
my $range = $METADATA{$enumtypename}{$enumvaluename}{range};
if (not defined $range)
{
# XXX we can relax this and generate range only if range tag is defined
LogWarning "attribute $enumvaluename must have \@range tag";
next;
}
my $rangeLimit = 10;
if ($range > $rangeLimit)
{
# let's not generate too many attributes that will not be used
LogInfo "Limiting range from $range to $rangeLimit";
$range = $rangeLimit;
}
# we assume zero is reserved for *_MIN and last value for *_MAX
my @rangeElements = ();
for (my $idx = 1; $idx < $range; ++$idx)
{
my $attrid = "${prefix}$idx";
push@rangeElements, $attrid;
my $attr = ShallowCopyAttrEnum($METADATA{$enumtypename}{$enumvaluename});
$attr->{attrid} = $attrid;
$METADATA{$enumtypename}{$attrid} = $attr;
$EXTRA_RANGE_DEFINES{$attrid} = "($enumvaluename + $idx)";
}
# update enum values (this could be done in previous step
my @values = @{ $SAI_ENUMS{$enumtypename}{values} };
my ($index) = grep { $values[$_] =~ /^$enumvaluename$/ } 0..$#values;
splice @values, $index+1,0, @rangeElements;
$SAI_ENUMS{$enumtypename}{values} = \@values;
}
}
}
}