<commit_before>use Spit::Compile;
use Spit::OptsParser;
need Spit::Repo;

sub get-ver {
    try $*REPO.resolve(CompUnit::DependencySpecification.new(:short-name<Spit::Compile>)).distribution.meta<ver>
}

sub parse-args(@args) {
    my (@pos,%named);
    for @args {
        when s/^'--'// {
            if m/([\w|'-']+)['='(.*)]?/ {
                %named{$/[0].Str} = ( ($/[1] andthen .Str) || True);
            } else {
                die "badly formatted option";
            }
        }
        when s/^'-'// {
            when /(<[a..zA..Z]>)'='(.*)/ {
                %named{$/[0].Str} = $/[1].Str;
            }
            when /(<[a..zA..Z]>)+/ {
                %named{$_} = True for $/[0];
            }
            default {
                die "invalidly formatted option $_";
            }
        }
        default { @pos.push($_) }
    }

    @pos,%named;
}

constant $compile-options = q:to/END/;
Options:
  --debug
    Output debugging information + timings for each compilation stage.

  -d --in-docker[=<image>]
    Pipes script it into a docker container made from <image>.
    If <image> isn't specified 'debian' is used. The container is
    automatically removed. This automatically sets the 'os' option
    based on the image name (if it can) unless you specify another
    in --opts or --os.

  -s --mount-docker-socket
    Mounts /var/run/docker.sock into the container.

  -i --interactive
    Compile a script where $*interactive will be set to whether STDIN is
    a tty. Short for --opts='{ "interactive" : ": $?IN.tty" }'.

  -I --force-interactive
    Compile a script where $*ineractive will be set to True. Short for
    --opts='{ "interactive" : true }'

  --no-inline
    Turns inlining off for routine calls.

  -o --opts=<json>
    A json object where the keys are the option names and the values
    the option values. If a value starts with ':' the rest is evaluated
    as a Spit expression in the context of the option's declaration.

  --os=<os name> (default: debian)
    Shortcut for --opts='{ "os" : ": OS<debian>" }'

  --target=<stage name>
    Sets the compilation stage to finish at:  Can be any of:
      - parse:   A .gist of the match object from parsing the program.
      - stage1:  A .gist of the SAST tree after parsing.
      - stage2:  A .gist of the SAST tree after contextualisation.
      - stage3:  A .gist of the SAST tree after composition.
      - compile: The compiled shell script (default)

  --RUN
    Runs the output on this computer's /bin/sh. # Be careful :^)
END

constant $eval-usage = q:to/END/;
Usage: spit eval PROGRAM [OPTIONS]

Evaluate PROGRAM as spit code

\qq[$compile-options]

Examples:
  spit eval 'say "hello world"'
  # compile and run in docker
  spit eval -d 'say "hello world"'
  spit eval -d=centos 'say $*os.name'
  # compile for alpine
  spit eval --os=alpine 'say $*os.name'
END

constant $compile-usage = q:to/END/;
Usage: spit compile FILE [OPTIOS]

Compiles FILE as spit code

\qq[$compile-options]

Examples:
  spit compile my_program.spt
  # compile and run in docker
  spit compile -d my_program.spt
  spit compile -d=centos my_program.spt
  # compile for alpine
  spit compile --os=alpine my_program.spt
END

constant $prove-usage = q:to/END/;
Usage: spit prove PATH [OPTIONS]

Compiles and executes spit test files in docker containers under prove.
This command is just quick way of writing something like:

   for os in debian centos; do
       prove -r -e "spit -d=$os compile" spec/base/sanity.t || exit 1;
   done

   Which is similar to running:

   spit prove spec/base/sanity.t -d=debian,centos

Options:
  -d --in-docker=<image list>
      Docker images to execute the scripts under prove. Multiple image names
      must be comma separated.
  -j --jobs=<number>
      The number of jobs that prove should run.
  -s --mount-docker-socket
      Mounts /var/run/docker.sock inside the containers.

Examples:
  spit prove mytest.t
  spit prove t/
  spit prove -d=centos,alpine t/
END

constant $general-usage = q:to/END/;
Spook in the Shell Script compiler v\qq[{get-ver() || 'DEV'}]

Usage: spit [COMMAND|PATH]

If the first argument contains '/' or '.' it's assumed to be a PATH and is
run with the compile command.

Commands:
  compile  Compile a file as spit code
  eval     Compile a string as spit code
  prove    Run prove(1) with test files written in spit

run 'spit COMMAND --help' for more information about a command
END


my constant %usage = %(
    eval => $eval-usage,
    compile => $compile-usage,
    general => $general-usage,
    prove   => $prove-usage,
);

