=head1 TITLE Виртуальные таблицы Паррота =head1 Реализация типов переменных при помощи Виртуальных таблиц Это руководство по созданию ващих собственных PMC (Parrot Magic Cookie) классов. Оно рассказывает, что необходимо нописать надлежащим образом, что бы добавить новые переменный типы переменных в Паррот. =head2 Обзор Внутренности Паррот интерпритатора, в упошенной схеме (или, если ты хочешь меннее принебрежительно, скептически), - это лабиринт поведения типов переменных. Стандартный пример - различия между скалярами Перла и скалярами Питона. В Перле, если ты имеешь $a = "a9"; $a++; ты получишь, что C<$a> равно C. Это благодаря магии оперетора инкрементирования в Перле. В Питоне, с другой стороны, ты получишь ошибку выполнения. =over 3 =item * Чтобы быть совершенно честными, это немного некоректный пример, так как маловероятно что будет отдельный "Python scalar" PMC класс. Компилятор Питона мог бы догадатся что C является C, а C - это C. Но загвоздка остатется - инкрементирование C очень отличается от инкрементирования C =back Такое поведение является функцией PMC "типа", естественно рассматиривать различные типы PMC как классы в объектно-ориентированных системах. Паррот интерпритатор вызывает методы индивидуальных PMC объектов чтобы манипулировать ими. Так что привер, приведенный выше, выгледял бы подобно этому: =over 3 =item 1. Создание нового PMC класса PerlScalar. =item 2. Вызов метода, устанавливающего его строковое значение в C<"a9">. =item 3. Вызов метода, чтобы сказать ему инкрементировать себя. =back И если ты заменишь PerlScalar на PythonString, ты получишь различное поведение, но для основных внутренностей интерпритатора, инструкции будет такими же самыми. PMC являются абстрактными виртуальными классами; Интрепритатор вызывает методы, PMC объект делает требуемый вещи, и интепритатор не заботится особенно, что это требуемая вешь случается чтобы быть. Hence, добавление новых типов данный в Паррот -это вопрос об обеспечении методов, ктороые выполняют ожидаемые от типов данных действия. Давайте взлянем, как сделать это. =head2 Поехали Если ты добавляешь тип данных в ядро Паррота, (и ты сверяешься с Dan и/или Simon, что вы, как предполагается, делаете) ты должен создать файл в F подкаталоге; это там встроенные PMC классы живут. (И хороший источник примеров, чтобы разграбить, даже если Вы не пишете основной тип данных.) You should almost always start by running F found in the F subdirectory to generate a skeleton for the class. Let's generate a number type for the beautifully non-existant Fooby language: perl -I../lib genclass.pl FoobyNumber > foobynumber.pmc This will produce a skeleton C file (to be preprocessed by the F program) with stubs for all the methods you need to fill in. The function C allows you to set up anything you need to set up. Now you'll have to do something a little different depending on whether you're writing a built-in class or an extension class. If you're writing a built-in class, then you'll see a reference to C in the C function. For built-in classes, this is automatically defined in F when you run Configure.pl. If you're not writing a built-in class, you need to indicate this by using the 'extension' keyword after the 'pmclass YOURCLASS' declaration in classes/YOURCLASS.pmc. Then, change the type of the C function to return C, and then return C instead of assigning to the C array. To finish up adding a built-in class: =over 4 =item 1. Add classes/YOURCLASS.pmc to MANIFEST. =item 2. Rerun Configure.pl to add your new PMC to the set of built-in PMCs. =back =head2 What You Can and Cannot Do The usual way to continue from the F-generated skeleton is to define a structure that will hook onto the C, if your data type needs to use that, and then also define some user-defined flags. Flags are accessed by C<< pmc->flags >>. Most of the bits in the flag word are reserved for use by parrot itself, but a number of them have been assigned for general use by individual classes. These are referred to as C .. C. (The '7' may change during the early development of parrot, but will become pretty fixed at some point.) Normally, you will want to alias these generic bit names to something more meaningful within your class: enum { Foobynumber_is_bignum = Pobj_private0_FLAG, Foobynumber_is_bigint = Pobj_private1_FLAG, .... }; You're quite at liberty to declare these in a separate header file, but I find it more convenient to keep everything together in F. You may also use the C union in the PMC structure to remove some extraneous dereferences in your code if that would help. =head2 Multimethods One slightly (potentially) tricky element of implementing vtables is that several of the vtable functions have variant forms depending on the type of data that they're being called with. For instance, the C method has multiple forms; the default C means that you are being called with a PMC, and you should probably use the C method of the PMC to find its integer value; C means you're being passed an C. The final form is slightly special; if the interpreter calls C, you know that the PMC that you are being passed is of the same type as you. Hence, you can break the class abstraction to save a couple of dereferences - if you want to. Similar shortcuts exist for strings, (C and C) and floating point numbers. =head2 Methods you need to implement The master list of vtable methods can be found in F in the root directory of the Parrot source; since that's not exactly verbose, here's a better description of the methods that you need to implement: =over 3 =item C Return the enumeration value of your class. =item C Return a string containing your class name. =item C Do any data set-up you need to do. =item C True if the passed-in PMC has the same B as you. For instance, a Perl integer and a Python integer could have the same value, but could not be the same thing as defined by C. =back =head2 Methods, you might need, depending on your class =over 3 =item C Copy your data and state into the passed-in destination PMC. =item C Turn yourself into the specified type. =item C Do any data shut-down and finalization you need to do. To have this method called, you must set the C. =item C Return an integer representation of yourself. =item C Return a floating-point representation of yourself. =item C Return a string representation of yourself (a STRING* object), this should be a B of whatever string you are holding, not just a pointer to your own string so that anything that calls this method can happily modify this value without making a mess of your guts. =item C Return a boolean representation of yourself. =item C Return your private data as a raw pointer. =item C True if the passed-in PMC refers to exactly the same B as you. (Contrast C) =item C Set yourself to the passed-in integer value. This is an integer multimethod. =item C Set yourself to the passed-in float value. This is an floating-point multimethod. =item C Set yourself to the passed-in string. This is a string multimethod. =item C Set your private data to the raw pointer passed in. This will only be used in exceptional circumstances. =item C Fetch the number part of C and add your numeric value to it, storing the result in C. (Probably by calling its C or C method) This is a numeric multimethod. =item C Fetch the number part of C and subtract your numeric value from it, storing the result in C. (Probably by calling its C or C method) This is a numeric multimethod. =item C =item C =item C You get the picture. =item C Fetch the string part of C and catenate it to yourself, storing the result in C. (Probably by calling its C method) This is a string multimethod. =item C =item C Perform the given short-circuiting logical operations between your boolean value and the value passed in, storing the result in C. =item C Set yourself to be a logical negation of the value passed in. =item C Execute the given regular expression on C and store the result. =item C Repeat your string representation C times and store the result in C. =back If any method doesn't fit into your class, just don't implement it and don't provide an empty function body. The default class, which all classes inherit from, will through an exception, if this method would be called. If your class is a modification of an existing class, you may wish to use inheritance. At the beginning of your vtable specification in classes/YOURCLASS.pmc, add the C phrase. For example: pmclass PackedArray extends Array { ... See the POD documentation in classes/pmc2c.pl for a list of useful keywords that you may use in the .pmc file. (Run C to view the POD.)