9.6 Lexicals and Globals

     

9.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 lifetime 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.

9.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. In the third statement, store_global stores that PMC as the named global variable $foo . At some later point in the program, find_global retrieves the PMC from the global variable by name, and stores it in P0 so it can be printed.

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. Leaving the global variable as an alias 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.

The two-argument forms of store_global and find_global store or retrieve globals from the outermost namespace (what Perl users will know as the "main" namespace). A simple flat global namespace isn't enough for most languages, so Parrot also needs to support hierarchical namespaces for separating packages (classes and modules in Perl 6). The three-argument versions of store_global and find_global add an argument to select a nested namespace:

 store_global "Foo", "var", P0 # store P0 as var in the Foo namespace find_global P1, "Foo", "var"  # get Foo::var 

Eventually, the global opcodes will have variants that take a PMC to specify the namespace, but the design and implementation of these aren't finished yet.

9.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.

9.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 9.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.

9.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, so -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.



Perl 6 and Parrot Essentials
Perl 6 and Parrot Essentials, Second Edition
ISBN: 059600737X
EAN: 2147483647
Year: 2003
Pages: 116

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net