# -*- cperl -*- =head1 Writing a PMC PMC classes are stored in the C directory on the root of the parrot tarball. They are codified in a pseudo-C file with extension C<.pmc>. Later, this file will be converted in a pure C file. To start writing a Parrot Magic Cookie use the C script. It works supplying the PMC name: perl genclass.pl pmc-name > pmc-name.pmc This file contains the basic includes you should need, and a stub class with methods you should write. =head2 PMC Structure On the C created you can use several variables without declaring them: =over 4 =item SELF This variable refers to the pmc object. It's type is C in case you want to know. The basic structure for a PMC object is: =over 4 =item vtable This structure hold all dispatch information for a PMC object. It includes references for each function you will declare in C. Check C section. =item flags This item holds information about your object. Check the flags section bellow. Check C section. =item data This variable is a pointer to your object data. Some of these pointer properties are set using the C item. =item cache C is intended to just be B to commonly-accessed data, B pointers to completely different data. =back =item INTERP When parrot is running, this variable refers to the parrot interpreter. It contains various information. It's type is C. =back =head2 PMC Methods =over 4 =item Initialization void init() # example: new P0, .pmc This method will be called whenever the PMC object is created. Use it for object initializations. void init_pmc(PMC* initializer) void morph(INTVAL type) Sometimes, a type-cast may be necessary. This method will be called with the type your type should be converted to. PMC* mark(PMC* tail) void destroy() This method should be used for PMC object destruction. Sometimes it can be omitted. =item Types INTVAL type() Query method which should return the PMC object type. INTVAL type_keyed(KEY* key) INTVAL type_keyed_int(INTVAL* key) UINTVAL subtype(INTVAL type) UINTVAL subtype_keyed(KEY* key, INTVAL type) UINTVAL subtype_keyed_int(INTVAL* key, INTVAL type) =item Name... STRING* name() STRING* name_keyed(KEY* key) STRING* name_keyed_int(INTVAL* key) =item Cloning PMC* clone() Whenever your object needs to be cloned, this method will be called. Use it to create and return a copy of your PMC. PMC* clone_keyed(KEY* key) PMC* clone_keyed_int(INTVAL* key) =item Finding... PMC* find_method(STRING* method_name) PMC* find_method_keyed(KEY* key, STRING* method_name) PMC* find_method_keyed_int(INTVAL* key, STRING* method_name) =item Getting values INTVAL get_integer() INTVAL get_integer_keyed(KEY* key) INTVAL get_integer_keyed_int(INTVAL* key) These methods should return integers. What they return depends on the PMC being implemented. For example, the simple C is used on arrays to get the array size. Keyed versions are used whenever the code tryies to access some element of the object using a key. For arrays, keys are the position index. For hashes, we use them as keys. For your PMC it can returns what you think it should. FLOATVAL get_number() FLOATVAL get_number_keyed(KEY* key) FLOATVAL get_number_keyed_int(INTVAL* key) Same accessing methods returning number (C registers) values; BIGNUM* get_bignum() BIGNUM* get_bignum_keyed(KEY* key) BIGNUM* get_bignum_keyed_int(INTVAL* key) Same accessing methods returning big numbers values; STRING* get_string() STRING* get_string_keyed(KEY* key) STRING* get_string_keyed_int(INTVAL* key) Same accessing methods returning strings (C registers) values; PMC* get_pmc() PMC* get_pmc_keyed(KEY* key) PMC* get_pmc_keyed_int(INTVAL* key) Same accessing methods returning PMC (C registers) objects; INTVAL get_bool() INTVAL get_bool_keyed(KEY* key) INTVAL get_bool_keyed_int(INTVAL* key) Parrot doesn't have a boolean type, but sometimes you can use a PMC in a conditional statement, needing to get a boolean value from it. In the case of arrays, for example, the C can return true if the array has elements, or false otherwise. INTVAL elements() INTVAL elements_keyed(KEY* key) INTVAL elements_keyed_int(INTVAL* key) INTVAL is_same(PMC* value) INTVAL is_same_keyed(KEY* key, PMC* value, KEY* value_key) INTVAL is_same_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key) =item Setting values void set_integer(PMC* value) void set_integer_native(INTVAL value) # example: set P0, I0 void set_integer_same(PMC* value) void set_integer_keyed(KEY* key, INTVAL value) void set_integer_keyed_int(INTVAL* key, INTVAL value) void set_number(PMC* value) void set_number_native(FLOATVAL value) # example: set P0, N0 void set_number_same(PMC* value) void set_number_keyed(KEY* key, FLOATVAL value) void set_number_keyed_int(INTVAL* key, FLOATVAL value) void set_bignum(PMC* value) void set_bignum_native(BIGNUM* value) void set_bignum_same(PMC* value) void set_bignum_keyed(KEY* key, BIGNUM* value) void set_bignum_keyed_int(INTVAL* key, BIGNUM* value) void set_string(PMC* value) void set_string_native(STRING* value) # example: set P0, S0 void set_string_unicode(STRING* value) void set_string_other(STRING* value) void set_string_same(PMC* value) void set_string_keyed(KEY* key, STRING* value) void set_string_keyed_int(INTVAL* key, STRING* value) void set_pmc(PMC* value) # example: set P0, P1 void set_pmc_keyed(KEY* key, PMC* value, KEY* value_key) void set_pmc_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key) void set_same(PMC* value) void set_same_keyed(KEY* key, PMC* value, KEY* value_key) void set_same_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key) =item Stack operations INTVAL pop_integer() INTVAL pop_integer_keyed(KEY* key) INTVAL pop_integer_keyed_int(INTVAL* key) FLOATVAL pop_float() FLOATVAL pop_float_keyed(KEY* key) FLOATVAL pop_float_keyed_int(INTVAL* key) BIGNUM* pop_bignum() BIGNUM* pop_bignum_keyed(KEY* key) BIGNUM* pop_bignum_keyed_int(INTVAL* key) STRING* pop_string() STRING* pop_string_keyed(KEY* key) STRING* pop_string_keyed_int(INTVAL* key) PMC* pop_pmc() PMC* pop_pmc_keyed(KEY* key) PMC* pop_pmc_keyed_int(INTVAL* key) void push_integer(INTVAL value) void push_integer_keyed(KEY* key, INTVAL value) void push_integer_keyed_int(INTVAL* key, INTVAL value) void push_float(FLOATVAL value) void push_float_keyed(KEY* key, FLOATVAL value) void push_float_keyed_int(INTVAL* key, FLOATVAL value) void push_bignum(BIGNUM* value) void push_bignum_keyed(KEY* key, BIGNUM* value) void push_bignum_keyed_int(INTVAL* key, BIGNUM* value) void push_string(STRING* value) void push_string_keyed(KEY* key, STRING* value) void push_string_keyed_int(INTVAL* key, STRING* value) void push_pmc(PMC* value) void push_pmc_keyed(KEY* key, PMC* value, KEY* value_key) void push_pmc_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key) INTVAL shift_integer() INTVAL shift_integer_keyed(KEY* key) INTVAL shift_integer_keyed_int(INTVAL* key) FLOATVAL shift_float() FLOATVAL shift_float_keyed(KEY* key) FLOATVAL shift_float_keyed_int(INTVAL* key) BIGNUM* shift_bignum() BIGNUM* shift_bignum_keyed(KEY* key) BIGNUM* shift_bignum_keyed_int(INTVAL* key) STRING* shift_string() STRING* shift_string_keyed(KEY* key) STRING* shift_string_keyed_int(INTVAL* key) PMC* shift_pmc() PMC* shift_pmc_keyed(KEY* key) PMC* shift_pmc_keyed_int(INTVAL* key) void unshift_integer(INTVAL value) void unshift_integer_keyed(KEY* key, INTVAL value) void unshift_integer_keyed_int(INTVAL* key, INTVAL value) void unshift_float(FLOATVAL value) void unshift_float_keyed(KEY* key, FLOATVAL value) void unshift_float_keyed_int(INTVAL* key, FLOATVAL value) void unshift_bignum(BIGNUM* value) void unshift_bignum_keyed(KEY* key, BIGNUM* value) void unshift_bignum_keyed_int(INTVAL* key, BIGNUM* value) void unshift_string(STRING* value) void unshift_string_keyed(KEY* key, STRING* value) void unshift_string_keyed_int(INTVAL* key, STRING* value) void unshift_pmc(PMC* value) void unshift_pmc_keyed(KEY* key, PMC* value, KEY* value_key) void unshift_pmc_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key) =item Arithmetic void add(PMC* value, PMC* dest) void add_int(INTVAL value, PMC* dest) void add_bignum(BIGNUM* value, PMC* dest) void add_float(FLOATVAL value, PMC* dest) void add_same(PMC* value, PMC* dest) These methods are used to add something with the current PMC object. All they receive as first element the value you should add (another PMC, an integer, big number, number (float)) and should put the value on the C PMC. The C is used whenever we already know that PMC we are adding have the same type as our own PMC; void add_keyed(KEY* key, PMC* value, KEY* value_key, PMC* dest, KEY* dest_key) void add_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key, PMC* dest, INTVAL* dest_key) void subtract(PMC* value, PMC* dest) void subtract_int(INTVAL value, PMC* dest) void subtract_bignum(BIGNUM* value, PMC* dest) void subtract_float(FLOATVAL value, PMC* dest) void subtract_same(PMC* value, PMC* dest) Same as C, for subtraction; void subtract_keyed(KEY* key, PMC* value, KEY* value_key, PMC* dest, KEY* dest_key) void subtract_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key, PMC* dest, INTVAL* dest_key) void multiply(PMC* value, PMC* dest) void multiply_int(INTVAL value, PMC* dest) void multiply_bignum(BIGNUM* value, PMC* dest) void multiply_float(FLOATVAL value, PMC* dest) void multiply_same(PMC* value, PMC* dest) Same as C, for multiplication; void multiply_keyed(KEY* key, PMC* value, KEY* value_key, PMC* dest, KEY* dest_key) void multiply_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key, PMC* dest, INTVAL* dest_key) void divide(PMC* value, PMC* dest) void divide_int(INTVAL value, PMC* dest) void divide_bignum(BIGNUM* value, PMC* dest) void divide_float(FLOATVAL value, PMC* dest) void divide_same(PMC* value, PMC* dest) Same as C, for division; void divide_keyed(KEY* key, PMC* value, KEY* value_key, PMC* dest, KEY* dest_key) void divide_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key, PMC* dest, INTVAL* dest_key) void modulus(PMC* value, PMC* dest) void modulus_int(INTVAL value, PMC* dest) void modulus_bignum(BIGNUM* value, PMC* dest) void modulus_float(FLOATVAL value, PMC* dest) void modulus_same(PMC* value, PMC* dest) void modulus_keyed(KEY* key, PMC* value, KEY* value_key, PMC* dest, KEY* dest_key) void modulus_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key, PMC* dest, INTVAL* dest_key) void neg(PMC* dest) void neg_keyed(KEY* key, PMC* dest, KEY* dest_key) void neg_keyed_int(INTVAL* key, PMC* dest, INTVAL* dest_key) =item Bitwise logic void bitwise_or(PMC* value, PMC* dest) void bitwise_or_int(INTVAL value, PMC* dest) void bitwise_or_same(PMC* value, PMC* dest) void bitwise_or_keyed(KEY* key, PMC* value, KEY* value_key, PMC* dest, KEY* dest_key) void bitwise_or_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key, PMC* dest, INTVAL* dest_key) void bitwise_and(PMC* value, PMC* dest) void bitwise_and_int(INTVAL value, PMC* dest) void bitwise_and_same(PMC* value, PMC* dest) void bitwise_and_keyed(KEY* key, PMC* value, KEY* value_key, PMC* dest, KEY* dest_key) void bitwise_and_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key, PMC* dest, INTVAL* dest_key) void bitwise_xor(PMC* value, PMC* dest) void bitwise_xor_int(INTVAL value, PMC* dest) void bitwise_xor_same(PMC* value, PMC* dest) void bitwise_xor_keyed(KEY* key, PMC* value, KEY* value_key, PMC* dest, KEY* dest_key) void bitwise_xor_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key, PMC* dest, INTVAL* dest_key) void bitwise_not(PMC* dest) void bitwise_not_keyed(KEY* key, PMC* dest, KEY* dest_key) void bitwise_not_keyed_int(INTVAL* key, PMC* dest, INTVAL* dest_key) void bitwise_shl(PMC* value, PMC* dest) void bitwise_shl_int(INTVAL value, PMC* dest) void bitwise_shl_same(PMC* value, PMC* dest) void bitwise_shl_keyed(KEY* key, PMC* value, KEY* value_key, PMC* dest, KEY* dest_key) void bitwise_shl_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key, PMC* dest, INTVAL* dest_key) void bitwise_shr(PMC* value, PMC* dest) void bitwise_shr_int(INTVAL value, PMC* dest) void bitwise_shr_same(PMC* value, PMC* dest) void bitwise_shr_keyed(KEY* key, PMC* value, KEY* value_key, PMC* dest, KEY* dest_key) void bitwise_shr_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key, PMC* dest, INTVAL* dest_key) =item Concatenation void concatenate(PMC* value, PMC* dest) void concatenate_native(STRING* value, PMC* dest) void concatenate_unicode(STRING* value, PMC* dest) void concatenate_other(STRING* value, PMC* dest) void concatenate_same(PMC* value, PMC* dest) void concatenate_keyed(KEY* key, PMC* value, KEY* value_key, PMC* dest, KEY* dest_key) void concatenate_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key, PMC* dest, INTVAL* dest_key) =item Comparisons INTVAL is_equal(PMC* value) INTVAL is_equal_keyed(KEY* key, PMC* value, KEY* value_key) INTVAL is_equal_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key) INTVAL cmp(PMC* value) INTVAL cmp_keyed(KEY* key, PMC* value, KEY* value_key) INTVAL cmp_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key) INTVAL cmp_num(PMC* value) INTVAL cmp_num_keyed(KEY* key, PMC* value, KEY* value_key) INTVAL cmp_num_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key) INTVAL cmp_string(PMC* value) INTVAL cmp_string_keyed(KEY* key, PMC* value, KEY* value_key) INTVAL cmp_string_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key) =item Logical Operations void logical_or(PMC* value, PMC* dest) void logical_or_keyed(KEY* key, PMC* value, KEY* value_key, PMC* dest, KEY* dest_key) void logical_or_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key, PMC* dest, INTVAL* dest_key) void logical_and(PMC* value, PMC* dest) void logical_and_keyed(KEY* key, PMC* value, KEY* value_key, PMC* dest, KEY* dest_key) void logical_and_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key, PMC* dest, INTVAL* dest_key) void logical_xor(PMC* value, PMC* dest) void logical_xor_keyed(KEY* key, PMC* value, KEY* value_key, PMC* dest, KEY* dest_key) void logical_xor_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key, PMC* dest, INTVAL* dest_key) void logical_not(PMC* dest) void logical_not_keyed(KEY* key, PMC* dest, KEY* dest_key) void logical_not_keyed_int(INTVAL* key, PMC* dest, INTVAL* dest_key) =item Repeat void repeat(PMC* value, PMC* dest) void repeat_int(INTVAL value, PMC* dest) void repeat_keyed(KEY* key, PMC* value, KEY* value_key, PMC* dest, KEY* dest_key) void repeat_keyed_int(INTVAL* key, PMC* value, INTVAL* value_key, PMC* dest, INTVAL* dest_key) void repeat_int_keyed(KEY* key, INTVAL value, PMC* dest, KEY* dest_key) void repeat_int_keyed_int(INTVAL* key, INTVAL value, PMC* dest, INTVAL* dest_key) =item Incrementing/Decrementing void increment() void increment_keyed(KEY* key) void increment_keyed_int(INTVAL* key) void decrement() void decrement_keyed(KEY* key) void decrement_keyed_int(INTVAL* key) INTVAL exists_keyed(KEY* key) INTVAL exists_keyed_int(INTVAL* key) INTVAL defined() INTVAL defined_keyed(KEY* key) INTVAL defined_keyed_int(INTVAL* key) void delete_keyed(KEY* key) void delete_keyed_int(INTVAL* key) KEY* nextkey_keyed(KEY* key) KEY* nextkey_keyed_int(INTVAL* key) void substr(INTVAL offset, INTVAL length, PMC* dest) void substr_keyed(KEY* key, INTVAL offset, INTVAL length, PMC* dest, KEY* dest_key) void substr_keyed_int(INTVAL* key, INTVAL offset, INTVAL length, PMC* dest, INTVAL* dest_key) STRING* substr_str(INTVAL offset, INTVAL length) STRING* substr_str_keyed(KEY* key, INTVAL offset, INTVAL length) STRING* substr_str_keyed_int(INTVAL* key, INTVAL offset, INTVAL length) =back =head2 PMC flags =over 4 =item C Set this flag whenever your PMC class has a destroy method which must be called when destroying the object; =item C This flag should be set if yours PMC holds multiple PMCs, like hashes, arrays, lists,... =item C This flag should be set if your PMC data pointer points to some buffer memory, like a string or a buffer pointer; =item C If your PMC data pointer points to a PMC; =item C If your PMC class uses a private Garbage Collector function, set this flag; =item C Set to true if the PMC has a custom mark routine; =back =cut