sub ProcessEnumInitializers()

in meta/utils.pm [430:608]


sub ProcessEnumInitializers
{
    #
    # This function attempts to figure out enum integers values during paring
    # time in similar way as C compiler would do. Because SAI community agreed
    # that enum grouping is more beneficial then ordering enums, then enum
    # values could be not sorted any more. But if we figure out integers
    # values, we could perform stable sort at this parser level, and generate
    # enums metadata where enum values are sorted.
    #

    my ($arr_ref, $ini_ref, $enumTypeName, $SAI_DEFINES_REF) = @_;

    return if $enumTypeName =~ /_extensions_t$/; # ignore initializers on extensions

    if (scalar(@$arr_ref) != scalar(@$ini_ref))
    {
        LogError "attr array not matching initializers array on $enumTypeName";
        return;
    }

    #return if grep (/<</, @$ini_ref); # skip shifted flags enum

    my $previousEnumValue = -1;

    my $idx = 0;

    # using reference here, will cause update $ini inside initializer table
    # reference and that's what we want

    for my $ini (@$ini_ref)
    {
        if ($ini eq "")
        {
            $previousEnumValue += 1;

            $ini = sprintf("0x%08x", $previousEnumValue);
        }
        elsif ($ini =~ /^= (0x[0-9a-f]{8})$/)
        {
            $previousEnumValue = hex($1);

            $ini = sprintf("0x%08x", $previousEnumValue);
        }
        elsif ($ini =~ /^=\s+(\d+)$/)
        {
            $previousEnumValue = hex($1);

            $ini = sprintf("0x%08x", $previousEnumValue);
        }
        elsif ($ini =~ /= (SAI_\w+)$/)
        {
            for my $i (0..$idx)
            {
                if ($$arr_ref[$i] eq $1)
                {
                    $ini = @$ini_ref[$i];

                    $previousEnumValue = hex($ini);
                    last;
                }
            }

            LogError "initializer $ini not found on $enumTypeName before $$arr_ref[$idx]" if not $ini =~ /^0x/;
        }
        elsif ($ini =~ /^= (SAI_\w+) \+ (SAI_\w+)$/) # special case SAI_ACL_USER_DEFINED_FIELD_ATTR_ID_RANGE
        {
            # this case is in form: = (sai enum value) + (sai define)

            my $first = $1;

            my $val = $SAI_DEFINES_REF->{$2};

            if (not defined $val)
            {
                LogError "Value $2 not defined using #define directive";
            }
            elsif (not $val =~ /^0x[0-9a-f]+$/i)
            {
                LogError "$val not in hex format 0xYY";
            }
            else
            {
                for my $i (0..$idx)
                {
                    if ($$arr_ref[$i] eq $first)
                    {
                        $ini = sprintf("0x%08x", hex(@$ini_ref[$i]) + hex($val));

                        $previousEnumValue = hex($ini);
                        last;
                    }
                }

                LogError "initializer $ini not found on $enumTypeName before $$arr_ref[$idx]" if not $ini =~ /^0x/;
            }
        }
        elsif ($ini =~/^= (SAI_\w+) \+ (\d+)$/)
        {
            my $first = $1;
            my $val = $2;

            for my $i (0..$idx)
            {
                if ($$arr_ref[$i] eq $first)
                {
                    $ini = sprintf("0x%08x", hex(@$ini_ref[$i]) + $val);

                    $previousEnumValue = hex($ini);
                    last;
                }
            }

            LogError "initializer $ini not found on $enumTypeName before $$arr_ref[$idx]" if not $ini =~ /^0x/;
        }
        elsif ($ini =~/^= (SAI_\w+) \+ (0x[0-9a-f]{1,8})$/)
        {
            my $first = $1;
            my $val = $2;

            for my $i (0..$idx)
            {
                if ($$arr_ref[$i] eq $first)
                {
                    $ini = sprintf("0x%08x", hex(@$ini_ref[$i]) + hex($val));

                    $previousEnumValue = hex($ini);
                    last;
                }
            }

            LogError "initializer $ini not found on $enumTypeName before $$arr_ref[$idx]" if not $ini =~ /^0x/;
        }
        elsif ($ini =~ /^= \(?(\d+) << (\d+)\)?$/)
        {
            $previousEnumValue = $1 << $2;

            $ini = sprintf("0x%08x", $previousEnumValue);
        }
        else
        {
            LogError "not supported initializer '$ini' on $$arr_ref[$idx], FIXME";
        }

        $idx++;
    }

    # in final form all initializers must be hex numbers 8 digits long, since
    # they will be used in stable sort

    if (scalar(grep (/^0x[0-9a-f]{8}$/, @$ini_ref)) != scalar(@$ini_ref))
    {
        LogError "wrong initializers on $enumTypeName: @$ini_ref";
        return;
    }

    my $before = "@$arr_ref";

    my @joined = ();

    for my $idx (0..$#$arr_ref)
    {
        push @joined, "$$ini_ref[$idx]$$arr_ref[$idx]"; # format is: 0x00000000SAI_
    }

    my @sorted = sort { substr($a, 0, 10) cmp substr($b, 0, 10) } @joined;

    s/^0x[0-9a-f]{8}SAI/SAI/i for @sorted;

    my $after = "@sorted";

    return if $after eq $before;

    LogDebug "Need sort initalizers for $enumTypeName";

    @$arr_ref = ();

    push @$arr_ref, @sorted;
}