#!/usr/bin/env raku # This script reads the native_array.rakumod file, and generates the # intarray, numarray and strarray postcircumfix candidates and # writes it 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 postcircumfix candidates of '; my $idpos = $start.chars; my $idchars = 3; my $end = '#- end of postcircumfix candidates of '; my %type_mapper = ( int => ( :nullval("0"), :postfix, :postfix_push, :postfix_cmp, :type, :Type, :value, :Value, ).Map, num => ( :nullval("0e0"), :postfix, :postfix_push, :postfix_cmp, :type, :Type, :value, :Value, ).Map, str => ( :nullval('""'), :postfix, :postfix_push, :postfix_cmp, :type, :Type, :value, :Value, ).Map, uint => ( :nullval("0"), :postfix, :postfix_push, :postfix_cmp, :type, :Type, :value, :Value, ).Map, ); # slurp the whole file and set up writing to it my $filename = "src/core.c/native_array.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, check validity and set up mapper my $type = $line.substr($idpos,$idchars); $type = "uint" if $type eq "uin"; die "Don't know how to handle $type" unless my %mapper := %type_mapper{$type}; 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 while @lines { last if @lines.shift.starts-with($end); } # spurt the candidates say Q:to/SOURCE/.subst(/ '#' (\w+) '#' /, -> $/ { %mapper{$0} }, :g).chomp; multi sub postcircumfix:<[ ]>( array::#type#array:D \SELF, uint $pos ) is raw { nqp::atposref_#postfix#(nqp::decont(SELF),$pos) } multi sub postcircumfix:<[ ]>( array::#type#array:D \SELF, Int:D $pos ) is raw { nqp::islt_i($pos,0) ?? X::OutOfRange.new(:what, :got($pos), :range<0..^Inf>).throw !! nqp::atposref_#postfix#(nqp::decont(SELF),$pos) } multi sub postcircumfix:<[ ]>( array::#type#array:D \SELF, uint $pos, #Type#:D \assignee ) is raw { nqp::bindpos_#postfix#(nqp::decont(SELF),$pos,assignee) } multi sub postcircumfix:<[ ]>( array::#type#array:D \SELF, Int:D $pos, #Type#:D \assignee ) is raw { nqp::islt_i($pos,0) ?? X::OutOfRange.new(:what, :got($pos), :range<0..^Inf>).throw !! nqp::bindpos_#postfix#(nqp::decont(SELF),$pos,assignee); } multi sub postcircumfix:<[ ]>( array::#type#array:D, Int:D, :$BIND! ) { X::Bind.new(target => 'a native #type# array').throw } multi sub postcircumfix:<[ ]>( array::#type#array:D \SELF, Int:D $pos, :$exists!, *%_ ) { my int $state = nqp::isge_i($pos,0) && nqp::islt_i($pos,nqp::elems(nqp::decont(SELF))); my $value := nqp::hllbool($exists ?? $state !! nqp::not_i($state)); $state ?? nqp::elems(my $adverbs := nqp::getattr(%_,Map,'$!storage')) ?? nqp::atkey($adverbs,'kv') ?? ($pos,$value) !! nqp::atkey($adverbs,'p') ?? Pair.new($pos,$value) !! X::Adverb.new( what => "slice", source => "a native #type# array", nogo => ('exists', |%_.keys).sort ).Failure !! $value !! $value } multi sub postcircumfix:<[ ]>( array::#type#array:D \SELF, Int:D $pos, :$delete!, *%_ ) is raw { nqp::islt_i($pos,0) ?? X::OutOfRange.new(:what, :got($pos), :range<0..^Inf>).throw !! $delete ?? X::Delete.new(target => 'a native #type# array').throw !! nqp::elems(nqp::getattr(%_,Map,'$!storage')) ?? postcircumfix:<[ ]>(SELF, $pos, |%_) !! nqp::atposref_#postfix#(nqp::decont(SELF),$pos) } multi sub postcircumfix:<[ ]>( array::#type#array:D \SELF, Int:D $pos, :$kv! ) is raw { nqp::islt_i($pos,0) ?? X::OutOfRange.new(:what, :got($pos), :range<0..^Inf>).throw !! $kv ?? nqp::list($pos,nqp::atpos_#postfix#(nqp::decont(SELF),$pos)) !! nqp::atposref_#postfix#(nqp::decont(SELF),$pos) } multi sub postcircumfix:<[ ]>( array::#type#array:D \SELF, Int:D $pos, :$p! ) is raw { nqp::islt_i($pos,0) ?? X::OutOfRange.new(:what, :got($pos), :range<0..^Inf>).throw !! $p ?? Pair.new($pos,nqp::atpos_#postfix#(nqp::decont(SELF),$pos)) !! nqp::atposref_#postfix#(nqp::decont(SELF),$pos) } multi sub postcircumfix:<[ ]>( array::#type#array:D \SELF, Int:D $pos, :$k! ) is raw { nqp::islt_i($pos,0) ?? X::OutOfRange.new(:what, :got($pos), :range<0..^Inf>).throw !! $k ?? $pos !! nqp::atposref_#postfix#(nqp::decont(SELF),$pos) } multi sub postcircumfix:<[ ]>( array::#type#array:D \SELF, Int:D $pos, :$v! ) is raw { nqp::islt_i($pos,0) ?? X::OutOfRange.new(:what, :got($pos), :range<0..^Inf>).throw !! $v ?? nqp::isge_i($pos,0) && nqp::islt_i($pos,nqp::elems(nqp::decont(SELF))) ?? nqp::list(nqp::atpos_#postfix#(nqp::decont(SELF),$pos)) !! () !! nqp::atpos_#postfix#(nqp::decont(SELF),$pos) } multi sub postcircumfix:<[ ]>( array::#type#array:D \SELF, Callable:D $pos ) is raw { nqp::istype((my $got := $pos.POSITIONS(SELF)),Int) ?? nqp::islt_i($got,0) ?? X::OutOfRange.new(:what, :$got, :range<0..^Inf>).throw !! nqp::atposref_#postfix#(nqp::decont(SELF),$got) !! postcircumfix:<[ ]>(SELF, $got) } multi sub postcircumfix:<[ ]>( array::#type#array:D \SELF, Iterable:D $pos is rw ) is raw { nqp::islt_i((my int $got = $pos.Int),0) ?? X::OutOfRange.new(:what, :$got, :range<0..^Inf>).throw !! nqp::atposref_#postfix#(nqp::decont(SELF),$got) } multi sub postcircumfix:<[ ]>( array::#type#array:D \SELF, Iterable:D $pos ) is raw { my $self := nqp::decont(SELF); my $indices := $pos.iterator; my #type# @result; nqp::until( nqp::eqaddr((my $pulled := $indices.pull-one),IterationEnd), nqp::if( nqp::istype( (my $got = nqp::if( nqp::istype($pulled,Callable), $pulled.POSITIONS($self), $pulled )), Int ) && nqp::isge_i($got,0), nqp::push_#postfix_push#(@result,nqp::atpos_#postfix#($self,$got)), nqp::if( nqp::istype($got,Int), X::OutOfRange.new(:what, :$got, :range<0..^Inf>).throw, (die "Cannot handle {$got.raku} as an index in an Iterable when slicing a native #type# array".naive-word-wrapper) ) ) ); @result } multi sub postcircumfix:<[ ]>( array::#type#array:D \SELF, Iterable:D $pos, array::#type#array:D $values ) is raw { my $self := nqp::decont(SELF); my $indices := $pos.iterator; my int $i = -1; my #type# @result; nqp::until( nqp::eqaddr((my $pulled := $indices.pull-one),IterationEnd), nqp::if( nqp::istype( (my $got = nqp::if( nqp::istype($pulled,Callable), $pulled.POSITIONS($self), $pulled )), Int ) && nqp::isge_i($got,0), nqp::push_#postfix_push#( @result, nqp::bindpos_#postfix#($self,$got,nqp::atpos_#postfix#($values,++$i)) ), nqp::if( nqp::istype($got,Int), X::OutOfRange.new(:what, :$got, :range<0..^Inf>).throw, (die "Cannot handle {$got.raku} as an index in an Iterable when assigning to a native #type# array slice".naive-word-wrapper) ) ) ); @result } multi sub postcircumfix:<[ ]>( array::#type#array:D \SELF, Iterable:D $pos, \values ) is raw { my $self := nqp::decont(SELF); my $indices := $pos.iterator; my $values := Rakudo::Iterator.TailWith(values.iterator,#nullval#); my #type# @result; nqp::until( nqp::eqaddr((my $pulled := $indices.pull-one),IterationEnd), nqp::if( nqp::istype( (my $got = nqp::if( nqp::istype($pulled,Callable), $pulled.POSITIONS($self), $pulled )), Int ) && nqp::isge_i($got,0), nqp::push_#postfix_push#( @result, nqp::bindpos_#postfix#( $self, $got, $values.pull-one.#Type# ) ), nqp::if( nqp::istype($got,Int), X::OutOfRange.new(:what, :$got, :range<0..^Inf>).throw, (die "Cannot handle {$got.raku} as an index in an Iterable when assigning to a native #type# array slice".naive-word-wrapper) ) ) ); @result } multi sub postcircumfix:<[ ]>( array::#type#array:D \SELF, Whatever ) { nqp::decont(SELF) } multi sub infix:(array::#type#array:D \a, array::#type#array:D \b) { my int $elems-a = nqp::elems(a); my int $elems-b = nqp::elems(b); my int $elems = nqp::islt_i($elems-a,$elems-b) ?? $elems-a !! $elems-b; my int $i = -1; nqp::until( nqp::isge_i(++$i,$elems) || (my $res = nqp::cmp_#postfix_cmp#(nqp::atpos_#postfix#(a,$i),nqp::atpos_#postfix#(b,$i))), nqp::null ); ORDER($res || nqp::cmp_i($elems-a,$elems-b)) } SOURCE # we're done for this role say "#- PLEASE DON'T CHANGE ANYTHING ABOVE THIS LINE"; say $end ~ $type ~ "array ---------------------------------"; } # close the file properly $*OUT.close; # vim: expandtab sw=4