The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!perl

use Test::More tests => 46;

use warnings FATAL => 'all';
use strict;

use Function::Parameters {
    fun => {
        default_arguments => 1,
    },

    nofun => {
        default_arguments => 0,
    },
};

fun foo0($x, $y = 1, $z = 3) { $x * 5 + $y * 2 + $z }

is foo0(10), 55;
is foo0(5, -2), 24;
is foo0(6, 10, 1), 51;

is fun ($answer = 42) { $answer }->(), 42;

fun sharingan($input, $x = [], $y = {}) {
    push @$x, $input;
    $y->{$#$x} = $input;
    $x, $y
}

{
    is_deeply [sharingan 'e'], [['e'], {0 => 'e'}];
    my $sneaky = ['ants'];
    is_deeply [sharingan $sneaky], [[['ants']], {0 => ['ants']}];
    unshift @$sneaky, 'thanks';
    is_deeply [sharingan $sneaky], [[['thanks', 'ants']], {0 => ['thanks', 'ants']}];
    @$sneaky = 'thants';
    is_deeply [sharingan $sneaky], [[['thants']], {0 => ['thants']}];
}

is eval('fun ($x, $y = $powersauce) {}'), undef;
like $@, qr/^Global symbol.*explicit package name/;

{
    my $d = 'outer';
    my $f;
    {
        my $d = 'herp';
        fun guy($d = $d, $x = $d . '2') {
            return [$d, $x];
        }

        is_deeply guy('a', 'b'), ['a', 'b'];
        is_deeply guy('c'), ['c', 'c2'];
        is_deeply guy, ['herp', 'herp2'];

        $d = 'ort';
        is_deeply guy('a', 'b'), ['a', 'b'];
        is_deeply guy('c'), ['c', 'c2'];
        is_deeply guy, ['ort', 'ort2'];

        my $g = fun ($alarum = $d) { "[$alarum]" };
        is $g->(""), "[]";
        is $g->(), "[ort]";

        $d = 'flowerpot';
        is_deeply guy('bloodstain'), ['bloodstain', 'bloodstain2'];
        is $g->(), "[flowerpot]";

        $f = $g;
    }

    is $f->(), "[flowerpot]";
    is $f->("Q"), "[Q]";
}

{
    my $c = 0;
    fun edelweiss($x = $c++) :(;$) { $x }
}

is edelweiss "AAAAA", "AAAAA";
is_deeply edelweiss [], [];
is edelweiss, 0;
is edelweiss, 1;
is_deeply edelweiss {}, {};
is edelweiss 0, 0;
is edelweiss, 2;

for my $f (fun ($wtf = return 'ohi') { "~$wtf" }) {
    is $f->(""), "~";
    is $f->("a"), "~a";
    is $f->(), "ohi";
}

is eval('fun (@x = 42) {}'), undef;
like $@, qr/default value/;

is eval('fun ($x, %y = ()) {}'), undef;
like $@, qr/default value/;

is eval('nofun ($x = 42) {}'), undef;
like $@, qr/nofun.*default argument/;


{
    my $var = "outer";

    fun scope_check(
        $var,  # inner
        $snd = "${var}2",  # initialized from $var)
        $both = "$var and $snd",
    ) {
        return $var, $snd, $both;
    }

    is_deeply [scope_check 'A'],      ['A', 'A2', 'A and A2'];
    is_deeply [scope_check 'B', 'C'], ['B', 'C', 'B and C'];
    is_deeply [scope_check 4, 5, 6],  [4, 5, 6];

    is eval('fun ($QQQ = $QQQ) {}; 1'), undef;
    like $@, qr/Global symbol.*\$QQQ.*explicit package name/;


    use Function::Parameters { method => 'method' };

    method mscope_check(
        $var,  # inner
        $snd = "${var}2",  # initialized from $var
        $both = "($self) $var and $snd",  # and $self!
    ) {
        return $self, $var, $snd, $both;
    }

    is_deeply [mscope_check '$x', 'A'],      ['$x', 'A', 'A2', '($x) A and A2'];
    is_deeply [mscope_check '$x', 'B', 'C'], ['$x', 'B', 'C', '($x) B and C'];
    is_deeply [mscope_check '$x', 4, 5, 6],  ['$x', 4, 5, 6];
}