sub ProcessEnumSection()

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;
            }
        }
    }
}