CodeUnit - provide a unit for execution of code
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;
}
The 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.
my $cu1 = CodeUnit.new;
my $context = context;
my $cu2 = CodeUnit.new(:$context);
# start with grammar including any mixins
my $cu3 = CodeUnit.new(:lang(BEGIN $*LANG));
The new
method instantiates a CodeUnit
object. It takes the following named arguments:
Optional. The :context
named argument can be specified with a value returned by the context
subroutine. If not specified, will assume a fresh context without any outer / caller lexicals visible.
Used value available with the .context
method.
Optional. The :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 nqp::getcomp
function to obtain the low level compiler object. Defaults to "Raku"
.
Used value available with the .compiler
method.
Optional, Boolean. Indicate whether it is ok to interprete multiple lines of input as a single statement to evaluate. Defaults to True
unless the RAKUDO_DISABLE_MULTILINE
environment variable has been specified with a true value.
Used value available with the .multi-line-ok
method, and can be used as a left-value to change.
Optional. Specifies the grammar
to be used initially. Defaults to the standard Raku grammar, or to what has been specified with :lang
.
Value available with the .grammar
method.
Optional. Specifies the action class to be used. Defaults to the standard Raku actions, or to what the .actions
method returns on what is specified with :lang
.
Optional. Specified which grammar
/ action class to be used. Defaults to the standard Raku grammar
and action class. If specified, this is usually BEGIN $*LANG
;
$cu.eval('my $a = 42');
$cu.eval('say $a'); # 42
The eval
method evaluates the given string with Raku code within the context of the code unit, and returns the result of the evaluation.
$cu.reset;
The reset
method resets the context of the code unit to its initial state as (implicitely) specified with .new
.
say $cu.compiler-version;
# Welcome to Rakudo™ v2025.01.
# Implementing the Raku® Programming Language v6.d.
# Built on MoarVM version 2025.01.
The compiler-version
method returns the compiler version information, which is typically shown when starting a REPL.
.say for $cu.context-completions;
The 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).
The state
method returns one of the Status
enums to indicate the result of the last call to .eval
. It can also be used as a left-value to set the state (usually to OK
).
with $cu.exception {
note .message.chomp; # Variable '$b' is not declared...
$cu.exception = Nil;
}
The exception
method returns the Exception
object if anything went wrong in the .eval
call. Note that this can also be the case even if the state is OK
. Can also be used as a left-value to (re)set.
The Status
enum is exported: it is used by the state
method to indicate the state of the last call to .eval
. It provides the following states:
-
OK (0) - evalution ok
-
MORE-INPUT (1) - string looks like incomplete code
-
CONTROL (2) - some kind of control statement was executed
my $context = context;
my $cu = CodeUnit.new(:$context);
The context
subroutine returns a context object that can be used to initialize the context of a code unit with.
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 --optimize=off
may make these "invisble" variables visible.
Because each call introduces its own scope, certain side-effects of this scoping behaviour may produce unexpected results and/or errors. For example: my $a = 42
, followed by say $a
, is really:
my $a = 42;
{
say $a;
}
This works because the lexical variable $a
is visible from the scope that has the say
.
Another example which you might expect to give at least a warning, but doesn't: my $a = 42;
followed by my $a = 666
, which would normally produce a worry: "Redeclaration of symbol '$a'", but doesn't here because they are different scopes:
my $a = 42;
{
my $a = 666;
}
As you can see, the second $a
shadows the first $a
, and is not a worry as such.
Future versions of CodeUnit
may be able to work around this scoping behaviour.
Elizabeth Mattijsen liz@raku.rocks
Source can be located at: https://github.com/lizmat/CodeUnit . Comments and Pull Requests are welcome.
If you like this module, or what I'm doing more generally, committing to a small sponsorship would mean a great deal to me!
Copyright 2025 Elizabeth Mattijsen
This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.