parrotcode: Parrot Magic Cookies | |
Contents | Documentation |
docs/pdds/pdd17_pmc.pod - Parrot Magic Cookies
$Revision$
This PDD describes the internal structure and behavior of the Parrot Magic Cookie (PMC) data type.
PMCs implement all internal data types more complex than a simple integer, float, or string, and also the data types of high-level languages. Nothing outside the core of Parrot (in fact, nothing outside the data type's vtable routines) should infer anything about a PMC (hence the Magic part).
This does mean, though, that you need to either know what functions are available and what they do, or have some method of finding out. Parrot defines a standard set of functions that each PMC provides. More complex features are constructed out of these fundamental building blocks.
All PMCs have the form:
struct PMC {
UnionVal cache;
Parrot_UInt flags;
VTABLE *vtable;
DPOINTER *data;
struct PMC_EXT *pmc_ext;
};
where cache
is a UnionVal
union:
typedef union UnionVal {
struct {
void * _bufstart;
size_t _buflen;
} _b;
struct {
DPOINTER* _struct_val;
PMC* _pmc_val;
} _ptrs;
struct _i {
INTVAL _int_val;
INTVAL _int_val2;
} _i;
FLOATVAL _num_val;
struct parrot_string_t * _string_val;
} UnionVal;
u
holds data associated with the PMC. This can be in the form of an integer value, a floating-point value, a string value, or a pointer to other data. u
may be empty, since the PMC structure also provides a more general data pointer, but is useful for PMCs which hold only a single piece of data (e.g. PerlInts
).
flags
holds a set of flags associated with the PMC; these are documented in include/parrot/pobj.h, and are generally only used within the Parrot internals.
vtable
holds a pointer to the vtable associated with the PMC. This points to a set of functions, with interfaces described in "Vtable Functions" that implement the basic behaviour of the PMC (i.e. how it behaves under addition, subtraction, cloning etc.)
data
holds a pointer to the core data associated with the PMC. This may be NULL.
pmc_ext
points to an extended PMC structure. This has the form:
struct PMC_EXT {
PMC *_metadata;
struct _Sync *_synchronize; # [Note: may be deprecated, see STM]
PMC *_next_for_GC;
};
_metadata
holds internal PMC metadata. The specification for this has not yet been finalized.
_synchronize
is for access synchronization between shared PMCs.
_next_for_GC
determines the next PMC in the 'used' list during dead object detection in the GC.
PMCs are not required to have a PMC_EXT
structure (i.e. pmc_ext
can be null).
PMCs are used to implement the basic data types of the high level languages running on top of Parrot. For instance, a Perl 5 SV
will map onto one (or more) types of PMC, while particular Python datatypes will map onto different types of PMC.
PMCs are declared by the pmclass
keyword:
pmclass <name> [ <modifier> ... ] {
}
The modifiers specify core features, such as:
PMC_EXT
structure when instantiating the PMC.abstract
.share_ro()
.)does
which is now called provides
.]does
may also define provides
for one or more interfaces. (They generally define at least a provides
corresponding to their own name.)array
is an aggregate PMC with numerically-keyed elementshash
is an aggregate PMC with string-keyed elementslibrary
corresponds to a dynamic libraryref
references another PMCstring
behaves similarly to the base string typeinteger
behaves similarly to the base int typefloat
behaves similarly to the base number typeboolean
does true/false only.scalar
(only used by the sample src/dynpmc/foo.pmc)event
can be used with event queuehll
modifier.The attributes of a PMC (both public and private) live in a custom struct for the PMC, stored in the data
member of the PMC
struct. The standard way of declaring attributes is with ATTR
within the body of a pmclass
or prole
declaration.
ATTR <type> <name> [ :<modifier> ... ];
This declaration is used to generate the data struct for the PMC (named "Parrot_<pmcname>_Data"). The data struct incorporates any attributes declared in a composed role. The declaration is also used to generate accessor macros for the class, in the form of GET_ATTR_<attrname> and SET_ATTR_<attrname>, and to set up helper information for the inspect
vtable function, and to provide attribue access throught the default get_attr
and set_attr
vtable functions.
It's also possible to define and store the PMC's data struct manually, but the standard declaration syntax must be used in roles, in PMCs that compose roles, and in PMCs that will be subclassed by high-level classes (this means all core PMCs, and most non-core PMCs).
Vtable functions are defined as C functions within the body of the pmclass
declaration, and are marked with VTABLE
.
VTABLE STRING *get_string() {...}
VTABLE void set_string_native(STRING *value) {...}
Within the body of vtable functions, several shortcuts are provided:
SELF
.]SELF
. [NOTE: again, seems that this should be the dynamic type, not static type.]SELF
.Methods are declared in the body of the pmclass
or prole
declaration with METHOD
.
METHOD inspect(STRING *what :optional, int got_what :opt_flag) {...}
[NOTE: There is an older METHOD
keyword, which is deprecated. The current PCCMETHOD
will be renamed to METHOD
.]
Like high-level classes, low-level PMCs are tied to a corresponding namespace. By default this is a namespace with the same name as the PMC in the 'parrot' HLL, but the hll
modifier in the pmclass
declaration selects a different HLL.
Accessing a core PMC type from within an HLL other than 'parrot' requires the same steps as accessing a class from another HLL, first retrieving the namespace object, and then instantiating from that namespace.
$P0 = get_root_namespace ['parrot'; 'Integer']
$P1 = new $P0
HLLs can choose to provide direct access to Parrot's core PMC types by aliasing them within the HLL namespace.
PMCs can inherit behavior and state from other PMCs. Inheritance is performed in the pmclass
declaration using the extends
keyword.
pmclass Foo extends Bar {
}
Composition is another form of code reuse in PMCs. Unlike inheritance, composed roles aren't complete stand-alone PMCs, they are just bundles of behavior and state that can be used within the composing PMC. As such, roles are never instantiated directly, and are never translated to C directly. They have no core structs, though they define attributes to be added to the PMC they are composed into.
When a PMC that uses a role is translated to C, the role provides vtable functions, methods, and attributes that will be added to the generated C code for that PMC. Composed vtable functions, methods, and attributes are not permitted to have the same name as corresponding features defined in the composing PMC. This is called a conflict, and must be explicitly resolved in the composing PMC. When composed features have the same name as inherited vtable functions, methods, or attributes, the composed feature overrides the inherited feature, just as it would if defined in the composing PMC.
Roles are defined using the prole
keyword.
prole <name> <modifiers> {
}
Roles can compose other roles, but they can't inherit.
Role attributes are defined using the same format as PMC attributes.
Core roles live in src/role and have a file extension of .pr
.
Roles are composed into a PMC with the does
modifier.
High-level objects, as specified in PDD15, need to be able to inherit from PMCs. Subclassing a low-level PMC from a high-level class makes an entry in the high-level class's list of parents.
For PDD15 objects, there is a corresponding instance of the Class
PMC. For a low-level PMC, however, the class definition is written in C and compiled away. There needs to be something placed in the parents list for a PDD15 class, that can provide access to the low-level PMC's vtable and methods, and define the storage that the low-level PMC will need within the high-level object. That something is the PMCProxy
PMC. Like a PDD15 class, it is stored as the class
element in the namespace associated with a PMC, provides introspection facilities and can sit in an inheritance hierarchy.
The PMCProxy PMCs are only created when needed for subclassing a low-level PMC, to avoid a large load of unused PMCProxy objects. When created, they are cached in the class slot of the namespace corresponding to the low-level PMC, so they are only created once.
Therefore, subclassing a PMC looks, at a PIR level, like subclassing a high level class.
$P0 = get_class 'Hash'
$P1 = newclass 'MyClass'
addparent $P1, $P0 # The new class inherits from the Hash PMC
Or, more briefly:
$P1 = subclass 'Hash', 'MyClass'
PMCs store state in a very different way to PDD15 objects. When a method inherited from a PMC is called on a PDD15 object, that method needs to access the attributes of the inherited low-level PMC. Further, if multiple PMCs are inherited from, they may each have attributes with the same name, that need to be correctly "visible" to the PDD 15 object according to the laws of inheritance. Users of Parrot at a PIR level should not have to care about such issues.
To enable attributes from the low-level PMC to act as full inherited attributes in the child class, the PMCProxy class will create a set of PDD 15 attributes that correspond in type and name to the attributes declared with ATTR
in the declaration body of the low-level PMC, as if each had been added with add_attribute
. It will also override the GET_ATTR_attrname
and SET_ATTR_attrname
functions to point to the PDD 15 attributes (with automatic boxing and unboxing for the PMC values) rather than to members of a C struct.
The PMCProxy will also scan the low-level PMC for methods declared with METHOD
and insert them in the proxy class as if each had been declared with add_method
(possibly with a shim to standardize calling conventions, but hopefully the calling conventions are similar enough between C-defined and PIR-defined methods not to need a shim). The PMCProxy will maintain a link to the low-level PMC's vtable, and use it for any vtable calls that aren't overridden by the proxy class itself.
As a result, a low-level PMC used as a parent of a PDD 15 class will never be instantiated directly. It will only be used as a source for attribute names and types, methods, and a vtable.
When a method is called on an object whose class has low-level PMC parents, the call is made exactly as it would be for PDD 15 parents. The invocant is always the PDD 15 object. Any method or vtable calls made within the low-level PMC are dispatched on the PDD 15 object invocant. This allows the PDD 15 object to intelligently handle method and vtable overrides within multiple parents and itself.
(This will likely require changing the SELF
shortcut to be equivalent to DYNSELF
, which is what it probably should have been in the first place. We can create an alternative STATICSELF
for the rare cases when we really need it.)
If a low-level PMC expects to be overridden by high-level classes (which means all the core low-level PMC types), it must respect the standard interface.
Vtables decouple the interface and implementation of various object functions. The actual vtable structure contains pointers to functions that implement the methods for that particular PMC. All pointers must point to valid functions with appropriate prototypes.
In C code, the first parameter to any vtable routine is the current interpreter. The second parameter is the PMC itself.
The following list details each of the vtable functions, their prototypes, and their behavior.
void init(INTERP, PMC* self)
void init_pmc(INTERP, PMC* self, PMC* initializer)
PMC* instantiate(INTERP, PMC* self, PMC* init)
PMC* new_from_string(INTERP, PMC* self, STRING* rep, INTVAL flags)
instantiate
. Any initialization arguments can be passed in the init hash.] PMC* inspect(INTERP, PMC* self)
PMC* inspect_str(INTERP, PMC* self, STRING* what)
void morph(INTERP, PMC* self, INTVAL type)
void mark(INTERP, PMC* self)
mark
method on any PMCs it marks--the DOD system takes care of that. (So no need to recurse into aggregate PMCs or anything of the sort). void destroy(INTERP, PMC* self)
PMC* clone(INTERP, PMC* self)
INTVAL defined(INTERP, PMC* self)
PMC* get_class(INTERP, PMC* self)
Class
object (or other high-level class object). For low-level PMCs, this returns a PMCProxy
object. INTVAL class_type(INTERP, PMC* self)
PMC* pmc_namespace(INTERP, PMC* self)
get_namespace
.] PMC* get_namespace(INTERP, PMC* self)
void freeze(INTERP, PMC* self, visit_info* info)
void thaw (INTERP, PMC* self, visit_info* info)
void thawfinish (INTERP, PMC* self, visit_info* info)
void visit (INTERP, PMC* self, visit_info* info)
freeze
and thaw
to visit the contents of the PMC. void share(INTERP, PMC* self)
PMC* share_ro(INTERP, PMC* self)
PMC* getprop(INTERP, PMC* self, STRING* key)
void setprop(INTERP, PMC* self, STRING* key, PMC* value)
void delprop(INTERP, PMC* self, STRING* key)
PMC* getprops(INTERP, PMC* self)
INTVAL type(INTERP, PMC* self)
UINTVAL subtype(INTERP, PMC* self, INTVAL type)
does
and inspect
.] STRING* name(INTERP, PMC* self)
INTVAL get_integer(INTERP, PMC* self)
FLOATVAL get_number(INTERP, PMC* self)
PMC* get_bignum(INTERP, PMC* self)
STRING* get_string(INTERP, PMC* self)
STRING* get_repr(INTERP, PMC* self)
get_string
, candidate for deprecation.] INTVAL get_bool(INTERP, PMC* self)
PMC* get_pmc(INTERP, PMC* self)
get_pmc
is being called on. void set_integer_native(INTERP, PMC* self, INTVAL value)
void set_integer_same(INTERP, PMC* self, PMC* value)
void set_number_native(INTERP, PMC* self, FLOATVAL value)
void set_number_same(INTERP, PMC* self, PMC* value)
void* get_pointer(INTERP, PMC* self)
void set_bignum_int(INTERP, PMC* self, INTVAL value)
void set_string_native(INTERP, PMC* self, STRING* value)
void assign_string_native(INTERP, PMC* self, STRING* value)
void set_string_same(INTERP, PMC* self, PMC* value)
void set_bool(INTERP, PMC* self, INTVAL value)
void assign_pmc(INTERP, PMC* self, PMC* value)
void set_pmc(INTERP, PMC* self, PMC* value)
void set_pointer(INTERP, PMC* self, void* value)
Many of the following functions have a *_keyed form, a *_keyed_int form, and a *_keyed_str form. The keyed forms take a PMC*, INTVAL, or STRING* key as a parameter. The PMC* parameter is NULL if there is no key for that PMC; this means that that argument is unkeyed.
In some cases, the caller must provide a non-NULL key. Those cases are explicitly stated below. In the other cases, you may have to implement the keyed vtable functions and check for a NULL self key even if you are implementing a non-aggregate type. If the self key is non-NULL and the PMC class is a non-aggregate type, the _keyed_* methods should throw an exception.
If you do not implement the *_keyed_int and *_keyed_str functions, the default will convert the INTVAL or STRING* into a key PMC* and call the corresponding *_keyed functions.
INTVAL elements(INTERP, PMC* self)
INTVAL get_integer_keyed(INTERP, PMC* self, PMC* key)
INTVAL get_integer_keyed_int(INTERP, PMC* self, INTVAL key)
INTVAL get_integer_keyed_str(INTERP, PMC* self, STRING* key)
FLOATVAL get_number_keyed(INTERP, PMC* self, PMC* key)
FLOATVAL get_number_keyed_int(INTERP, PMC* self, INTVAL key)
FLOATVAL get_number_keyed_str(INTERP, PMC* self, STRING* key)
STRING* get_string_keyed(INTERP, PMC* self, PMC* key)
STRING* get_string_keyed_int(INTERP, PMC* self, INTVAL key)
STRING* get_string_keyed_str(INTERP, PMC* self, STRING* key)
PMC* get_pmc_keyed(INTERP, PMC* self, PMC* key)
PMC* get_pmc_keyed_int(INTERP, PMC* self, INTVAL key)
PMC* get_pmc_keyed_str(INTERP, PMC* self, STRING* key)
void* get_pointer_keyed(INTERP, PMC* self, PMC* key)
void* get_pointer_keyed_int(INTERP, PMC* self, INTVAL key)
void* get_pointer_keyed_str(INTERP, PMC* self, STRING* key)
void set_integer_keyed(INTERP, PMC* self, PMC* key, INTVAL value)
void set_integer_keyed_int(INTERP, PMC* self, INTVAL key, INTVAL value)
void set_integer_keyed_str(INTERP, PMC* self, STRING* key, INTVAL value)
void set_number_keyed(INTERP, PMC* self, PMC* key, FLOATVAL value)
void set_number_keyed_int(INTERP, PMC* self, INTVAL key, FLOATVAL value)
void set_number_keyed_str(INTERP, PMC* self, STRING* key, FLOATVAL value)
void set_string_keyed(INTERP, PMC* self, PMC* key, STRING* value)
void set_string_keyed_int(INTERP, PMC* self, INTVAL key, STRING* value)
void set_string_keyed_str(INTERP, PMC* self, STRING* key, STRING* value)
void set_pmc_keyed(INTERP, PMC* self, PMC* key, PMC* value)
void set_pmc_keyed_int(INTERP, PMC* self, INTVAL key, PMC* value)
void set_pmc_keyed_str(INTERP, PMC* self, STRING* key, PMC* value)
void set_pointer_keyed(INTERP, PMC* self, PMC* key, void* value)
void set_pointer_keyed_int(INTERP, PMC* self, INTVAL key, void* value)
void set_pointer_keyed_str(INTERP, PMC* self, STRING* key, void* value)
INTVAL type_keyed(INTERP, PMC* self, PMC* key)
INTVAL type_keyed_int(INTERP, PMC* self, INTVAL key)
INTVAL type_keyed_str(INTERP, PMC* self, STRING* key)
INTVAL pop_integer(INTERP, PMC* self)
FLOATVAL pop_float(INTERP, PMC* self)
STRING* pop_string(INTERP, PMC* self)
PMC* pop_pmc(INTERP, PMC* self)
void push_integer(INTERP, PMC* self, INTVAL value)
void push_float(INTERP, PMC* self, FLOATVAL value)
void push_string(INTERP, PMC* self, STRING* value)
void push_pmc(INTERP, PMC* self, PMC* value)
INTVAL shift_integer(INTERP, PMC* self)
FLOATVAL shift_float(INTERP, PMC* self)
STRING* shift_string(INTERP, PMC* self)
PMC* shift_pmc(INTERP, PMC* self)
void unshift_integer(INTERP, PMC* self, INTVAL value)
void unshift_float(INTERP, PMC* self, FLOATVAL value)
void unshift_string(INTERP, PMC* self, STRING* value)
void unshift_pmc(INTERP, PMC* self, PMC* value)
void splice(INTERP, PMC* self, PMC* value, INTVAL offset, INTVAL count)
INTVAL exists_keyed(INTERP, PMC* self, PMC* key)
INTVAL exists_keyed_int(INTERP, PMC* self, INTVAL key)
INTVAL exists_keyed_str(INTERP, PMC* self, STRING* key)
INTVAL defined_keyed(INTERP, PMC* self, PMC* key)
INTVAL defined_keyed_int(INTERP, PMC* self, INTVAL key)
INTVAL defined_keyed_str(INTERP, PMC* self, STRING* key)
void delete_keyed(INTERP, PMC* self, PMC* key)
void delete_keyed_int(INTERP, PMC* self, INTVAL key)
void delete_keyed_str(INTERP, PMC* self, STRING* key)
PMC* nextkey_keyed(INTERP, PMC* self, PMC* key, INTVAL what)
PMC* nextkey_keyed_int(INTERP, PMC* self, INTVAL key, INTVAL what)
PMC* nextkey_keyed_str(INTERP, PMC* self, STRING* key, INTVAL what)
void add(INTERP, PMC* self, PMC* value, PMC* dest)
void add_int(INTERP, PMC* self, INTVAL value, PMC* dest)
void add_float(INTERP, PMC* self, FLOATVAL value, PMC* dest)
void i_add(INTERP, PMC* self, PMC* value)
void i_add_int(INTERP, PMC* self, INTVAL value)
void i_add_float(INTERP, PMC* self, FLOATVAL value)
i_
variants perform an inplace operation, modifying the value of self. PMC* subtract(INTERP, PMC* self, PMC* value, PMC* dest)
PMC* subtract_int(INTERP, PMC* self, INTVAL value, PMC* dest)
PMC* subtract_float(INTERP, PMC* self, FLOATVAL value, PMC* dest)
void i_subtract(INTERP, PMC* self, PMC* value)
void i_subtract_int(INTERP, PMC* self, INTVAL value)
void i_subtract_float(INTERP, PMC* self, FLOATVAL value)
i_
variants perform an inplace operation, modifying the value of self. void increment(INTERP, PMC* self)
void decrement(INTERP, PMC* self)
void multiply(INTERP, PMC* self, PMC* value, PMC* dest)
void multiply_int(INTERP, PMC* self, INTVAL value, PMC* dest)
void multiply_float(INTERP, PMC* self, FLOATVAL value, PMC* dest)
void i_multiply(INTERP, PMC* self, PMC* value)
void i_multiply_int(INTERP, PMC* self, INTVAL value)
void i_multiply_float(INTERP, PMC* self, FLOATVAL value)
i_
variants perform an inplace operation, modifying the value of self. void divide(INTERP, PMC* self, PMC* value, PMC* dest)
void divide_int(INTERP, PMC* self, INTVAL value, PMC* dest)
void divide_float(INTERP, PMC* self, FLOATVAL value, PMC* dest)
void i_divide(INTERP, PMC* self, PMC* value)
void i_divide_int(INTERP, PMC* self, INTVAL value)
void i_divide_float(INTERP, PMC* self, FLOATVAL value)
i_
variants perform an inplace operation, modifying the value of self. PMC* floor_divide(INTERP, PMC* self, PMC* value, PMC* dest)
PMC* floor_divide_int(INTERP, PMC* self, INTVAL value, PMC* dest)
PMC* floor_divide_float(INTERP, PMC* self, FLOATVAL value, PMC* dest)
void i_floor_divide(INTERP, PMC* self, PMC* value)
void i_floor_divide_int(INTERP, PMC* self, INTVAL value)
void i_floor_divide_float(INTERP, PMC* self, FLOATVAL value)
floor()
of the division i.e. the next whole integer towards -inf. If the denominator is zero, a 'Divide by zero' exception is thrown. The i_
variants perform an inplace operation, modifying the value of self. void modulus(INTERP, PMC* self, PMC* value, PMC* dest)
void modulus_int(INTERP, PMC* self, INTVAL value, PMC* dest)
void modulus_float(INTERP, PMC* self, FLOATVAL value, PMC* dest)
void i_modulus(INTERP, PMC* self, PMC* value)
void i_modulus_int(INTERP, PMC* self, INTVAL value)
void i_modulus_float(INTERP, PMC* self, FLOATVAL value)
i_
variants perform an inplace operation, modifying the value of self. void cmodulus(INTERP, PMC* self, PMC* value, PMC* dest)
void cmodulus_int(INTERP, PMC* self, INTVAL value, PMC* dest)
void cmodulus_float(INTERP, PMC* self, FLOATVAL value, PMC* dest)
void i_cmodulus(INTERP, PMC* self, PMC* value)
void i_cmodulus_int(INTERP, PMC* self, INTVAL value)
void i_cmodulus_float(INTERP, PMC* self, FLOATVAL value)
i_
variants perform an inplace operation, modifying the value of self.modulus
uses Knuth's "corrected mod" algorithm, as implemented in src/utils.c, while cmodulus
uses the C-style fmod function. PMC* pow(INTERP, PMC* self, PMC* value, PMC* dest)
PMC* pow_int(INTERP, PMC* self, INTVAL value, PMC* dest)
PMC* pow_float(INTERP, PMC* self, FLOATVAL value, PMC* dest)
void i_pow(INTERP, PMC* self, PMC* value)
void i_pow_int(INTERP, PMC* self, INTVAL value)
void i_pow_float(INTERP, PMC* self, FLOATVAL value)
i_
variants perform an inplace operation, modifying the value of self. PMC* absolute(INTERP, PMC* self, PMC* dest)
void i_absolute(INTERP, PMC* self)
i_
variant performs an inplace operation, modifying the value of self. void neg(INTERP, PMC* self, PMC* dest)
void i_neg(INTERP, PMC* self)
i_
variant performs an inplace operation, modifying the value of self. void bitwise_or(INTERP, PMC* self, PMC* value, PMC* dest)
void bitwise_or_int(INTERP, PMC* self, INTVAL value, PMC* dest)
void i_bitwise_or(INTERP, PMC* self, PMC* value)
void i_bitwise_or_int(INTERP, PMC* self, INTVAL value)
i_
variants perform an inplace operation and store the result in self. PMC* bitwise_and(INTERP, PMC* self, PMC* value, PMC* dest)
PMC* bitwise_and_int(INTERP, PMC* self, INTVAL value, PMC* dest)
void i_bitwise_and(INTERP, PMC* self, PMC* value)
void i_bitwise_and_int(INTERP, PMC* self, INTVAL value)
i_
variants perform an inplace operation and store the result in self. PMC* bitwise_xor(INTERP, PMC* self, PMC* value, PMC* dest)
PMC* bitwise_xor_int(INTERP, PMC* self, INTVAL value, PMC* dest)
void i_bitwise_xor(INTERP, PMC* self, PMC* value)
void i_bitwise_xor_int(INTERP, PMC* self, INTVAL value)
i_
variants perform an inplace operation and store the result in self. PMC* bitwise_ors(INTERP, PMC* self, PMC* value, PMC* dest)
PMC* bitwise_ors_str(INTERP, PMC* self, STRING* value, PMC* dest)
void i_bitwise_ors(INTERP, PMC* self, PMC* value)
void i_bitwise_ors_str(INTERP, PMC* self, STRING* value)
i_
variants perform an inplace operation and store the result in self. PMC* bitwise_ands(INTERP, PMC* self, PMC* value, PMC* dest)
PMC* bitwise_ands_str(INTERP, PMC* self, STRING* value, PMC* dest)
void i_bitwise_ands(INTERP, PMC* self, PMC* value)
void i_bitwise_ands_str(INTERP, PMC* self, STRING* value)
i_
variants perform an inplace operation and store the result in self. PMC* bitwise_xors(INTERP, PMC* self, PMC* value, PMC* dest)
PMC* bitwise_xors_str(INTERP, PMC* self, STRING* value, PMC* dest)
void i_bitwise_xors(INTERP, PMC* self, PMC* value)
void i_bitwise_xors_str(INTERP, PMC* self, STRING* value)
i_
variants perform an inplace operation and store the result in self. PMC* bitwise_not(INTERP, PMC* self, PMC* dest)
void i_bitwise_not(INTERP, PMC* self)
i_
variant performs an inplace operation, storing the result in self. PMC* bitwise_nots(INTERP, PMC* self, PMC* dest)
void i_bitwise_nots(INTERP, PMC* self)
i_
variant performs an inplace operation, storing the result in self. PMC* bitwise_shl(INTERP, PMC* self, PMC* value, PMC* dest)
PMC* bitwise_shl_int(INTERP, PMC* self, INTVAL value, PMC* dest)
void i_bitwise_shl(INTERP, PMC* self, PMC* value)
void i_bitwise_shl_int(INTERP, PMC* self, INTVAL value)
i_
variants perform an inplace operation, storing the result in self.BigInt
. PMC* bitwise_shr(INTERP, PMC* self, PMC* value, PMC* dest)
PMC* bitwise_shr_int(INTERP, PMC* self, INTVAL value, PMC* dest)
void i_bitwise_shr(INTERP, PMC* self, PMC* value)
void i_bitwise_shr_int(INTERP, PMC* self, INTVAL value)
i_
variants perform an inplace operation, storing the result in self.BigInt
(when value is negative). PMC* bitwise_lsr(INTERP, PMC* self, PMC* value, PMC* dest)
PMC* bitwise_lsr_int(INTERP, PMC* self, INTVAL value, PMC* dest)
void i_bitwise_lsr(INTERP, PMC* self, PMC* value)
void i_bitwise_lsr_int(INTERP, PMC* self, INTVAL value)
i_
variants perform an inplace operation, storing the result in self. INTVAL is_equal(INTERP, PMC* self, PMC* value)
INTVAL is_equal_num(INTERP, PMC* self, PMC* value)
INTVAL is_equal_string(INTERP, PMC* self, PMC* value)
_num
version tests for numeric equality, while the _string
version tests for string equality. INTVAL is_same(INTERP, PMC* self, PMC* value)
INTVAL cmp(INTERP, PMC* self, PMC* value)
INTVAL cmp_num(INTERP, PMC* self, PMC* value)
INTVAL cmp_string(INTERP, PMC* self, PMC* value)
_num
version performs a numeric comparison, while the _string
version performs a string comparison. PMC* logical_or(INTERP, PMC* self, PMC* value, PMC* dest)
PMC* logical_and(INTERP, PMC* self, PMC* value, PMC* dest)
PMC* logical_xor(INTERP, PMC* self, PMC* value, PMC* dest)
PMC* logical_not(INTERP, PMC* self, PMC* dest)
void i_logical_not(INTERP, PMC* self)
i_
variant performs an inplace negation, modifying the value of self. PMC* concatenate(INTERP, PMC* self, PMC* value, PMC* dest)
PMC* concatenate_str(INTERP, PMC* self, STRING* value, PMC* dest)
void i_concatenate(INTERP, PMC* self, PMC* value)
void i_concatenate_str(INTERP, PMC* self, STRING* value)
i_
variant performs an inplace concatenation, modifying the value of self. PMC* repeat(INTERP, PMC* self, PMC* value, PMC* dest)
PMC* repeat_int(INTERP, PMC* self, INTVAL value, PMC* dest)
void i_repeat(INTERP, PMC* self, PMC* value)
void i_repeat_int(INTERP, PMC* self, INTVAL value)
i_
variants perform an inplace operation, modifying the value of self. void substr(INTERP, PMC* self, INTVAL offset, INTVAL length, PMC* dest)
STRING* substr_str(INTERP, PMC* self, INTVAL offset, INTVAL length)
opcode_t* invoke(INTERP, PMC* self, void* next)
INTVAL can(INTERP, PMC* self, STRING* method)
INTVAL isa(INTERP, PMC* self, STRING* classname)
INTVAL does(INTERP, PMC* self, STRING* role)
does
(composes) or performs
(satisfies the interface of) the role named role, return 0 otherwise. PMC* get_attr(INTERP, PMC* self, INTVAL idx) [deprecated]
PMC* get_attr_str(INTERP, PMC* self, STRING* idx)
void set_attr(INTERP, PMC* self, INTVAL idx, PMC* value) [deprecated]
void set_attr_str(INTERP, PMC* self, STRING* idx, PMC* value)
void add_parent(INTERP, PMC* self, PMC* parent)
void remove_parent(INTERP, PMC* self, PMC* parent)
void add_role(INTERP, PMC* self, PMC* role)
void remove_role(INTERP, PMC* self, PMC* role)
void add_attribute(INTERP, PMC* self, STRING* name, PMC* type)
void remove_attribute(INTERP, PMC* self, STRING* name)
void add_method(INTERP, PMC* self, STRING* method_name, PMC* sub_pmc)
void remove_method(INTERP, PMC* self, STRING* method_name)
void add_vtable_override(INTERP, PMC* self, STRING* vtable_name, PMC* sub_pmc)
void remove_vtable_override(INTERP, PMC* self, STRING* vtable_name)
PMC* subclass(INTERP, PMC* self, PMC* name)
subclass
opcode, but implement it using this more direct route. (With the added advantage of increased abstraction, allowing multiple object metamodels more easily.)] PMC* find_method(INTERP, PMC* self, STRING* method_name)
Parrot has a number of core PMC types that all programs can guarantee will be available to them. (With the possible exception of Parrot programs executing on an embedded device or other restricted environment)
register_ref
opcode. Any assignment to the register will behave like a set instruction. That is, when assigning a PMC using a WeakRegisterRef PMC, the register will be updated to reference that PMC rather than calling the assign v-table call on the PMC in that register. This is not the same behaviour as the Ref PMC.ResizablePMCArray
, but that's likely to change.Note that for the following types you can set the size of the array by using the VTABLE_set_integer_native() method. Assigning an integer to the array as a whole sets the array to that size.
Size-changing operations (such as push, pop, shift, unshift, and splice) on statically-sized arrays will throw an exception.
ResizablePMCArray returns Undef for unset elements (so does the new object model, because it uses ResizablePMCArray for storage), but Hash returns PMCNULL. Standardize all core aggregate PMC types on the singleton PMCNULL.
new P1, 'Env'
set S1, P1['TERM']
Sub
that provides dynamic code evaluation and execution.None.
None.
docs/pmc2c.pod
|