NAME

docs/compiler_faq.pod - Parrot FAQ for compiler writers in PIR

General Questions

Which C compilers can I use with Parrot?

Whoa, there--you're looking at the wrong FAQ. This document is for people writing compilers that target Parrot.

To answer your question, though, Parrot should theoretically work with any C89-compliant C compiler. See the README files in the root directory for more information about building Parrot.

How can I implement a compiler to use as a compiler object from within Parrot?

See http://www.parrotblog.org/2008/03/targeting-parrot-vm.html.

How do I embed source locations in my code for debugging?

Use .line 42 "file.pir" for this.

Subroutines

How do I generate a sub call in PIR?

This looks like a function call in many HLLs:

   $P0( $P1, $P2, $P3 )

where $P0 is the function object, and $P1, $P2, and $P3 are its parameters. You can also use a function's name in place of the object, as long as it's in the same namespace.

   somefunctionlabel( $P1, $P2, $P3 )

You can also get return value(s):

  ($P1,$P2) = $P0( $P1, $P2, $P3 )

If the function name might collide with a Parrot opcode, quote it:

   .local int i
   i = 'new'(42)

You can also use the full PCC for these calls. See "pdd19_pir.pod/Parameter Passing and Getting Flags" in docs and other questions below for more information.

How do I generate a method call in PIR?

Similar to function calls, just append . and the method name to the object. You should quote a literal method name to avoid confusion.

  .local pmc ret_val, some_obj, arg
  ret_val = some_obj.'some_meth'(arg)

The method name may also be a string variable representing a method name:

  .local string m
  .local pmc curses_obj
  m = 'bold'
  curses_obj.m()

How do I locate or create a subroutine object?

There are several ways to achieve this, depending on the location of the subroutine.

If the sub is in the same file use a Sub constant:

  .const 'Sub' foo = 'foo'
  # ...
  foo()

A more dynamic way is:

  .local pmc foo
  foo = find_name 'foo'

This searches for a subroutine 'foo' in the current lexical pad, in the current namespace, in the global, and in the builtin namespace in that order. This opcode is generated, if foo() is used, but the compiler can't figure out, where the function is.

If the subroutine is in a different namespace, use the get_hll_global or get_root_global opcodes:

  .local pmc foo
  foo = get_root_global ['Foo'], 'foo'

This fetches the sub foo in the Foo namespace.

How do I create a Closure or Coroutine?

Closure and Coroutine carry both a dynamic state. Therefore you need to perform two steps. First use one of the above ways to locate the Sub object. Then use the op newclosure to capture the environment.

  .local pmc coro
  coro = find_name 'my_coro'
  coro = newclosure coro

Any subroutine that contains a .yield directive is automatically created as a Coroutine PMC:

  .sub my_coro             # automagically a Coroutine PMC
     .param pmc result
     #...
     .yield (result)
     #...
  .end

How do I generate a tail call in PIR?

  .sub foo
      # ...
      .tailcall bar(42)           # tail call sub bar
  .end

  .sub bar
      .param int answer
      inc answer
      .return(answer)
  .end

The sub bar will return to the caller of foo. (Warning! This fails in some cases. XXX Find the Trac ticket and reference it here.)

How do I generate a sub call with a variable-length parameter list in PIR?

If you have a variable amounts of arguments in an array, you can pass all items of that array with the :flat directive.

  .local pmc ar, foo
  ar = new 'ResizablePMCArray'
  push ar, "arg 1\n"
  push ar, "arg 2\n"
  #...
  foo(ar :flat)
  #...

How to I retrieve the contents of a variable-length parameter list being passed to me?

Use a slurpy array:

  .sub mysub
    .param pmc argv      :slurpy
    .local int argc
    argc = argv
    #...
  .end

If you have a few fixed parameters too, you can use a slurpy array to get the rest of the arguments

  .sub mysub
    .param pmc arg0
    .param pmc arg1
    .param pmc varargs   :slurpy
    .local int num_varargs
    num_varargs = varargs
    # ...
  .end

How do I pass optional arguments?

Use the :optional and :opt_flag pragmas:

  .sub foo
     .param pmc arg1       :optional
     .param int has_arg1   :opt_flag
     .param pmc arg2       :optional
     .param int has_arg2   :opt_flag

     if has_arg1 goto got_arg1
     #...
  .end

How do I create nested subroutines?

Please refer to "pdds/pdd20_lexical_vars.pod/Nested Subroutines Have Outies; the ":outer" attribute" in docs for details.

Variables

How do I fetch a variable from the global namespace?

Use the get_root_global or get_hll_global op:

    get_hll_global $P0, ['name'; 'space'], 'name_of_the_global'
    get_hll_global $P1, 'name_of_the_global'

