Search code examples
regexrakuproto

perl6 Need help to understand more about proto regex/token/rule


The following code is taken from the Perl 6 documentation, and I am trying to learn more about it before more experimentation:

proto token command {*}
      token command:sym<create>   { <sym> }
      token command:sym<retrieve> { <sym> }
      token command:sym<update>   { <sym> }
      token command:sym<delete>   { <sym> }
  1. Is the * in the first line a whatever-star? Can it be something else, such as

    proto token command { /give me an apple/ }
    
  2. Can "sym" be something else, such as

    command:eat<apple> { <eat> } ?
    

Solution

  • {*} tells the runtime to call the correct candidate.
    Rather than force you to write {{*}} for the common case of just call the correct one, the compiler allows you to shorten it to just {*}

    That is the case for all proto routines like sub, method, regex, token, and rule.

    In the case of the regex proto routines, only a bare {*} is allowed.
    The main reason is probably because no-one has really come up with a good way to make it work sensibly in the regex sub-language.

    So here is an example of a proto sub that does some things that are common to all of the candidates.

    #! /usr/bin/env perl6
    use v6.c;
    for @*ARGS { $_ = '--stdin' when '-' }
    
    # find out the number of bytes
    proto sub MAIN (|) {
      try {
        # {*} calls the correct multi
        # then we get the number of elems from its result
        # and try to say it
        say {*}.elems #            <-------------
      }
      # if {*} returns a Failure note the error message to $*ERR
      or note $!.message;
    }
    
    #| the number of bytes on the clipboard
    multi sub MAIN () {
      xclip
    }
    
    #| the number of bytes in a file
    multi sub MAIN ( Str $filename ){
      $filename.IO.slurp(:!chomp,:bin)
    }
    
    #| the number of bytes from stdin
    multi sub MAIN ( Bool :stdin($)! ){
      $*IN.slurp-rest(:bin)
    }
    
    sub xclip () {
      run( «xclip -o», :out )
      .out.slurp-rest( :bin, :close );
    }