Team LiB   Previous Section   Next Section

6.6 Lexicals and Globals

So far, we've been treating Parrot registers like the variables of a high-level language. This is fine, as far as it goes, but it isn't the full picture. The dynamic nature and introspective features of languages like Perl make it desirable to manipulate variables by name, instead of just by register or stack location. These languages also have global variables, which are visible throughout the entire program. Storing a global variable in a register would either tie up that register for the life of the program or require unwieldy manipulation of the user stack.

Parrot provides structures for storing both global and lexically scoped named variables. Lexical and global variables must be PMC values. PASM provides instructions for storing and retrieving variables from these structures so the PASM opcodes can operate on their values.

6.6.1 Globals

Global variables are stored in a PerlHash, so every variable name must be unique. PASM has two opcodes for globals, store_global and find_global:

new P10, .PerlInt
set P10, 42
store_global "$foo", P10
# ...
find_global P0, "$foo"
print P0                        # prints 42
end

The first two statements create a PerlInt in the PMC register P10 and give it the value 42.

The store_global opcode only stores a reference to the object. If we add an increment statement:

inc P10

after the store_global it increments the stored global printing 43. If that's not what you want, you can clone the PMC before you store it. It does have advantages, though. If you retrieve a stored global into a register and modify it as follows:

find_global P0, "varname"
inc P0

the value of the stored global is directly modified, so you don't need to call store_global again.

6.6.2 Lexicals

Lexical variables are stored in a lexical scratchpad. There's one pad for each lexical scope. Every pad has both a hash and an array, so elements can be stored either by name or by numeric index. Parrot stores the scratchpads for nested lexical scopes in a pad stack.

6.6.2.1 Basic instructions

The instructions for manipulating lexical scratchpads are new_pad to create a new pad, store_lex to store a variable in a pad, find_lex to retrieve a variable from a pad, push_pad to push a pad onto the pad stack, and pop_pad to remove a pad from the stack:

new_pad 0                # create and push a pad with depth 0
new P0, .PerlInt         # create a variable
set P0, 10               # assign value to it
store_lex 0, "$foo", P0  # store the var at depth 0 by name
# ...
find_lex P1, 0, "$foo"   # get the var into P1
print P1
print "\n"               # prints 10
pop_pad                  # remove pad
end

The first statement creates a new scratchpad and pushes it onto the pad stack. It's created with depth 0, which is the outermost lexical scope. The next two statements create a new PMC object in P0, and give it a value. The store_lex opcode stores the object in P0 as the named variable $foo in the scratchpad at depth 0. At some later point in the program, the find_lex opcode retrieves the value of $foo in the pad at depth 0 and stores it in the register P1 so it can be printed. At the very end, pop_pad removes the pad from the pad stack.

The new_pad opcode has two forms, one that creates a new scratchpad and stores it in a PMC, and another that creates a new scratchpad and immediately pushes it onto the pad stack. If the pad were stored in a PMC, you would have to push it onto the pad stack before you could use it:

new_pad P10, 0                # create a new pad in P10
push_pad P10                  # push it onto the pad stack

In a simple case like this, it really doesn't make sense to separate out the two instructions, but you'll see later in Section 6.7 why it's valuable to have both.

The store_lex and find_lex opcodes can take an integer index in place of a name for the variable:

store_lex 0, 0, P0  # store by index
# ...
find_lex P1, 0      # retrieve by index

With an index, the variable is stored in the scratchpad array, instead of the scratchpad hash.

6.6.2.2 Nested scratchpads

To create a nested scope, you create another scratchpad with a higher depth number and push it onto the pad stack. The outermost scope is always depth 0, and each nested scope is one higher. The pad stack won't allow you to push on a scratchpad that's more than one level higher than the current depth of the top of the stack:

new_pad 0                  # outer scope
new_pad 1                  # inner scope
new P0, .PerlInt
set P0, 10
store_lex -1, "$foo", P0   # store in top pad
new P1, .PerlInt
set P1, 20
store_lex -2, "$foo", P1   # store in next outer scope
find_lex P2, "$foo"        # find in all scopes
print P2                   # prints 10
print "\n"
find_lex P2, -1, "$foo"    # find in top pad
print P2                   # prints 10
print "\n"
find_lex P2, -2, "$foo"    # find in next outer scope
print P2                   # prints 20
print "\n"
pop_pad
pop_pad
end

The first two statements create two new scratchpads, one at depth 0 and one at depth 1, and push them onto the pad stack. When store_lex and find_lex have a negative number for the depth specifier, they count backward from the top pad on the stack. -1 is the top pad, and -2 is the second pad back. In this case, the pad at depth 1 is the top pad, and the pad at depth 0 is the second pad. So:

store_lex -1, "$foo", P0   # store in top pad

stores the object in P0 as the named variable $foo in the pad at depth 1. Then:

store_lex -2, "$foo", P1   # store in next outer scope

stores the object in P1 as the named variable $foo in the pad at depth 0.

A find_lex statement with no depth specified searches every scratchpad in the stack from the top of the stack to the bottom:

find_lex P2, "$foo"        # find in all scopes

Both pad 0 and pad 1 have variables named $foo, but only the value from the top pad is returned. store_lex also has a version with no depth specified, but it only works if the named lexical has already been created at a particular depth. It searches the stack from top to bottom and stores the object in the first lexical it finds with the right name.

The peek_pad instruction retrieves the top entry on the pad stack into a PMC register, but doesn't pop it off the stack.

    Team LiB   Previous Section   Next Section