How can I delete a global?

You can retrieve the namespace hash and use the delete opcode.

    .sub main :main
    $P0 = new 'Integer'
    $P0 = 42
    set_hll_global 'foo', $P0
    set_hll_global ['Bar'], 'baz', $P0
    show_baz()
    .local pmc ns, Bar_ns
    ns = get_hll_namespace
    delete ns['foo']              # delete from top level
    Bar_ns = ns['Bar']            # get Bar namespace
    delete Bar_ns['baz']
    show_baz()
    .end
    .sub show_baz
    $P0 = get_hll_global ['Bar'], 'baz'
    print "'baz' is "
    if null $P0 goto is_null
    print $P0
    print ".\n"
    .return ()
    is_null:
    print "null.\n"
    .end

How do I use lexical pads to have both a function scope and a global scope?

Please refer to "pdds/pdd20_lexical_vars.pod" in docs for details.

How can I delete a lexical variable?

You can't. You can store a PMCNULL as the value though, which will catch all further access to that variable and throw an exception. (You can create a PMCNULL with the null opcode.)

How do I resolve a variable name?

Use find_name:

    $P0 = find_name '$x'
    find_name $P0, 'foo'    # same thing

This will find the name foo in the lexical, global, or builtin namespace, in that order, and store it in $P0.

How do I fetch a variable from the current lexical pad?

    find_lex $P0, 'foo'

or much better, if possible just use the variable defined along with the .lex definition of foo.

How do I fetch a variable from any nesting depth?

That is still the same:

    find_lex $P0, 'foo'

This finds a foo variable at any outer depth starting from the top.

If your language looks up variables differently, you have to walk the 'caller' chain. See also t/dynpmc/dynlexpad.t.

How can I produce more efficient code for lexicals?

Don't emit store_lex at all. Use find_lex only if the compiler doesn't know the variable. You can always just use the register that was defined in the .lex directive as an alias to that lexical, if you are in the same scope.

Modules, Classes, and Objects

How do I create a module?

XXX

How do I create a class?

With the newclass op:

    newclass $P0, 'Animal'

How do I add instance variables/attributes?

Each class knows which attributes its objects can have. You can add attributes to a class (not to individual objects) like so:

    addattribute $P0, 'legs'

How do I add instance methods to a class?

Methods are declared as functions in the class namespace with the :method keyword appended to the function declaration:

  .namespace [ 'Animal' ]

  .sub run :method
     print "slow and steady\n"
  .end

How do I override a vtable on a class?

As with methods, but note the new keyword. The vtable name specified must be an existing vtable slot.

  .namespace [ 'NearlyPi' ]

  .sub get_string :vtable
     .return ('three and a half')
  .end

Now, given an instance of NearlyPi in $P0

  $S0 = $P0
  say $S0  # prints 'three and a half'

How do I access attributes?

You can access attributes by a short name:

  $P0 = getattribute self, 'legs'
  assign $P0, 4                   # set attribute's value

When should I use properties vs. attributes?

Properties aren't inherited. If you have some additional data that don't fit into the class's hierarchy, you could use properties.

How do I create a class that is a subclass of another class?

You first have to get the class PMC of the class you want to subclass. Either you use the PMC returned by the newclass op if you created the class, or use the get_class op:

    get_class $P0, 'Animal'

Then you can use the subclass op to create a new class that is a subclass of this class:

    subclass $P1, $P0, 'Dog'

This stores the newly created class PMC in $P1.

How do I create a class that has more than one parent class?

First, create a class without a parent class using newclass (or with only one subclass, see previous question). Then add the other parent classes to it. Please refer to the next question for an example.

How do I add another parent class to my class?

If you have a class PMC (created with newclass or by subclass), you can add more parent classes to it with the addparent op:

    get_class $P1, 'Dog'
    subclass $P2, $P1, 'SmallDog'
    get_class $P3, 'Pet'
    addparent $P2, $P3  # make "SmallDog" also a "Pet"

How can I specify the constructor of a class?

Just override the init vtable for that class.

    .sub _ :main
      newclass $P0, 'Dog'         # create a class named Dog
    .end

    .namespace ['Dog']

    .sub init :vtable
      # ...
    .end

Or you can specify the constructor method by setting the BUILD property of the class PMC:

    newclass $P0, 'Dog'         # create a class named Dog
    new $P1, 'String'           # create a string
    set $P1, 'initialise'       # set it to the name of the constructor method
    setprop $P0, 'BUILD', $P1   # set the BUILD property

How do I instantiate a class?

You can do so either with the class name:

    new $P0, 'Dog'

