=begin pod

=head1 NAME

CodeUnit - provide a unit for execution of code

=head1 SYNOPSIS

=begin code :lang<raku>
use CodeUnit;

my $cu = CodeUnit.new;
$cu.eval('my $a = 42');
$cu.eval('say $a');  # 42

$cu.eval('say $b');
with $cu.exception {
    note .message.chomp;  # Variable '$b' is not declared...
    $cu.exception = Nil;
}
=end code

=head1 DESCRIPTION

The C<CodeUnit> distribution provides an interface to a compiler
context that allows code to be evaluated by given strings, while
maintaining context between states.

As such it provides one of the underlying functionalities of a REPL
(Read Evaluate Print Loop), but could be used by itself for a
multitude of uses.

=head1 METHODS

=head2 new

=begin code :lang<raku>
my $cu1 = CodeUnit.new;

# use current context
my $context = context;  # must be separate call
my $cu2 = CodeUnit.new(:$context);

# don't show warnings
my $cu3 = CodeUnit.new(:keep-warnings);
$cu3.eval(q/my $x; $x + 1/);                   # no output
.note for $cu3.warnings.map(*.Str.lines.head); # show without backtrace

# start with grammar including any mixins
my $cu4 = CodeUnit.new(:lang(BEGIN $*LANG));
=end code

The C<new> method instantiates a C<CodeUnit> object.  It takes the
following named arguments:

=head3 :context

Optional. The C<:context> named argument can be specified with a value
returned by the C<context> subroutine.  If not specified, will
assume a fresh context without any outer / caller lexicals visible.

Used value available with the C<.context> method.

=head3 :keep-warnings

Optional.  If specified with a true value, will cause any warnings to
be stored in the C<CodeUnit> object rather than being shown on STDERR.
The warnings (as C<CX::Warn> objects including their full stack-traces)
are accessible with the C<warnings> method (which will also reset any
warnings collected so far).

=head3 :lang

Optional.  Specified which C<grammar> / action class to be used.  Defaults
to the standard Raku C<grammar> and action class.  If specified, this is
usually C<BEGIN $*LANG>;

=head3 :compiler

Optional.  The C<:compiler> named argument can be specified to indicate
the low level compiler object that sould be used.  Can be specified as
a string, in which case it will be used as an argument to the
C<nqp::getcomp> function to obtain the low level compiler object.
Defaults to C<"Raku">.

Used value available with the C<.compiler> method.

=head3 :multi-line-ok

Optional, Boolean. Indicate whether it is ok to interprete multiple
lines of input as a single statement to evaluate.  Defaults to
C<True> unless the C<RAKUDO_DISABLE_MULTILINE> environment variable
has been specified with a true value.

Used value available with the C<.multi-line-ok> method, and can be
used as a left-value to change.

=head3 :grammar

Optional.  Specifies the C<grammar> to be used initially.  Defaults
to the standard Raku grammar, or to what has been specified with C<:lang>.

Value available with the C<.grammar> method.

=head3 :actions

Optional.  Specifies the action class to be used.  Defaults to the
standard Raku actions, or to what the C<.actions> method returns on what
is specified with C<:lang>.

=head2 eval

=begin code :lang<raku>
$cu.eval('my $a = 42');
$cu.eval('say $a');  # 42
=end code

The C<eval> method evaluates the given string with Raku code within
the context of the code unit, and returns the result of the evaluation.

=head2 reset

=begin code :lang<raku>
$cu.reset;
=end code

The C<reset> method resets the context of the code unit to its initial
state as (implicitely) specified with C<.new>.

=head2 compiler-version

=begin code :lang<raku>
say $cu.compiler-version;
# Welcome to Rakudo™ v2025.01.
# Implementing the Raku® Programming Language v6.d.
# Built on MoarVM version 2025.01.
=end code

The C<compiler-version> method returns the compiler version information,
which is typically shown when starting a REPL.

=head2 context-completions

=begin code :lang<raku>
.say for $cu.context-completions;
=end code

The C<context-completions> method returns an unsorted list of context
completion candidates found in the context of the code unit, which are
typically used to provide completions in a REPL (hence the name).

=head2 state

The C<state> method returns one of the C<Status> enums to indicate
the result of the last call to C<.eval>.  It can also be used as a
left-value to set the state (usually to C<OK>).

=head2 exception

=begin code :lang<raku>
with $cu.exception {
    note .message.chomp;  # Variable '$b' is not declared...
    $cu.exception = Nil;
}
=end code

The C<exception> method returns the C<Exception> object if anything
went wrong in the C<.eval> call.  Note that this can also be the
case even if the state is C<OK>.  Can also be used as a left-value
to (re)set.

=head2 warnings

=begin code :lang<raku>
my $cu = CodeUnit.new(:keep-warnings);
$cu.eval(q/my $x; $x + 1/);               # no output
.note for $cu.warnings.map(*.Str.lines.head);
# Use of uninitialized value $x of type Any in numeric context
=end code

=head1 ENUMS

=head2 Status

The C<Status> enum is exported: it is used by the C<state> method to
indicate the state of the last call to C<.eval>.  It provides the
following states:
=item OK (0) - evalution ok
=item MORE-INPUT (1) - string looks like incomplete code
=item CONTROL (2) - some kind of control statement was executed

=head1 SUBROUTINES

=head2 context

=begin code :lang<raku>
my $context = context;
my $cu = CodeUnit.new(:$context);
=end code

The C<context> subroutine returns a context object that can be used to
initialize the context of a code unit with.

=head1 CAVEATS

=head2 "Invisible" variables

By default, Raku does a lot of compile-time as well as run-time
optimizations.  This may lead to lexical variables being optimized
away, and thus become "invisible" to introspection.  If that appears
to be the case, then starting Raku with C<--optimize=off> may make
these "invisble" variables visible.

=head2 Each call is a scope

Because each call introduces its own scope, certain side-effects of this
scoping behaviour may produce unexpected results and/or errors.  For
example: C<my $a = 42>, followed by C<say $a>, is really:

=begin code :lang<raku>
my $a = 42;
{
    say $a;
}
=end code

This works because the lexical variable C<$a> is visible from the scope
that has the C<say>.

Another example which you might expect to give at least a warning, but
doesn't: C<my $a = 42;> followed by C<my $a = 666>, which would normally
produce a worry: "Redeclaration of symbol '$a'", but doesn't here because
they are different scopes:

=begin code :lang<raku>
my $a = 42;
{
    my $a = 666;
}
=end code

As you can see, the second C<$a> shadows the first C<$a>, and is not a worry
as such.

Future versions of C<CodeUnit> may be able to work around this scoping
behaviour.

=head1 AUTHOR

Elizabeth Mattijsen <liz@raku.rocks>

Source can be located at: https://codeberg.org/lizmat/CodeUnit . Comments
and Pull Requests are welcome.

If you like this module, or what I'm doing more generally, committing to a
L<small sponsorship|https://github.com/sponsors/lizmat/>  would mean a great
deal to me!

=head1 COPYRIGHT AND LICENSE

Copyright 2025, 2026 Elizabeth Mattijsen

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.

=end pod

# vim: expandtab shiftwidth=4
