Peta::Shell::Session#

evaluate Perl line by line and keep the state

SYNOPSIS#

use Peta::Shell::Session;

my $session = Peta::Shell::Session->new;

my $r = $session->eval('my @list = (1, 2, 3); scalar @list');
print "$r->{status}: @{ $r->{values} }\n";      # ok: 3

$r = $session->eval('push @list, 4; "@list"');  # @list is still there
print "@{ $r->{values} }\n";                    # 1 2 3 4

$r = $session->eval('for my $i (@list) {');
print $r->{status}, "\n";                       # incomplete

DESCRIPTION#

A session evaluates pieces of Perl one after another as if they were consecutive lines of one program. What a line leaves behind is there for every later line:

  • its my, state and our variables, when declared at the line’s top level;

  • its pragmas: use strict, use warnings, use feature, use v5.36 and any other lexical pragma;

  • the current package;

  • subs, packages and loaded modules, as in any program.

A variable declared inside a block of the line (for my $i (...), if (...) { my $t }) belongs to that block and is gone with it, as in a program.

Each line is compiled once and run at once. A line that does not compile changes nothing. A line that dies keeps what it had declared and assigned before it died.

How a my variable survives#

The variable itself is kept, not a copy: after the line that declares it, later lines reach it under its name as a package variable of a hidden package, bound with our when the line is compiled. So a closure and a named sub see every later assignment, \$x is the same reference in every line, and a second my $x in a later line makes a new variable while subs compiled before keep the old one.

Two things follow from “package variable”. local $x works on it in a later line, which a true lexical refuses. And the name is resolved when a line is compiled, so text compiled later at run time (a string eval) sees the variable, but a symbolic reference by its plain name does not.

METHODS#

new#

my $session = Peta::Shell::Session->new(%options);

Options:

  • name

    The name lines are reported under. Line 12 of a session named ipps is the file (ipps:12) in messages. Default ipps.

  • package

    The package the first line is compiled in. Default main.

  • preamble

    Perl evaluated before the first line; it sets the pragmas the session starts with and is not counted as a line. Default use strict qw(refs   subs); use warnings;. Pass an empty string for none.

Dies if the preamble does not compile or dies.

eval#

my $result = $session->eval($text);

Passes $text through the preprocessors, compiles it and runs it in list context. $text may hold several lines. Returns a hash reference:

  • status

    ok, error, incomplete or empty.

    incomplete means the text ends inside a construct: an open bracket, a string or here-document without its end, an expression that expects more. Nothing was run. The caller reads more input and calls eval again with the whole text.

    empty means there was nothing but blank space, before or after the preprocessors.

  • values

    Array reference: what the last statement returned, in list context. Empty unless the status is ok.

  • error

    For error: the exception, as it was thrown (a string or an object).

  • phase

    For error: preprocess, compile or run.

  • warnings

    Array reference of the warnings the line raised, compiling or running, unless a line has installed its own $SIG{__WARN__}, which then gets them.

  • line

    The line number this text got. Only ok and error texts are numbered.

  • text

    The text after the preprocessors.

  • wall, cpu

    Seconds of wall-clock and of processor time, compiling and running.

variables#

my @names = $session->variables;

The names of the session’s variables with their sigils, sorted.

variable#

my $ref = $session->variable('@list');

A reference to the variable itself, or undef when the session has none of that name.

bind#

$session->bind('$ans', \$value);

Makes the referenced variable the session’s variable of that name, as if a line had declared it. The name is a sigil ($, @ or %) and an identifier; the reference must be of the matching kind.

package#

The package the next line is compiled in.

line#

The number of the last numbered line; 0 before the first.

name#

The session’s name.

add_preprocessor#

$session->add_preprocessor(sub { my ($text, $session) = @_; ...; $text });

Appends a preprocessor. Before a text is compiled it passes through the preprocessors in the order they were added; each gets the text and the session and returns the text to go on with. Returning an empty string ends the line there (status empty). An exception makes the line an error of phase preprocess.

This is where macros, aliases and commands of the shell live: they turn what was typed into Perl.

remove_preprocessor#

$session->remove_preprocessor($code);

Removes that preprocessor. Returns true if it was there.

preprocessors#

The list of preprocessors, in order.

LIMITS#

  • Text that turns out to be incomplete has still been compiled as far as it went, so a use or BEGIN block in it has already run and runs again when the completed text is compiled.

  • local at a line’s top level lasts to the end of that line.

  • The match variables ($1, $&) are scoped to the line.

  • A lexical sub (my sub name) is not kept.