or with the class object:

    .loadlib 'io_ops'

    $P1 = get_class 'Dog'   # find the 'Dog' class
    unless null $P1 goto have_dog_class
    printerr "Oops; can't find the 'Dog' class.\n"
    .return ()
  have_dog_class:
    new $P0, $P1    # creates a Dog object and stores it in register $P0

The chief difference is that using a string constant will produce the specific error "Class 'Dog' not found" if that happens to be the case; the other code has to check explicitly.

During the new opcode the constructor is called.

How can I pass arguments to a constructor?

You can pass only a single argument to a constructor. By convention, a hash PMC is passed to the constructor that contains the arguments as key/value pairs:

    new $P0, 'Hash'
    set $P0['greeting'], 'hello'
    set $P0['size'], 1.23

    new $P1, 'Alien', $P0       # create an Alien object and pass
                                # the hash to the constructor

How do I add module/class methods?

XXX

How do I access module/class variables?

XXX

Exceptions

How do I throw an exception in PIR?

The easiest way is the perl-like

    die 'Eeeek!'

You can also explicitly create an exception object and throw it:

    $P0 = new 'Exception'
    $P0 = 'something happened'
    throw $P0

How do I catch an exception in PIR?

Use push_eh to push an exception handler onto the stack. End the set of instructions that might throw the exception you're interested in with pop_eh.

    push_eh handler
      die 'whoops'  # or any other code that might throw an exception...
    pop_eh
    # ok

An exception handler is called with one argument, which is the exception object. The message of the exception can be easily extracted, as follows:

  handler: # exception
    .get_results ($P0)
    print 'Exception caught:'
    $S0 = $P0['message']
    say $S0

How do I let exceptions from exit pass through my handler?

Rethrow the exception if it has a severity of EXCEPT_EXIT.

  .include 'except_severity.pasm'
  # ...
  handler:
    .get_results ($P0)
    $I0 = $P0['severity']
    if $I0 == .EXCEPT_EXIT goto handle_exit
    say 'Exception caught!'
    # ...

  handle_exit:
    rethrow $P0 # let the next handler deal with it.

Exception example:

    push_eh handler
    $P0 = new 'Exception'
    $P0 = 'something happened'
    throw $P0
    pop_eh
    exit 0

  handler:
    .local pmc exception
    .local string message
    .get_results (exception)
    print 'Exception: '
    message = exception['message']
    print message
    print "\n"
    exit 1

C Extensions

How do I create PMCs for my compiler?

Parrot supports dynamic PMCs, loadable at runtime, to allow compiler writers to extend Parrot with additional types. For more information about writing PMCs, see "build/pmc2c.pl" in tools and "pmc.pod" in docs.

See "dynpmc/Makefile" in src for an example of how to build your dynamic PMCS.

How do I add another op to Parrot?

Parrot supports dynamic op libraries. These allow for ops specific to one language to be used without having to place them into the Parrot core itself. For examples of dynamic op libraries, see "dynoplibs" in src.

How do I use the Native Calling Interface (NCI)?

Using the NCI you can invoke functions written in C from a Parrot script. To every NCI invocation, there are two parts: the native function to be invoked, and the PIR code to do the invocation.

First the native function, to be written in C. On Windows, it is necessary to do a DLL export specification of the NCI function:

  /* foo.c */

  /* specify the function prototype */
  #ifdef __WIN32
  __declspec(dllexport) void foo(void);
  #else
  void foo(void);
  #endif

  void foo(void) {
    printf("Hello Parrot!\n");
  }

Then, after having compiled the file as a shared library, the PIR code looks like this:

  .sub main :main
     .local pmc lib, func

     # load the shared library
     lib = loadlib "hello" # no extension, .so or .dll is assumed

     # get a reference to the function from the library just
     # loaded, called "foo", and signature "void" (and no arguments)
     func = dlfunc lib, "foo", "v"

     # invoke
     func()

  .end

If you embedded a Parrot in your C file and you want to invoke another function in that same C file, you should pass a null string to loadlib. Do that as follows:

 .local pmc lib
 .local string libname
 null libname

 lib = loadlib libname

Under Linux, the .c file must then be linked with the -export-dynamic option.

Misc

How can I access a program's environment?

Create a new Env PMC and access it like a hash.

    .local pmc e
    e = new 'Env'
    $P0 = e['USER']      # lt

How can I access Parrot's configuration?

    .include 'iglobals.pasm'
    .local pmc interp, cfg
    interp = getinterp
    cfg = interp[.IGLOBALS_CONFIG_HASH]
    $S0 = cfg['VERSION']    # "0.3.0"

See config_lib.pasm for all the keys in the config hash - or iterate over the config hash.