package Sidef::Variable::GetOpt {

    use utf8;
    use 5.016;
    require Getopt::Long;

    sub new {
        my (undef, $argv, $block) = @_;

        foreach my $func ($block, (exists($block->{kids}) ? @{$block->{kids}} : ())) {

            my @types;
            my $slurpy;
            my @argv = @$argv;

            foreach my $v (@{$func->{vars}}) {
                if (exists $v->{type}) {
                    if ($v->{type} eq 'Sidef::Types::Number::Number') {
                        push @types, "$v->{name}=f";
                    }
                    elsif ($v->{type} eq 'Sidef::Types::Bool::Bool') {
                        push @types, "$v->{name}!";
                    }
                    else {
                        push @types, "$v->{name}=s";
                    }
                }
                elsif ($v->{slurpy}) {
                    $slurpy //= $v->{name};
                }
                else {
                    push @types, "$v->{name}=s";
                }
            }

            my %opt;
            do {
                local $SIG{__WARN__} = sub { };
                Getopt::Long::GetOptionsFromArray(\@argv, \%opt, @types) || next;
            };

            my @params;
            foreach my $key (keys %opt) {
                my $var   = $func->{vars}[$func->{table}{$key} // die "[ERROR] unknown command-line argument <<<$key>>>"];
                my $value = $opt{$key};

                if (exists $var->{type}) {
                    $value = $var->{type}->new($value);
                }
                else {
                    $value = Sidef::Types::String::String->new($value);
                }

                push @params, Sidef::Variable::NamedParam->new($key => $value);
            }

            if (defined($slurpy) and @argv) {
                push @params, Sidef::Variable::NamedParam->new($slurpy, map { Sidef::Types::String::String->new($_) } @argv);
            }

            return $func->call(@params);
        }

        $block->call(map { Sidef::Types::String::String->new($_) } @$argv);
    }

};

1
