Team LiB   Previous Section   Next Section

6.3 Working with PMCs

In most of the examples we've shown so far, PMCs just duplicate the functionality of integers, numbers, and strings. They wouldn't be terribly useful if that's all they did, though. PMCs offer several advanced features, each with its own set of operations.

6.3.1 Aggregates

PMCs can define complex types that hold multiple values. These are commonly called "aggregates." The most important feature added for aggregates is keyed access. Elements within an aggregate PMC can be stored and retrieved by a numeric or string key. PASM also offers a full set of operations for manipulating aggregate data types.

Since PASM is intended to implement Perl, the two most fully featured aggregates already in operation are arrays and hashes. Any aggregate defined for any language could take advantage of the features described here.

6.3.1.1 Arrays

The PerlArray PMC is an ordered aggregate with integer keys. The syntax for keyed access to a PMC puts the key in square brackets after the register name:

new P0, .PerlArray  # obtain a new array object

set P0, 2           # set its length 

set P0[0], 10       # set first element to 10

set P0[1], I31      # set second element to I31

set I0, P0[0]       # get the first element

set I1, P0          # get array length

A key on the destination register of a set operation sets a value for that key in the aggregate. A key on the source register of a set returns the value for that key. If you set P0 without a key, you set the length of the array, not one of its values.[7] And if you set an integer to the value of a PerlArray, you get the length of the array.

[7] PerlArray is an autoextending array, so you never need to set its length. Other array types may require the length to be set explicitly.

Some other useful instructions for working with arrays are push, pop, shift, and unshift (you'll find them later in Section 8).

6.3.1.2 Hashes

The PerlHash PMC is an unordered aggregate with string keys:

new P1, .PerlHash   # generate a new hash object

set P1["key"], 10   # set key and value

set I0, P1["key"]   # obtain value for key

set I1, P1          # number of entries in hash

The exists opcode tests whether a keyed value exists in an aggregate. It returns 1 if it finds the key in the aggregate, and returns 0 if it doesn't. It doesn't care if the value itself is true or false, only that the key has been set:

new P0, .PerlArray

set P0[0], 0

exists I0, P0[0]  # does a value exist at key 0?

print I0          # prints 1

print "\n"

end

The delete opcode is also useful for working with hashes: it removes a key/value pair.

6.3.1.3 Data structures

Arrays and hashes can hold any data type, including other aggregates. Accessing elements deep within nested data structures is a common operation, so PASM provides a way to do it in a single instruction. Complex keys specify a series of nested data structures, with each individual key separated by a semicolon:

new P0, .PerlHash

new P1, .PerlArray

set P1[2], 42

set P0["answer"], P1

set I1, 2

set I0, P0["answer";I1]        # $i = %hash{"answer"}[2]

print I0

print "\n"

end

This example builds up a data structure of a hash containing an array. The complex key P0["answer";I1] retrieves an element of the array within the hash. You can also set a value using a complex key:

set P0["answer";0], 5   # %hash{"answer"}[0] = 5

The individual keys are integers or strings, or registers with integer or string values.

6.3.2 PMC Assignment

We mentioned before that set on two PMCs simply aliases them both to the same object, and that clone creates a complete duplicate object. But if you just want to assign the value of one PMC to another PMC, you need the assign opcode:

new P0, .PerlInt

new P1, .PerlInt

set P0, 42

set P2, P0

assign P1, P0     # note: P1 has to exist already

inc P0

print P0          # prints 43

print "\n"

print P1          # prints 42

print "\n"

print P2          # prints 43

print "\n"

end

This example creates two PerlInt PMCs: P0 and P1. It gives P0 a value of 42. It then uses set to give the same value to P2, but uses assign to give the value to P1. When P0 is incremented, P2 also changes, but P1 doesn't. The destination register for assign must have an existing object of the right type in it, since assign doesn't create a new object (as with clone) or reuse the source object (as with set).

6.3.3 Properties

PMCs can have additional values attached to them as "properties" of the PMC. What these properties do is entirely up to the language being implemented. Perl 6 uses them to store extra information about a variable: whether it's a constant, if it should always be interpreted as a true value, etc.

The setprop opcode sets the value of a named property on a PMC. It takes three arguments: the PMC to be set with a property, the name of the property, and a PMC containing the value of the property. The getprop opcode returns the value of a property. It also takes three arguments: the PMC to store the property's value, the name of the property, and the PMC to have a property value retrieved:

new P0, .PerlString

set P0, "Zaphod"

new P1, .PerlInt

set P1, 1

setprop P0, "constant", P1        # set a property on P0

getprop P3, "constant", P0        # retrieve a property on P0

print P3                          # prints 1

print "\n"

end

This example creates a PerlString object in P0, and a PerlInt object with the value 1 in P1. setprop sets a property named "constant" on the object in P0 and gives the property the value in P1.[8] getprop retrieves the value of the property "constant" on P0 and stores it in P3.

[8] The "constant" property is ignored by PASM, but is significant to the Perl 6 code running on top of it.

Properties are kept in a separate hash for each PMC. Property values are always PMCs, but only references to the actual PMCs. Trying to fetch the value of a property that doesn't exist returns a PerlUndef.

delprop deletes a property from a PMC. You can also return a complete hash of all properties on a PMC with prophash.

prophash P0, P1         # set P0 to the property hash of P1

delprop P1, "constant"  # delete property
    Team LiB   Previous Section   Next Section