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.
It's faster if you know which vtable entry does what,
so that's the method parrot uses.
- Where should c-level role implementations live?
In src/pmc?
What naming convention should we use for the files?
Singleton role goes to rsingleton.pmc?
- Should we create a pmrole keyword like pmclass?
And pmr2c to translate them to C?
How different are classes and roles at the PMC level?
- <particle> pmclass needs a keyword to specify what roles a class is composed from.
We're already using 'does',
but in an ad hoc way,
from what I can see in the little docs there are about 'does'.
- <particle> Do c-level roles have custom flags like PMCs?
Class PMC has a custom flag for 'instantiated',
right now it uses a full int,
which I think is a waste of space.
<allison> 8 bits is pretty limited,
and IIRC we've already run into the limitation.
This runs back to Leo's proposal to make PMCs a little more flexible,
so we wouldn't have to hold all PMCs to the same 8 bits
- <pmichaud> there is a question about when 'Integer' is not really .Integer e.g.,
in a HLL,
the meaning of 'Integer' can be different,
and using
new 'Integer'
is safe only if in the root of the parrot HLL namespace
<allison> true,
the only way to guarantee that you're getting a built-in PMC under the type id-less system is to look in the 'parrot' HLL,
and even that isn't a total guarantee,
because it could have been replaced in the 'parrot' HLL
<pmichaud> the closest we have at the moment is
$P0 = get_root_namespace ['parrot'; 'Integer']
$P1 = new $P0
but even this assumes that the 'Integer' namespace is tied to the Integer class, which also hasn't been specced
<allison> builtin PMCs will be tied to a corresponding spot in the 'parrot' HLL namespace
<pmichaud> according to pdd15: $P0 = new .Integer
can be replaced by $P0 = new 'Integer'
only in the parrot root namespace. in all other namespaces, one would need to get the namespace for the 'Integer' class and use that
$P0 = new 'Integer' # works in parrot HLL, root namespace
$P0 = new ['Integer'] # works in parrot HLL, any namespace
<pmichaud> even easier, HLLs can set their notion of 'Integer' to point to the parrot class :-)
<allison> yes, aliasing across namespaces is allowed
<particle> we can design a decoration for core pmcs with something that doesn't allow override in 'parrot' namespace, if it's wanted.
<pmichaud> particle: I'm not sure it's entirely necessary to have the decoration i.e., I'd wait until we find we need it :-)
<particle> sure, it's mostly a change for pmc2c i suspect
pmclass Foo does bar extends baz is_core {
ResizablePMCArray returns Undef for unset elements (so does the new object model, because it uses ResizablePMCArray for storage), but Hash returns null. Various other PMCs return different values for undefinedness. Pick a standard. The current favorite is a singleton Null PMC. Check the implementation of PMCNULL.
<chromatic> How does COW work and why doesn't COW work? (docs/glossary.pod)
- - High-level objects can subclass low-level PMCs
All PMCs have the form:
struct PMC {
pobj_t obj;
VTABLE *vtable;
PMC *real_self;
#if ! PMC_DATA_IN_EXT
DPOINTER *data;
#endif
struct PMC_EXT *pmc_ext;
};
where obj
is a pointer to a pobj_t
structure:
typedef struct pobj_t {
UnionVal u;
Parrot_UInt flags;
} pobj_t;
and where:
typedef union UnionVal {
struct {
void * _bufstart;
size_t _buflen;
} _b;
struct {
DPOINTER* _struct_val;
PMC* _pmc_val;
} _ptrs;
INTVAL _int_val;
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.)
{{ PROPOSED: real_self
holds a pointer to the PMC that dynamically dispatched method calls should be made on. Normally this will be a pointer directly back to the PMC itself. However, in the case that the PMC has been subclassed by a non-PMC it will hold a pointer to the real object. This is so DYNSELF.method() style calls will dispatch correctly, calling any methods and/or v-table methods that have been overridden in PIR. }}
data
(if present) holds a pointer to any additional data associated with the PMC. This may be NULL.
pmc_ext
points to an extended PMC structure. This has the form:
struct PMC_EXT {
#if PMC_DATA_IN_EXT
DPOINTER *data;
#endif
PMC *_metadata; # [Note: replaced by roles]
struct _Sync *_synchronize; # [Note: may be deprecated, see STM]
PMC *_next_for_GC;
};
data
is a generic data pointer, as described above.
_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.
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 methods, their prototypes, and their behavior.
- void init(INTERP, PMC* self)
- Called when a PMC is first instantiated. It takes an unused PMC parameter and turns it into a PMC of the appropriate class.
- void init_pmc(INTERP, PMC* self, PMC* initializer)
- Alternative entry point called when a PMC is first instantiated. Accepts a PMC parameter used to initialize the given object. Interpretation of the PMC initializer is left open, each PMC is free to choose its own implemention. A NULL value passed as the initializer parameter is allowed.
- NOTE: It is strongly suggested that init_pmc(PMCNULL) be equivalent to init(), though there will of necessity be exceptions.
- void morph(INTERP, PMC* self, INTVAL type)
- Turn the PMC into a PMC of type type. If the morphing can't be done in any reasonable way -- for instance if an integer is asked to turn into an Array -- then the PMC is first destroyed, then recreated as an empty PMC of the new type.
- This method is primarily used when the interpreter has need of coercing a PMC to a particular type, and isn't meant as a general purpose casting tool. Compilers should only emit valid morphing operations.
- void mark(INTERP, PMC* self)
- Called when the DOD is tracing live PMCs. If this method is called then the code must mark all strings and PMCs that it contains as live, otherwise they may be collected.
- This method is only called if the DOD has detected that this PMC is both alive and has a custom mark routine as indicated by the custom mark PMC flag. (Most normal PMCs don't need a custom mark routine.)
- If a PMC has this flag set, then it is responsible for marking all buffers and PMCs under its control as alive. If it does not, those PMCs or buffers may be collected later. This method does not have to call the
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).
- This method may allocate no memory from Parrot, nor may it alter Parrot's internal structures. It should have no side-effects from the C level either. This routine may not throw an exception.
- void destroy(INTERP, PMC* self)
- Called when the PMC is destroyed. This method is called by the DOD when it determines that a PMC is dead and that the PMC has marked itself as having a destroy method (an active finalizer).
- When this method finishes, the PMC will be marked as dead. As such you should make sure that you don't leave any references to it in any Parrot structure by the end of the method.
- This method may not throw an exception. It will be ignored if it does.
- PMC* clone(INTERP, PMC* self)
- Return a clone of a PMC.
- defined
- PMC* getprop(INTERP, PMC* self, STRING* key)
- Return the value from the property hash of self keyed by key. The key should not be NULL.
- void setprop(INTERP, PMC* self, STRING* key, PMC* value)
- Set the value in the property hash of self that is keyed by key to the value of value. The key should not be NULL.
- void delprop(INTERP, PMC* self, STRING* key)
- Delete the value from the property hash of self keyed by key. The key should not be NULL.
- PMC* getprops(INTERP, PMC* self)
- Return the entire property hash for self.
- INTVAL type(INTERP, PMC* self)
- Return the type of the PMC. Type is a unique number associated with the PMC when the PMC's class is loaded. Negative numbers are considered interpreter-specific, non-public types.
- UINTVAL subtype(INTERP, PMC* self, INTVAL type) [deprecated]
- Return the subtype of a PMC. (Note that this may be unimplemented, and may go away). This is intended to return information about the PMC--what type of number or string it is, whether it's a scalar, hash, array, or list, and suchlike things.
- [This can be adequately handled by
does
and inspect
.]
- STRING* name(INTERP, PMC* self)
- Return the name of the class for the PMC.
- get_integer
INTVAL get_integer(INTERP, PMC* self)
- Return the native integer value of the PMC.
- get_number
FLOATVAL get_number(INTERP, PMC* self)
- Return the native floating-point value of the PMC.
- get_bignum
PMC* get_bignum(INTERP, PMC* self)
- Return the extended precision numeric value of the PMC as a new bignum PMC.
- get_string
STRING* get_string(INTERP, PMC* self)
- Return the native string value of the PMC. This may be in any encoding, chosen by the PMC.
- get_bool
INTVAL get_bool(INTERP, PMC* self)
- Return the true/false value of the PMC (the constant TRUE or the constant FALSE). The definition of truth for a given PMC will depend on the type of the PMC. For a scalar, it may be as simple as returning false when the PMC has a value 0 or "", and returning true when the PMC has any other value.
- get_pmc
PMC* get_pmc(INTERP, PMC* self)
- Return the PMC value for this PMC. This is useful in circumstances where the thing being accessed may return something other than its own value. For example, an array might return a reference to itself. Any PMC may return a value different from the PMC that
get_pmc
is being called on.
- set_integer_native
void set_integer_native(INTERP, PMC* self, INTVAL value)
- Set the integer value of this PMC from a native integer value (integer register/constant).
- set_integer_same
void set_integer_same(INTERP, PMC* self, PMC* value)
- Set the value of this PMC from the integer value of another PMC. The value PMC is guaranteed to be of the same type as the self PMC, so optimizations may be made.
- set_number_native
void set_number_native(INTERP, PMC* self, FLOATVAL value)
- Set the value of this PMC from a native floating-point value (float register/constant).
- set_number_same
void set_number_same(INTERP, PMC* self, PMC* value)
- Set the value of this PMC from the floating-point value another PMC. The value PMC is guaranteed to be of the same type as the self PMC, so optimizations may be made.
- get_pointer
void* get_pointer(INTERP, PMC* self)
- Returns a pointer value for the PMC. Useful for PMCs that hold pointers to arbitrary data. The details of the data (type, location etc.) depend on the PMC.
- set_bignum_int
void set_bignum_int(INTERP, PMC* self, INTVAL value)
- Morph the PMC to a BIGNUM PMC, and set the extended-precision value from a native integer.
- set_string_native
void set_string_native(INTERP, PMC* self, STRING* value)
- Set the value of this PMC from a native string value (string register/constant).
- assign_string_native
void assign_string_native(INTERP, PMC* self, STRING* value)
- Set the value of this PMC to a copied native string value (string register/constant).
- set_string_same
void set_string_same(INTERP, PMC* self, PMC* value)
- Set the value of this PMC from the string value of another PMC. The value PMC is guaranteed to be of the same type as the self PMC, so optimizations may be made.
- set_bool
void set_bool(INTERP, PMC* self, INTVAL value)
- Set the boolean state of the PMC to TRUE if the native integer value passed in is TRUE, or FALSE if the value is FALSE. The definition of truth is left open to the particular PMC. For a scalar, it may be as simple as setting false when a 0 value is passed in, and seting true when any other value is passed in.
- assign_pmc
void assign_pmc(INTERP, PMC* self, PMC* value)
- Set the value of the PMC in self to the value of the PMC in value by copying the value.
- set_pmc
void set_pmc(INTERP, PMC* self, PMC* value)
- Make the PMC in self refer to the PMC passed as value.
- set_pointer
void set_pointer(INTERP, PMC* self, void* value)
- Set the pointer value of the PMC Useful for PMCs that hold pointers to arbitrary data. The details of the data (type, location etc.) depend on the PMC.
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.
- elements
INTVAL elements(INTERP, PMC* self)
- Return the number of elements in the PMC.
- get_integer_keyed
INTVAL get_integer_keyed(INTERP, PMC* self, PMC* key)
- Return the integer value for the element indexed by a PMC key. The key is guaranteed not to be NULL for this function.
- get_integer_keyed_int
INTVAL get_integer_keyed_int(INTERP, PMC* self, INTVAL key)
- Return the integer value for the element indexed by an integer key. The key is guaranteed not to be NULL for this function.
- get_integer_keyed_str
INTVAL get_integer_keyed_str(INTERP, PMC* self, STRING* key)
- Return the integer value for the element indexed by a string key. The key is guaranteed not to be NULL for this function.
- get_number_keyed
FLOATVAL get_number_keyed(INTERP, PMC* self, PMC* key)
- Return the native floating-point value for the element indexed by a PMC key. The key is guaranteed not to be NULL for this function.
- get_number_keyed_int
FLOATVAL get_number_keyed_int(INTERP, PMC* self, INTVAL key)
- Return the native floating-point value for the element indexed by an integer key. The key is guaranteed not to be NULL for this function.
- get_number_keyed_str
- Return the native floating-point value for the element indexed by a string key. The key is guaranteed not to be NULL for this function.
- get_string_keyed
STRING* get_string_keyed(INTERP, PMC* self, PMC* key)
- Return the string value for the element indexed by a PMC key. The key is guaranteed not to be NULL for this function.
- get_string_keyed_int
STRING* get_string_keyed_int(INTERP, PMC* self, INTVAL key)
- Return the string value for the element indexed by an integer key. The key is guaranteed not to be NULL for this function.
- get_string_keyed_str
STRING* get_string_keyed_str(INTERP, PMC* self, STRING* key)
- Return the string value for the element indexed by a string key. The key is guaranteed not to be NULL for this function.
- get_bool_keyed
- Return the boolean value for the element indexed by a PMC key.
- get_bool_keyed_int
- Return the boolean value for the element indexed by an integer key.
- get_bool_keyed_str
- Return the boolean value for the element indexed by a string key.
- get_pmc_keyed
PMC* get_pmc_keyed(INTERP, PMC* self, PMC* key)
- Return the PMC value for the element indexed by a PMC key. The key is guaranteed not to be NULL for this function.
- get_pmc_keyed_int
PMC* get_pmc_keyed_int(INTERP, PMC* self, INTVAL key)
- Return the PMC value for the element indexed by an integer key. The key is guaranteed not to be NULL for this function.
- get_pmc_keyed_str
PMC* get_pmc_keyed_str(INTERP, PMC* self, STRING* key)
- Return the PMC value for the element indexed by a string key. The key is guaranteed not to be NULL for this function.
- get_pointer_keyed
void* get_pointer_keyed(INTERP, PMC* self, PMC* key)
- Return the pointer value for the element indexed by a PMC key. The details of the data (type, location etc.) depend on the PMC.
- get_pointer_keyed_int
void* get_pointer_keyed_int(INTERP, PMC* self, INTVAL key)
- Return the pointer value for the element indexed by an integer key. The details of the data (type, location etc.) depend on the PMC.
- get_pointer_keyed_str
void* get_pointer_keyed_str(INTERP, PMC* self, STRING* key)
- Return the pointer value for the element indexed by a string key. The details of the data (type, location etc.) depend on the PMC.
- set_integer_keyed
void set_integer_keyed(INTERP, PMC* self, PMC* key, INTVAL value)
- Set the integer value of the element indexed by a PMC key. The key is guaranteed not to be NULL for this function.
- set_integer_keyed_int
void set_integer_keyed_int(INTERP, PMC* self, INTVAL key, INTVAL value)
- Set the integer value of the element indexed by an integer key. The key is guaranteed not to be NULL for this function.
- set_integer_keyed_str
void set_integer_keyed_str(INTERP, PMC* self, STRING* key, INTVAL value)
- Set the integer value of the element indexed by a string key. The key is guaranteed not to be NULL for this function.
- set_number_keyed
void set_number_keyed(INTERP, PMC* self, PMC* key, FLOATVAL value)
- Set the floating-point value of the element indexed by a PMC key. The key is guaranteed not to be NULL for this function.
- set_number_keyed_int
void set_number_keyed_int(INTERP, PMC* self, INTVAL key, FLOATVAL value)
- Set the floating-point value of the element indexed by an integer key. The key is guaranteed not to be NULL for this function.
- set_number_keyed_str
void set_number_keyed_str(INTERP, PMC* self, STRING* key, FLOATVAL value)
- Set the floating-point value of the element indexed by a string key. The key is guaranteed not to be NULL for this function.
- set_string_keyed
void set_string_keyed(INTERP, PMC* self, PMC* key, STRING* value)
- Set the string value of the element indexed by a PMC key. The key is guaranteed not to be NULL for this function.
- set_string_keyed_int
void set_string_keyed_int(INTERP, PMC* self, INTVAL key, STRING* value)
- Set the string value of the element indexed by an integer key. The key is guaranteed not to be NULL for this function.
- set_string_keyed_str
void set_string_keyed_str(INTERP, PMC* self, STRING* key, STRING* value)
- Set the string value of the element indexed by a string key. The key is guaranteed not to be NULL for this function.
- set_pmc_keyed
void set_pmc_keyed(INTERP, PMC* self, PMC* key, PMC* value)
- Set the value of the element indexed by a PMC key, by copying the value of another PMC.
- set_pmc_keyed_int
void set_pmc_keyed_int(INTERP, PMC* self, INTVAL key, PMC* value)
- Set the PMC value of the element indexed by an integer key, by copying the value of another PMC.
- set_pmc_keyed_str
void set_pmc_keyed_str(INTERP, PMC* self, STRING* key, PMC* value)
- Set the PMC value of the element indexed by a string key, by copying the value of another PMC.
- set_pointer_keyed
void set_pointer_keyed(INTERP, PMC* self, PMC* key, void* value)
- Set the pointer value of the element indexed by a PMC key.
- set_pointer_keyed_int
void set_pointer_keyed_int(INTERP, PMC* self, INTVAL key, void* value)
- Set the pointer value of the element indexed by an integer key.
- set_pointer_keyed_str
void set_pointer_keyed_str(INTERP, PMC* self, STRING* key, void* value)
- Set the pointer value of the element indexed by a string key.
- INTVAL type_keyed(INTERP, PMC* self, PMC* key)
- Return the type number of the PMC indexed by a PMC key. The key parameter is guaranteed not to be NULL for this method.
- INTVAL type_keyed_int(INTERP, PMC* self, INTVAL key)
- Return the type number of the PMC indexed by an integer key. The key parameter is guaranteed not to be NULL for this method.
- INTVAL type_keyed_str(INTERP, PMC* self, STRING* key)
- Return the type number of the PMC indexed by a string key. The key parameter is guaranteed not to be NULL for this method.
- pop_integer
INTVAL pop_integer(INTERP, PMC* self)
- Return the integer value of the last item on the list, removing that item.
- pop_float
FLOATVAL pop_float(INTERP, PMC* self)
- Return the floating-point value of the last item on the list, removing that item.
- pop_string
STRING* pop_string(INTERP, PMC* self)
- Return the string value of the last item on the list, removing that item.
- pop_pmc
PMC* pop_pmc(INTERP, PMC* self)
- Return the PMC value of the last item on the list, removing that item.
- push_integer
void push_integer(INTERP, PMC* self, INTVAL value)
- Add the passed in integer value to the end of the list.
- push_float
void push_float(INTERP, PMC* self, FLOATVAL value)
- Add the passed in floating-point number to the end of the list.
- push_string
void push_string(INTERP, PMC* self, STRING* value)
- Add the passed in string to the end of the list.
- push_pmc
void push_pmc(INTERP, PMC* self, PMC* value)
- Add the passed in PMC to the end of the list.
- shift_integer
INTVAL shift_integer(INTERP, PMC* self)
- Return the integer value of the first item on the list, removing that item.
- shift_float
FLOATVAL shift_float(INTERP, PMC* self)
- Return the floating-point value of the first item on the list, removing that item.
- shift_string
STRING* shift_string(INTERP, PMC* self)
- Return the string value of the first item on the list, removing that item.
- shift_pmc
PMC* shift_pmc(INTERP, PMC* self)
- Return the PMC value of the first item on the list, removing that item.
- unshift_integer
void unshift_integer(INTERP, PMC* self, INTVAL value)
- Add the passed in integer value to the beginning of the list.
- unshift_float
void unshift_float(INTERP, PMC* self, FLOATVAL value)
- Add the passed in floating-point number to the beginning of the list.
- unshift_string
void unshift_string(INTERP, PMC* self, STRING* value)
- Add the passed in string to the beginning of the list.
- unshift_pmc
void unshift_pmc(INTERP, PMC* self, PMC* value)
- Add the passed in PMC to the beginning of the list.
- splice
- void splice(INTERP, PMC* self, PMC* value, INTVAL offset, INTVAL count)
- Replace the count PMCs at offset offset from the beginning of self with the PMCs in the aggregate value.
- exists_keyed
- exists_keyed_int
- exists_keyed_str
- defined_keyed
- defined_keyed_int
- defined_keyed_str
- dtem delete_keyed_str
- nextkey_keyed
- nextkey_keyed_itr_str
- add
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)
- Add the value of self to the value of a PMC, native integer, or native floating-point number and store the result in a PMC dest. Note that dest may be the same PMC as self; in that case optimizations may be made.
- subtract
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)
- Subtract the value of a PMC, native integer, or native floating-point number from a PMC and store the result in dest. If dest is NULL create a result PMC of an appropriate type. Note that dest may be the same PMC as self; in that case optimizations may be made.
- i_subtract
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)
- Inplace operation: subtract a PMC, native integer, or native floating-point number from the value of a PMC and store the result back in the same PMC.
- increment
- decrement
- multiply
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)
- Multiply a PMC, native integer, or floating-point value by the value of the PMC self and store the result in the dest PMC. Note that dest may be the same PMC as self; in that case optimizations may be made.
- divide
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)
- Divide the value of the self PMC by a PMC, native integer, or native floating-point number and store the result in dest. Note that dest may be the same PMC as self; in that case optimizations may be made.
- modulus
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)
- Divide the value of the self PMC by the value of a PMC, native integer, or native floating-point number and store the remainder in dest. Note that dest may be the same PMC as self; in that case optimizations may be made.
- cmodulus
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)
- Divide the value of the self PMC by the value of a PMC, native integer, or native floating-point number and store the remainder in dest. Note that dest may be the same PMC as self; in that case optimizations may be made.
- Note that
modulus
uses Knuth's "corrected mod" algorithm, as implemented in src/utils.c, while cmodulus
uses the C-style fmod function.
- neg
void neg(INTERP, PMC* self, PMC* dest)
- Negate the sign of self and store the result in dest. Note that self and dest may refer to the same PMC, in which case optimizations may be made.
- bitwise_or
void bitwise_or(INTERP, PMC* self, PMC* value, PMC* dest)
void bitwise_or_int(INTERP, PMC* self, INTVAL value, PMC* dest)
- Calculate the bitwise-OR of the value of the self PMC and the value of a PMC or native integer and store the result in dest. Note that dest may be the same PMC as self; in that case optimizations may be made. [Question: what happens when the self and value PMCs aren't integers?]
- bitwise_and
- bitwise_and_int
- bitwise_xor
- bitwise_xor_int
- bitwise_ors
- bitwise_ors_str
- bitwise_ands
- bitwise_ands_str
- bitwise_xors
- bitwise_xors_str
- bitwise_not
- bitwise_shl
- bitwise_shl_int
- bitwise_shr
- bitwise_shr_int
- is_equal
- is_same
- cmp
- cmp_num
- cmp_string
- logical_or
- logical_and
- logical_xor
- logical_not
- concatenate
- concatenate_native
- repeat
- repeat_int
- invoke
- fsh
- visit
- share
- can
- does
- isa
- add_method
- add_attribute
- get_attr
- set_attr
- add_parent
- add_role
- PMC* find_method(INTERP, PMC* self, STRING* method_name)
- Return a subroutine PMC for the passed method name. This subroutine PMC may be cached, so the method must return an equivalent sub PMC each time, or be capable of dealing with the returned sub PMCs being reused. [Why should it be cached? Can you turn off caching? What if you want to override find_method to generate methods on the fly?]
{{ Address the problem of high-level objects inheriting from low-level PMCs, and any structural changes to low-level PMCs that might require. }}
{{ PROPOSED:
High-level objects, as specified in PDD15, need to be able to inherit from PMCs. This is achieved through the combination of a PMCProxy
PMC and delegation.
For PDD15 objects, there is a corresponding instance of the Class
PMC. For a PMC, however, the class definition is written in C and compiled away. There needs to be something that can be placed in the parents list for a PDD15 class. That something is the PMCProxy
PMC. Like a PDD15 class, it is attached to the namespace that a PMC is attached to, provides introspection facilities and can sit in an inheritance hierarchy.
Therefore, subclassing a PMC looks, at a PIR level, like subclassing a high level class.
$P0 = get_class 'Hash'
$P1 = new 'Class'
addparent $P1, $P0 # The new class inherits from the Hash PMC
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 get a chunk of state that it can use as it wishes. Further to this, if multiple PMCs are inherited from, they may use the state in different ways. Users of Parrot at a PIR level should not have to care about such issues.
Therefore, when a PDD15 object is instantiated and it inherits from PMCs, an instance of each of the PMCs that it inherits from is also created. These are stored at the end of the object's attributes store.
When a method is called on an object whose class has PMC parents, the call is delegated up to each of the PMC parents, in MRO order. The invocant must be the appropriate PMC instance from the object's attribute store. For v-table calls, this is just a case of passing the correct thing. For other methods that are located by find_method
, a Bound_NCI
PMC is used to ensure that the method from the PMC is invoked with the correct instance, so it has access to the correct state.
When a PMC calls a method on itself, it may have been overridden in a high level class. Therefore dynamic dispatches of method calls need to be done with the vtable of the high level class, not the vtable of the PMC itself.
For PMCs that are instantiated and not overridden, the real_self
pointer in the PMC structure is a reference to the PMC instance itself. If, however, it is just acting to provide the state a PMC needs but is not the real instance, this pointer will point to the instance of the high level class (an instance of the Object
PMC). Method dispatches using DYNSELF
will always go through this mechanism.
Attribute access is, like method access, delegated upwards. Since attribute lookup is a vtable method, the down case is covered by the previous paragraph.
}}
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 a standard interface. It must implement the get_attr
and set_attr
vtable entries for any core attributes it expects to be accessible to subclasses.
Subclassing a low-level class from a high-level class makes an entry in the high-level class's list of parents. This entry is a proxy class object for the low-level PMC class that provides access to the low-level PMC's vtable (including the implementations of get_attr and set_attr), and defines the storage that the low-level object will need within the high-level object (this could be as simple as a single PMC attribute that is an instance of the low-level class).
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)
- Undef
- This is the generic no-value type. It has a numeric value of zero, a string value of empty string, and a boolean value of false. It will, on assignment, turn itself into a PMC of the source type, or if assigned a basic type will turn itself into one of the wrapper PMC types (detailed below) for the basic types.
- Integer
- The PMC wrapper for Parrot's low-level integer type. Always an integer, with other types auto-converted to an integer when stored into this PMC. The range and behaviour of the Integer PMC is identical to the platform low-level integer.
- The boolean value for an Integer is false if zero, otherwise true.
- Floating point, string, and bignum values assigned to an Integer PMC round to the nearest integer. Floats, or strings which resolve to numbers, cap at the platform maximum or minimum integer value.
- Integer PMCs take on a value of 1 if a boolean true is assigned, and a value of 0 if a boolean false is assigned.
- If an out-of-range value is assigned to an Integer PMC, the PMC will throw an exception if exact math is enabled.
- Float
- The PMC wrapper for Parrot's low-level floating-point type. Always a float, with other types autoconverted to a float when stored into this PMC.
- The boolean value for a Float is false if exactly zero, otherwise true.
- When converted to an integer, floats round to the closest integer, capping at the platform maximum or minimum integer value.
- When converting to a string, floats use the platform default snprintf format.
- String
- The PMC wrapper for Parrot's low-level string type. Always a simple string, with other types autoconverted to a string when stored into this PMC.
- The boolean value for a String is false if empty or the string '0' (a one character string holding a zero) otherwise true. This PMC autoconverts to an integer or float when its integer or float value is fetched.
- Boolean
- A true/false value. Returns 0 for false, 1 for true when fetched as an integer or float, empty string for false and '1' for true when fetched as a string.
- {{ IMPLEMENTATION NOTE: move the definitions of the Python constants "True" and "False" out of src/pmc/boolean.pmc. They belong in HLL-specific code, not in the core boolean type. }}
- BigInt
- An arbitrary precision integer.
- BigNum
- The PMC wrapper for Parrot's low-level BigNum type. {{ NOTE: this type doesn't seem to exist. }}
- Complex
- A complex number, consisting of a real part and an imaginary part. {{ NOTE: is this a complete and useful implementation of complex numbers? }}
- ParrotClass
- The PMC for Parrot's class. (Note that this may go away if we ultimately make all classes just objects)
- ParrotObject
- The PMC for Parrot's base object type.
- Ref
- The PMC that represents a reference to another PMC. Delegates all functions to the referred-to PMC.
- AggregateElementRef
- This PMC represents a reference to an element contained in an aggregate PMC type, such as an array or hash. It is initialized with the key being referenced and the aggregate PMC containing that key.
- Note that assigning to the reference PMC will be equivalent to a keyed set on the referenced aggregate PMC - that is, it modifies the element rather than doing a v-table call on the element itself. It is important to be aware of this when assigning a PMC through this reference; it is not the same behaviour as the Ref PMC.
- WeakRegisterRef
- This PMC represents a weak reference to a register. Should the reference live beyond the context containing the register that it references, any attempt to use the reference will throw an exception.
- A weak register reference can only be created by the
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.
- Random
- A singleton PMC that generates a random number. {{ NOTE: Why do we have this? }}
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.
- Array
- The base class for all array types (a statically sized array for any arbitrary type). New array types can be derived from the base Array. In user code it is recommended to use one of the specific array types below, rather than the base type.
- FixedBooleanArray
- A statically sized array which holds only Boolean values.
- ResizableBooleanArray
- A dynamically sized array which holds only Boolean values.
- FixedIntegerArray
- A statically sized array which holds only Integer values.
- ResizableIntegerArray
- A dynamically sized array which holds only Integer values.
- FixedFloatArray
- A statically sized array which holds only Float values.
- ResizableFloatArray
- A dynamically sized array which holds only Float values.
- FixedPMCArray
- A statically sized array which holds only PMC values.
- ResizablePMCArray
- A dynamically sized array which holds only PMC values.
- FixedStringArray
- A statically sized array which holds only String values.
- ResizableStringArray
- A dynamically sized array which holds only String values.
- Exception
- Hash
- A container with key-value semantics. The values are PMCs.
- Env
- Env is a singleton PMC class, that is there is only one Env PMC in any interpreter. This PMC gives access to the process' environment variables--reading from it returns the value of the named process environment variable, while writing to it sets the value of a process environment variable. For example, to retrieve the current value of TERM (the terminal type on most Unix systems):
new P1, .Env
set S1, P1['TERM']
- Note that an embedding system may override this behavior.
- Namespace
- OrderedHash
- AddrRegistry
- Simulates reference counting for dead-object detection and garbage collection.
- Sub
- Closure
- A closure: subroutine object plus captured lexical scope.
- Coroutine
- Continuation
- CSub
- Eval
- Exception_Handler
- MultiSub
- NCI
- A native call interface wrapper around a C function.
- Bound_NCI
- An internal NCI method call bound to a particular call instance. {{ NOTE: where are these used? }}
- Compiler
- A subroutine implementing a language compiler. (Derived from NCI.)
None.
None.
None.