Parrot Virtual Machine/Polymorphic Containers (PMCs)
Polymorphic Containers (PMCs)
editPolymorphic Containers (PMCs) -- which were previously known as 'Parrot Magic Cookies' -- are one of the fundamental data types of Parrot, and are one of the most powerful and flexible data types available. A PMC is very much like a class object, with data storage and associated class methods. PMCs include all aggregate data types including arrays, associative arrays (Hashes), Exceptions, Structures, and Objects. Parrot comes with a core set of PMCs, but new PMCs can be added for use with specific programs or languages.
PMCs are written in a C-like language that we will call "PMC Script" and compiled. PMCs can be built-in to Parrot directly, or they can be written separately and loaded in later. PMCs which are loaded at runtime are called "dynamic PMCs", or DYNPMCs for short.
Writing PMCs in C
editPMC definitions are written in a C-like language that is translated to C code using a special PMC compiler program called pmc2c.pl
. Once converted to C code, the PMCs are included in the Parrot build process.
The PMC Compiler
editThe PMC Compiler, pmc2c.pl
has a number of tasks to perform. It converts the PMC into legal C syntax, inserts the function names in the appropriate tables, and exports information about the PMC and its methods to the rest of the Parrot system.
PMC Script
editThe script language used to write a PMC is based on C. In fact, it's mostly C with a few additional keywords and constructs. The PMC compiler converts PMC files into C code for compilation. All standard ANSI C 89 code is acceptable for use in PMC files. Here we will list some of the additions.
PMC Class Definition
editAll the methods and vtables of the PMC must be enclosed in a PMC class declaration:
pmclass NAME { }
In addition to just giving the name of the PMC, you can specify single-inheritance too:
pmclass NAME is SUPERNAME { }
Where SUPERNAME is the name of the parent PMC class. In your PMC vtable methods you can use the SUPER keyword to access the vtable methods of the parent class.
You can also allocate an additional storage area called a PMC_EXT using the needs_ext keyword. PMC_EXT is an additional structure that can be allocated to help with special operations, such as sharing between multiple interpreters. If the PMC is not automatically thread safe, you should add a PMC_EXT.
Specifier | Meaning |
---|---|
is SUPERNAME | Specifies the parent class, if any |
need_ext | Needs a PMC_EXT for special handling |
abstract | The class is abstract and cannot be instantiated |
no_init | The PMC does not have an init vtable method for Parrot to call. Normally, Parrot calls the init method when the PMC is first created. if you don't need that, use no_init .
|
provides INTERFACE | INTERFACE is one of the standard interfaces, and the PMC can be used as if it were an object of that type. The interfaces are "array", "hash" |
Helper Functions
editLike ordinary C, you can define addtional functions to help with your calculations. These functions should be written in ordinary C (without any special keywords or values) and should be defined outside of the C<pmclass> definition.
Defining PMC Attributes
editPMCs can be given a custom set of data field attributes using the ATTR
keyword. ATTR allows the PMC to be extended to contain custom data structures that are automatically managed by Parrot's memory subsystem. Here's an example:
pmclass Foo { ATTR INTVAL bar; ATTR PMC baz; ... }
The attributes are stored in a custom data structure that can be accessed using a macro with the same name as the PMC, but all upper-case:
Parrot_Foo_attributes * attrs = PARROT_FOO(SELF); attrs->bar = 7; /* it's an INTVAL */ attrs->baz = pmc_new( ... ) /* It's a PMC */
Notice how the type name of the attributes structure is Parrot_
, followed by the name of the PMC with the same capitalization as is used in the pmclass
definition, followed by _attributes
. The macro to return this structure is PARROT_
followed by the name of the PMC in all caps.
Writing and Loading DYNPMCs
editVTABLEs and Methods
editThe VTABLE interface, and the specific functions in a vtable are subject to change before the Parrot 1.0 release.
PMCs can supply definitions for any number of VTABLE interfaces. Any interfaces not defined will fall back to a default implementation which throws an error. VTABLE interfaces must all follow a pre-defined format, and attempting to define a VTABLE interface that is not one of the normal interfaces or does not use the same parameter list and return value as the normal interfaces will throw an error.
The parameters for all VTABLE and METHOD declarations may be either INTVAL, FLOATVAL, STRING, or PMC, as these are the only values which can be passed from PIR code. VTABLE Interfaces are defined with the VTABLE keyword, and Methods on the PMC can be defined with the METHOD keyword.
VTABLES
editAll PMCs have a standard API, an interface that they share in common with all other PMCs. This standard interface is called a VTABLE. A VTABLE is a list of about 150 standard functions, called "VTABLE Interfaces" that implement basic, common, behavior for PMCs. All PMCs implement all these interfaces, although if one is not explicitly provided it can inherit from a parent PMC class, or it can default to throwing an exception.
VTABLE methods can be defined in one of two ways, in the .pmc
using the C-like PMC language, or in PIR using the :vtable
function qualifier. VTABLEs correspond to some basic operations that can be performed on any object, such as arithmetic, class operations, casting operations (to INTVAL, FLOATVAL, STRING, or PMC), and other common operations. Regardless of how the VTABLE method is defined, they must have very specific names.
Writing VTABLE Interfaces
editVTABLE functions all have fixed names and parameter lists. When implementing a new VTABLE method, you must strictly conform to this, or there could be several compilation errors and warnings. For a list of all vtable methods and their expected function signatures, you can check out the header file /include/parrot/vtables.h
.
Inside a VTABLE method there are several available keywords that can be used:
- SELF
- the current PMC
- INTERP
- the parrot interpreter
- SUPER
- The parent PMC class.
You can also reference other methods or vtable methods of the current PMC using a standard dot notation such as:
SELF.VTABLE_OR_METHOD_NAME()
If you want to default all or part of your processing to the super class (if you have a superclass), you can use the SUPER() function to do that. Any vtable method that you do not implement will be automatically defaulted to the super class (if any) or to te default parent class.
Methods
editIn addition to VTABLEs, a PMC may supply a series of custom interface functions called methods to supply additional functionality. Notice that methods are not integrated into the PIR operators or PASM opcodes in the same way that VTABLE methods are. Methods can be written in the C-like PMC script for individual PMCs, or they can be written in PIR for user-defined PMC subclasses.
Invoking Methods
editOnce a method has been defined, it can be accessed in a PMC file using the PCCINVOKE
command.
VTABLE List
editA complete list of all vtable methods is located in the appendix.
Resources
edit- Built-In PMC Appendix
- http://www.parrotcode.org/docs/pdd/pdd04_datatypes.html
- http://www.parrotcode.org/docs/pdd/pdd17_pmc.html
- http://www.parrotcode.org/docs/pmc2c.html
- http://www.parrotcode.org/docs/pmc.html