# Copyright (C) 2001-2012, Parrot Foundation.

=head1 NAME

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

=head1 DESCRIPTION

This is the FAQ for anyone interested in writing compilers in PIR, targeting
the Parrot Virtual Machine.

=head1 GENERAL QUESTIONS

=head2 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 F<README.pod> files in the root directory
for more information about building Parrot.

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

See L<http://parrot.github.com/html/examples/languages/squaak/doc/tutorial_episode_1.pod.html>.

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

Use C<.line 42 "file.pir"> for this.

=head1 SUBROUTINES

=head2 How do I generate a sub call in PIR?

This looks like a function call in many HLLs:

=begin PIR_FRAGMENT

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

=end PIR_FRAGMENT

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.

=begin PIR_FRAGMENT

   somefunctionlabel( $P1, $P2, $P3 )

=end PIR_FRAGMENT

You can also get return value(s):

=begin PIR_FRAGMENT

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

=end PIR_FRAGMENT

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

=begin PIR_FRAGMENT

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

=end PIR_FRAGMENT

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

=head2 How do I generate a method call in PIR?

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

=begin PIR_FRAGMENT

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

=end PIR_FRAGMENT

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

=begin PIR_FRAGMENT

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

=end PIR_FRAGMENT

=head2 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:

=begin PIR_FRAGMENT

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

=end PIR_FRAGMENT

A more dynamic way is:

=begin PIR_FRAGMENT

  .local pmc foo
  foo = find_name 'foo'

=end PIR_FRAGMENT

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 I<foo()> is used, but the
compiler can't figure out, where the function is.

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

=begin PIR_FRAGMENT

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

=end PIR_FRAGMENT

This fetches the sub C<foo> in the C<Foo> namespace.

=head2 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 C<newclosure> to capture the environment.

=begin PIR_FRAGMENT

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

=end PIR_FRAGMENT

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

=begin PIR

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

=end PIR

=head2 How do I generate a tail call in PIR?

=begin PIR

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

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

=end PIR

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

=head2 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 C<:flat> directive.

=begin PIR_FRAGMENT

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

=end PIR_FRAGMENT

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

Use a slurpy array:

=begin PIR

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

=end PIR

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

=begin PIR

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

=end PIR

=head2 How do I pass optional arguments?

Use the C<:optional> and C<:opt_flag> pragmas:

=begin PIR

  .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
      # ...
    got_arg1:
      # ...
  .end

=end PIR

=head2 How do I create nested subroutines?

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

=head1 VARIABLES

=head2 How do I fetch a variable from the global namespace?

Use the C<get_root_global> or C<get_hll_global> op:

=begin PIR_FRAGMENT

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

=end PIR_FRAGMENT

=head2 How can I delete a global?

You can retrieve the namespace hash and use the C<delete> opcode.

=begin PIR

    .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

=end PIR

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

Please refer to L<docs/pdds/pdd20_lexical_vars.pod> for details.

=head2 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 C<null> opcode.)

=head2 How do I resolve a variable name?

Use C<find_name>:

=begin PIR_FRAGMENT

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

=end PIR_FRAGMENT

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

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

=begin PIR_FRAGMENT

    find_lex $P0, 'foo'

=end PIR_FRAGMENT

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

=head2 How do I fetch a variable from any nesting depth?

That is still the same:

=begin PIR_FRAGMENT

    find_lex $P0, 'foo'

=end PIR_FRAGMENT

This finds a C<foo> variable at any B<outer> depth starting from the top.

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

=head2 How can I produce more efficient code for lexicals?

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

=head1 MODULES, CLASSES, and OBJECTS

=head2 How do I create a module?

XXX

=head2 How do I create a class?

With the C<newclass> op:

=begin PIR_FRAGMENT

    newclass $P0, 'Animal'

=end PIR_FRAGMENT

=head2 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:

=begin PIR_FRAGMENT

    addattribute $P0, 'legs'

=end PIR_FRAGMENT

=head2 How do I add instance methods to a class?

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

=begin PIR

  .namespace [ 'Animal' ]

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

=end PIR

=head2 How do I override a vtable on a class?

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

=begin PIR

  .namespace [ 'NearlyPi' ]

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

=end PIR

Now, given an instance of NearlyPi in $P0

=begin PIR_FRAGMENT

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

=end PIR_FRAGMENT

=head2 How do I access attributes?

You can access attributes by a short name:

=begin PIR_FRAGMENT_INVALID

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

=end PIR_FRAGMENT_INVALID

=head2 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.

=head2 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 C<newclass> op if you created
the class, or use the C<get_class> op:

=begin PIR_FRAGMENT

    get_class $P0, 'Animal'

=end PIR_FRAGMENT

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

=begin PIR_FRAGMENT

    subclass $P1, $P0, 'Dog'

=end PIR_FRAGMENT

This stores the newly created class PMC in $P1.

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

First, create a class without a parent class using C<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.

=head2 How do I add another parent class to my class?

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

=begin PIR_FRAGMENT

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

=end PIR_FRAGMENT

=head2 How can I specify the constructor of a class?

Just override the init vtable for that class.

=begin PIR

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

    .namespace ['Dog']

    .sub init :vtable
      # ...
    .end

=end PIR

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

=begin PIR_FRAGMENT

    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

=end PIR_FRAGMENT

=head2 How do I instantiate a class?

You can do so either with the class name:

=begin PIR_FRAGMENT

    new $P0, 'Dog'

=end PIR_FRAGMENT

or with the class object:

=begin PIR_FRAGMENT_INVALID

    .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

=end PIR_FRAGMENT_INVALID

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 C<new> opcode the constructor is called.

=head2 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:

=begin PIR_FRAGMENT

    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

=end PIR_FRAGMENT

=head2 How do I add module/class methods?

XXX

=head2 How do I access module/class variables?

XXX

=head1 EXCEPTIONS

=head2 How do I throw an exception in PIR?

The easiest way is the perl-like

=begin PIR_FRAGMENT

    die 'Eeeek!'

=end PIR_FRAGMENT

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

=begin PIR_FRAGMENT

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

=end PIR_FRAGMENT

=head2 How do I catch an exception in PIR?

Use C<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
C<pop_eh>.

=begin PIR_FRAGMENT_INVALID

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

=end PIR_FRAGMENT_INVALID

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

=begin PIR_FRAGMENT

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

=end PIR_FRAGMENT

=head2 How do I let exceptions from C<exit> pass through my handler?

Rethrow the exception if it has a severity of C<EXCEPT_EXIT>.

=begin PIR_FRAGMENT

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

=end PIR_FRAGMENT

Exception example:

=begin PIR_FRAGMENT

    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

=end PIR_FRAGMENT

=head1 C EXTENSIONS

=head2 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 L<tools/build/pmc2c.pl> and L<docs/pmc.pod>.

See L<src/dynpmc/Makefile> for an example of how to build your dynamic
PMCS.

=head2 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 L<src/dynoplibs>.

=head2 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:

=begin PIR

  .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

=end PIR

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:

=begin PIR_FRAGMENT

 .local pmc lib
 .local string libname
 null libname

 lib = loadlib libname

=end PIR_FRAGMENT

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

=head1 MISC.

=head2 How can I access a program's environment?

Create a new C<Env> PMC and access it like a hash.

=begin PIR_FRAGMENT

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

=end PIR_FRAGMENT

=head2 How can I access Parrot's configuration?

=begin PIR_FRAGMENT

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

=end PIR_FRAGMENT

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

=cut