my class commands {
    method compile(Str:D $file,
                   :$debug,
                   :$target,
                   :$opts,
                   :$no-inline,
                  ) {
        if $file.IO.e {
            compile($file.IO.slurp, :$debug, :$target, :$opts, :$no-inline, name => $file).gist;
        } else {
            die "no such file ‘$file’";
        }
    }

    method eval(Str:D $src, :$debug, :$target, :$opts, :$no-inline) {
        compile($src, :$debug, :$target, :$opts, :$no-inline, name => "eval").gist;
    }

    method prove(Str:D $path, Str:D $in-docker, :$mount-docker-socket, :$jobs) {<commit_msg>use Perl 6 IO errors instead of rolling my own<commit_after>use Spit::Compile;
use Spit::OptsParser;
need Spit::Repo;

sub get-ver {
    try $*REPO.resolve(CompUnit::DependencySpecification.new(:short-name<Spit::Compile>)).distribution.meta<ver>
}

sub parse-args(@args) {
    my (@pos,%named);
    for @args {
        when s/^'--'// {
            if m/([\w|'-']+)['='(.*)]?/ {
                %named{$/[0].Str} = ( ($/[1] andthen .Str) || True);
            } else {
                die "badly formatted option";
            }
        }
        when s/^'-'// {
            when /(<[a..zA..Z]>)'='(.*)/ {
                %named{$/[0].Str} = $/[1].Str;
            }
            when /(<[a..zA..Z]>)+/ {
                %named{$_} = True for $/[0];
            }
            default {
                die "invalidly formatted option $_";
            }
        }
        default { @pos.push($_) }
    }

    @pos,%named;
}

constant $compile-options = q:to/END/;
Options:
  --debug
    Output debugging information + timings for each compilation stage.

  -d --in-docker[=<image>]
    Pipes script it into a docker container made from <image>.
    If <image> isn't specified 'debian' is used. The container is
    automatically removed. This automatically sets the 'os' option
    based on the image name (if it can) unless you specify another
    in --opts or --os.

  -s --mount-docker-socket
    Mounts /var/run/docker.sock into the container.

  -i --interactive
    Compile a script where $*interactive will be set to whether STDIN is
    a tty. Short for --opts='{ "interactive" : ": $?IN.tty" }'.

  -I --force-interactive
    Compile a script where $*ineractive will be set to True. Short for
    --opts='{ "interactive" : true }'

  --no-inline
    Turns inlining off for routine calls.

  -o --opts=<json>
    A json object where the keys are the option names and the values
    the option values. If a value starts with ':' the rest is evaluated
    as a Spit expression in the context of the option's declaration.

  --os=<os name> (default: debian)
    Shortcut for --opts='{ "os" : ": OS<debian>" }'

  --target=<stage name>
    Sets the compilation stage to finish at:  Can be any of:
      - parse:   A .gist of the match object from parsing the program.
      - stage1:  A .gist of the SAST tree after parsing.
      - stage2:  A .gist of the SAST tree after contextualisation.
      - stage3:  A .gist of the SAST tree after composition.
      - compile: The compiled shell script (default)

  --RUN
    Runs the output on this computer's /bin/sh. # Be careful :^)
END

constant $eval-usage = q:to/END/;
Usage: spit eval PROGRAM [OPTIONS]

Evaluate PROGRAM as spit code

\qq[$compile-options]

Examples:
  spit eval 'say "hello world"'
  # compile and run in docker
  spit eval -d 'say "hello world"'
  spit eval -d=centos 'say $*os.name'
  # compile for alpine
  spit eval --os=alpine 'say $*os.name'
END

constant $compile-usage = q:to/END/;
Usage: spit compile FILE [OPTIOS]

Compiles FILE as spit code

\qq[$compile-options]

Examples:
  spit compile my_program.spt
  # compile and run in docker
  spit compile -d my_program.spt
  spit compile -d=centos my_program.spt
  # compile for alpine
  spit compile --os=alpine my_program.spt
END

constant $prove-usage = q:to/END/;
Usage: spit prove PATH [OPTIONS]

Compiles and executes spit test files in docker containers under prove.
This command is just quick way of writing something like:

   for os in debian centos; do
       prove -r -e "spit -d=$os compile" spec/base/sanity.t || exit 1;
   done

   Which is similar to running:

   spit prove spec/base/sanity.t -d=debian,centos

Options:
  -d --in-docker=<image list>
      Docker images to execute the scripts under prove. Multiple image names
      must be comma separated.
  -j --jobs=<number>
      The number of jobs that prove should run.
  -s --mount-docker-socket
      Mounts /var/run/docker.sock inside the containers.

Examples:
  spit prove mytest.t
  spit prove t/
  spit prove -d=centos,alpine t/
END

constant $general-usage = q:to/END/;
Spook in the Shell Script compiler v\qq[{get-ver() || 'DEV'}]

Usage: spit [COMMAND|PATH]

If the first argument contains '/' or '.' it's assumed to be a PATH and is
run with the compile command.

Commands:
  compile  Compile a file as spit code
  eval     Compile a string as spit code
  prove    Run prove(1) with test files written in spit

run 'spit COMMAND --help' for more information about a command
END


my constant %usage = %(
    eval => $eval-usage,
    compile => $compile-usage,
    general => $general-usage,
    prove   => $prove-usage,
);

my class commands {
    method compile(Str:D $file,
                   :$debug,
                   :$target,
                   :$opts,
                   :$no-inline,
                  ) {
        compile(($file.IO.slurp orelse .throw), :$debug, :$target, :$opts, :$no-inline, name => $file).gist;
    }

    method eval(Str:D $src, :$debug, :$target, :$opts, :$no-inline) {
        compile($src, :$debug, :$target, :$opts, :$no-inline, name => "eval").gist;
    }

    method prove(Str:D $path, Str:D $in-docker, :$mount-docker-socket, :$jobs) {
{'fraction_non_alphanumeric': 0.12987512007684918, 'fraction_numerical': 0.0020172910662824206, 'mean_word_length': 2.3638126009693052, 'pattern_counts': {'":': 4, '<': 29, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2921701', 'n_tokens_mistral': 3550, 'n_tokens_neox': 3313, 'n_words': 1177}