This document describes NAM, aka CgOp, the Niecza Abstract Machine. NAM is the language used to connect the portable parts of Niecza to the unportable. It is the last Niecza IR which is shared between all cross-compiler backends. It is used primarily to refer to two things: a computing model suitable for running Niecza output and a representation of abstract operations in the model.
NAM does not define a file format, nor does it handle the details of representing classes or similar things. Those are handled by a separate backend protocol (not yet documented). NAM only handles the executable expressions and statements that make up sub bodies.
Each sub which is created by the frontend is associated with a string of NAM code, and a list of metaobjects referenced by the NAM code. The backend then needs to use this code to make the sub executable; the CLR backend delays this as long as possible because of quirks of the AssemblyBuilder/TypeBuilder interface, but this is not generally required.
NAM code must be statically typable but this may not always be enforced. Different data objects have logical types, which can map many-to-one onto lower-level types, especially in type-poor environments such as Parrot and JavaScript.
NAM is vaguely similar to Lisp, in the sense that NAM code is built out of expressions which have a value and possibly side effects. An example might do well here:
["say",["str","Hello, world"]]
Here the "str" expression returns a str
, while the "say" expression does not return anything. NAM, like many backends, does not treat void
as a runtime type, and in fact has no way to represent the name.
NAM code is send to the backend in the form of a variant of JSON. Mappings and undefined
are not used; only sequences, strings, numbers, null
, true
, and false
will be generated. One additional syntactic item is added, !123
, which uses a decimal index to represent a runtime object which the code needs to reference.
Within string literals, the only escape sequence used is \uABCD
, with the requirement to use surrogate characters for codepoints outside the BMP. Outside string literals, whitespace is generally not used.
A native integer, suitable for loop variables and similar purposes.
A native float, suitable for the Perl 6 Num class.
A native bool, as returned by comparison operators.
A reference to a native immutable string.
A reference to a native mutable string.
A Perl 6 variable, with identity, potentially mutable and tied.
A reference to a Perl 6 object; not a variable and cannot be assigned to.
A hash table mapping strings to Perl 6 variables.
An array of Perl 6 variables fixed in length at creation.
An array of Perl 6 variables supporting O(1) deque operations.
The nexus of HOW, WHAT, WHO, and REPR. Details subject to flux.
A reference to a native text input object.
A reference to a native text output object.
A node in the LTM Automaton Descriptor metaobject tree.
A reference to a compiled character class.
A reference to a low-level cursor. Currently a subtype of obj.
A reference to a call frame. Currently a subtype of obj.
These do not appear in nam files as they are expanded in src/CgOp.pm6
.
Evaluates arguments in sequence and returns CORE::Nil
. Useful for embedding a sequence of void nam ops in a Perl 6 statement list.
These should not be used by the frontend. They are used for construction of some internal code fragments, usually in response to _hack settings.
Sets the $line_number
for the $operation
. In the C# backend, line number is only recorded at high-level call sites within the span.
Within $body
, any lexical access to a $lexname
is remapped into a letvar
access to the corresponding $letname
. This is used for inlined functions. If $transparent
is false, the corresponding scope should be seen by OUTER::
and the like (not yet implemented).
Generates the code for $body
bracketed by the labels $n1
and $n2
. If an exception transfers control to $n2
, the exception payload will be returned. Triples of $code
, $label
, and $goto
define exception handling within the block. $sync
forces exception handling to be synchronous with respect to the boundaries, allowing an ON_DIE
handler to function properly.
For each triple, while execution is within the block, an exception of class $class
[1] will cause control to be transferred to $goto
. $name
is used for targetted control exceptions, possibly paired with the identity of the target frame. A name of the empty string is treated as no name; such handlers can only be reached anonymously.
[1] The following class values are currently defined:
1 ON_NEXT &next
2 ON_LAST &last
3 ON_REDO &redo
4 ON_RETURN &return
5 ON_DIE General exception, payload usually Str
6 ON_SUCCEED &succeed, when{} matched
7 ON_PROCEED &proceed
8 ON_GOTO &goto
9 ON_NEXTDISPATCH &nextsame, &nextwith; payload is a Capture
Adds $left and $right together.
The basic polymorphic assignment operator. Depending on the list status of the left variable, either generates a basic store, or a LISTSTORE method call.
Extracts the value stored in a variable.
Creates a new scalar variable of type Any containing Any.
Used for binding parameters in beta-eliminated subs, used to be the heart of the binder but this is no longer so.
Wraps $obj
in a read-only variable with the list nature.
Creates a new variable of type Any containing $obj
.
Wraps $obj
in a read-only variable.
Were used for autovivification; currently unused.
Creates an autovivifiable variable which will call $sub
when written to or bound rw, and otherwise functions as ordinary rw.
Returns the object backing $var
(will be a fake proxy if not tied).
True if $var
has the list nature.
Creates a new variable of type $type
which delegates access to $fetch
and $store
. If $bind
is defined, it will be called on the first rw binding, per the autovivification protocol.
Implements X
or Xop
; if $usefun
is true, the first item in $fvarlist
is taken as a function reference.
Implements Z
or Zop
; if $usefun
is true, the first item in $fvarlist
is taken as a function reference.
A fvarlist
is a fixed sized object like a C# or Java Variable[]
array. A vvarlist
is an O(1) deque like a C++ std::deque<var>
. Most operations on these types are fairly straightforward. vvarlist
also does duty as the most fundamental type of iterator; several operations are designed to do essential iterator tasks. vvarlist_
operations are not cognizant of iterator structure and should not be used on iterators without careful consideration of the effect.
Extracts a single element. BUG: Currently evaluates its arguements in the wrong order.
Return the number of elements in the argument as an int
.
Construct a new fvarlist of compile-time length, like a C# array literal.
Creates a new iterator which iterates over the same values, but all copied into fresh read-write variables. Mostly eager.
Creates a new iterator which mostly-eagerly presents the same values with sublists flattened.
Attempts to extract a value from an iterator without flattening sublists. Returns bool
; if true, the value may be returned by vvarlist_shift
.
See iter_hasarg
.
Adds all elements (non-destructively) from a source list onto the end of a destination list in order.
Creates a new non-aliasing list with all elements aliases of the elements of an old list.
Returns the number of items in a list.
Creates a new list with exactly one initial element. Useful for bootstrapping iterations.
Removes and returns the last element of a nonempty list.
Adds a new element to the end of a list.
Removes and returns the first element of a nonempty list.
Sorts a list (not in place). $cb_obj
must be an invocable object which functions as a two-argument sort routine, returning Num
.
Adds a new element to the beginning of a list.
Adds the contents of a fixed list to the beginning of a variable list in order.
Go to label named $name
(must be a literal string) if $if
is true.
The most general interface to the exception generator.
Passes control to a coroutine identified by the continuation frame $cont
. When said coroutine uses take, the new continuation frame is stored in the $*nextframe
lexical and the value passed is returned.
Throws a basic non-resumable exception. $exception
may be a raw string and it will DWIM.
Calls method $name
on the first argument. The interpretation of the rest of the arguments is controlled by $sig
; for each argument, there is a token in $sig
consisting of a length and a sequence of characters. A zero-length sequence represents an ordinary positional, a string like ":name" represents a named parameter, and "flatcap" represents a | parameter. Note that in the last case, the argument should have type obj
.
See cgoto.
Evaluates arguments in sequence and returns the result of the last one.
Low-level return from a body; does NOT use the control exception mechanism. Probably best regarded as a backend-internal operator.
Creates a new coroutine to invoke $sub
without arguments, and returns the initial continuation frame.
Identical to methodcall, except that the method name is considered forced to INVOKE
.
Passes $thing
to the coroutine which caused the current coroutine to be invoked. When this coroutine is restarted, take returns the value unchanged.
The basic branching operator.
The basic repetition operator. If $once
is passed, the loop is treated as repeat..while. If $until
is passed, the condition is inverted.
The const op causes its argument to be evaluated once and stored in the constant table; it should only be used in cases where the identity will have the same effect, and backends are not required to honor it.
Produces a null value of type $type
, suitable for initializing a variable or other similar usage.
Evaluates and ignores $argument.
Creates a boxing object of a given type. $proto
may be a CORE:: name.
Returns the raw stab
for a class, by CORE:: name or xref node fields.
Implements Mu.new.
Fetches a named slot from an object. $type
must be used consistantly.
Returns the ClassHOW or similar instance for an object.
Instantiates a parameterized role (first argument) with arguments (rest).
Checks REPR-level definedness, not .defined.
Fastest way to create an object. Does not set up variables for attributes.
Implements the but operator for type objects.
Mutates a boxed value in place. Use carefully!
Binds a slot, possibly to a native value.
Obtains a reference to the Sub implementing a private method.