#!/usr/bin/env raku

# This script reads the native_array.pm6 file from STDIN, and generates the
# shaped1intarray, shaped1numarray and shaped1strarray postcircumfix
# candidates and writes it to STDOUT.

use v6;

my $generator = $*PROGRAM-NAME;
my $generated = DateTime.now.gist.subst(/\.\d+/,'');
my $start     = '#- start of postcircumfix candidates of shaped1';
my $idpos     = $start.chars;
my $idchars   = 3;
my $end       = '#- end of postcircumfix candidates of shaped1';

# for all the lines in the source that don't need special handling
for $*IN.lines -> $line {

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

    # found header
    my $type = $line.substr($idpos,$idchars);
    die "Don't know how to handle $type" unless $type eq "int" | "num" | "str";
    say $start ~ $type ~ "array ------------------------";
    say "#- Generated on $generated by $generator";
    say "#- PLEASE DON'T CHANGE ANYTHING BELOW THIS LINE";

    # skip the old version of the code
    for $*IN.lines -> $line {
        last if $line.starts-with($end);
    }

    # set up template values
    my %mapper =
      postfix => $type.substr(0,1),
      type    => $type,
      Type    => $type.tclc,
    ;

    # spurt the candidates
    say Q:to/SOURCE/.subst(/ '#' (\w+) '#' /, -> $/ { %mapper{$0} }, :g).chomp;

    multi sub postcircumfix:<[ ]>(
      array::shaped1#type#array \SELF, int \pos
    ) is raw {
        nqp::atposref_#postfix#(nqp::decont(SELF),pos)
    }
    multi sub postcircumfix:<[ ]>(
      array::shaped1#type#array \SELF, Int:D \pos
    ) is raw {
        nqp::atposref_#postfix#(nqp::decont(SELF),pos)
    }

    multi sub postcircumfix:<[ ]>(
      array::shaped1#type#array \SELF, int \pos, #Type#:D \assignee
    ) is raw {
        nqp::bindpos_#postfix#(nqp::decont(SELF),pos,assignee)
    }
    multi sub postcircumfix:<[ ]>(
      array::shaped1#type#array \SELF, Int:D \pos, #Type#:D \assignee
    ) is raw {
        nqp::bindpos_#postfix#(nqp::decont(SELF),pos,assignee)
    }

    multi sub postcircumfix:<[ ]>(
      array::shaped1#type#array \SELF, Int:D \pos, :$BIND!
    ) {
        X::Bind.new(target => 'a shaped native #type# array').throw
    }

    multi sub postcircumfix:<[ ]>(
      array::shaped1#type#array \SELF, int \pos, :$exists!
    ) {
        nqp::hllbool(
          $exists
            ?? nqp::isge_i(pos,0)
                 && nqp::islt_i(pos,nqp::elems(nqp::decont(SELF)))
            !! nqp::islt_i(pos,0)
                 || nqp::isge_i(pos,nqp::elems(nqp::decont(SELF)))
        )
    }
    multi sub postcircumfix:<[ ]>(
      array::shaped1#type#array \SELF, Int:D \pos, :$exists!
    ) {
        nqp::hllbool(
          $exists
            ?? nqp::isge_i(pos,0)
                 && nqp::islt_i(pos,nqp::elems(nqp::decont(SELF)))
            !! nqp::islt_i(pos,0)
                 || nqp::isge_i(pos,nqp::elems(nqp::decont(SELF)))
        )
    }

    multi sub postcircumfix:<[ ]>(
      array::shaped1#type#array \SELF, int \pos, :$delete!
    ) {
        $delete
          ?? X::Delete.new(target => 'a shaped native #type# array').throw
          !! nqp::atposref_#postfix#(nqp::decont(SELF),pos)
    }
    multi sub postcircumfix:<[ ]>(
      array::shaped1#type#array \SELF, Int:D \pos, :$delete!
    ) {
        $delete
          ?? X::Delete.new(target => 'a shaped native #type# array').throw
          !! nqp::atposref_#postfix#(nqp::decont(SELF),pos)
    }

    multi sub postcircumfix:<[ ]>(
      array::shaped1#type#array \SELF, Whatever
    ) {
        nqp::decont(SELF)
    }

SOURCE

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

# vim: expandtab sw=4
