### ----------------------------------------------------
### -- Hash::Sorted
### -- Licenses: Artistic-2.0
### -- Authors: Elizabeth Mattijsen
### -- File: makeGENERIC.raku
### ----------------------------------------------------
#!/usr/bin/env raku

# This script reads the lib/Hash/Sorted.rakumod file, and
# generates the necessary code for the identical parts of
# the roled being offered (to allow for the best possible
# performance), and writes them back to the file.

# always use highest version of Raku
use v6.*;

my $generator = $*PROGRAM-NAME;
my $generated = DateTime.now.gist.subst(/\.\d+/,'');
my $start     = '#- start of generated part ';
my $end       = '#- end of generated part ';

# slurp the whole file and set up writing to it
my $filename = "lib/Hash/Sorted.rakumod";
my @lines = $filename.IO.lines;
$*OUT = $filename.IO.open(:w);

# for all the lines in the source that don't need special handling
while @lines {
    my $line := @lines.shift;

    # nothing to do yet
    unless $line.starts-with($start) {
        say $line;
        next;
    }

    # found header
    say $start ~ "-----------------------------------------------------";
    say "#- Generated on $generated by $generator";
    say "#- PLEASE DON'T CHANGE ANYTHING BELOW THIS LINE";

    # skip the old version of the code
    while @lines {
        last if @lines.shift.starts-with($end);
    }

    # spurt the code
    say Q:to/SOURCE/.chomp;

    has @.keys;
    has @.values;

    method new() {
        my $self := nqp::create(self);
        nqp::bindattr($self,self,'@!keys',typed-array(KeyT).new);
        nqp::bindattr($self,self,'@!values',typed-array(ValueT).new);
        $self
    }

    method keys(::?ROLE:D:) { @!keys }

#---- Methods needed for consistency -------------------------------------------
    method gist(::?ROLE:D:) {
        '{' ~ self.pairs.map( *.gist).join(", ") ~ '}'
    }

    method Str(::?ROLE:D:) {
        self.pairs.join(" ")
    }

    method perl(::?ROLE:D:) is DEPRECATED("raku") {
        self.raku
    }
    method raku(::?ROLE:D:) {
        self.perlseen(self.^name, {
          ~ self.^name
          ~ '.new('
          ~ self.pairs.map({nqp::decont($_).perl}).join(',')
          ~ ')'
        })
    }

#---- Optional methods for performance -----------------------------------------
    method elems(::?ROLE:D:)  { @!keys.elems }
    method end(::?ROLE:D:)    { @!keys.end }
    method values(::?ROLE:D:) { @!values }

    method pairs(::?ROLE:D:) {
        (^@!keys).map: { Pair.new(@!keys.AT-POS($_), @!values.AT-POS($_)) }
    }
    method antipairs(::?ROLE:D:) {
        (^@!keys).map: { Pair.new(@!values.AT-POS($_), @!keys.AT-POS($_)) }
    }
    method kv(::?ROLE:D:) { Seq.new(KV.new(@!keys, @!values)) }

SOURCE

    # we're done for this role
    say "#- PLEASE DON'T CHANGE ANYTHING ABOVE THIS LINE";
    say $end ~ "-------------------------------------------------------";
}

# close the file properly
$*OUT.close;

# vim: expandtab shiftwidth=4


