#! perl
# Copyright (C) 2001-2006, The Perl Foundation.
# $Id: pmc2c.pl 16333 2006-12-30 17:14:19Z tewk $

use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../..";
use lib "$FindBin::Bin/../../lib";
use Getopt::Long;
use Data::Dumper;
use Parrot::Pmc2c::Utils;

my (%opt, @include);
my %action;

GetOptions(
    "include=s"     => \@include,
    "vtable"        => \$action{default},
    "dump"          => \$action{dump},
    "c|gen-c"       => \$action{gen_c},
    "tree"          => \$action{tree},
    "no-body"       => \$opt{nobody},
    "no-lines"      => \$opt{nolines},
    "debug+"        => \$opt{debug},
    "verbose+"      => \$opt{verbose},
    "library=s"     => \$opt{library},
    "testing"       => \$opt{testing},
) or exit 1;

if ( 0 == grep { $action{$_} } keys %action ) {
    die "No action specified!\n";
}

my @args = @ARGV;

my $self = Parrot::Pmc2c::Utils->new( {
    include => \@include,
    opt     => \%opt,
    args    => \@args,
} );

if ( $action{default} ) {
    my $dump_file = $self->dump_vtable("$FindBin::Bin/../../vtable.tbl");
    exit;
}

if ( $action{dump} ) {
    $self->dump_pmc();
    exit;
}

if ( $action{tree} ) {
    $self->print_tree( {
        depth   => 0,
    } );
    exit;
}

if ( $action{gen_c} ) {
    $self->gen_c();
    exit;
}

=head1 NAME

tools/build/pmc2c.pl - PMC definition to C compiler

=head1 SYNOPSIS

=head2 Options used in Parrot F<Makefile>

Create F<src/pmc/foo.dump>:

    % perl tools/build/pmc2c.pl --dump src/pmc/foo.pmc ...

Create F<vtable.dump>:

    % perl tools/build/pmc2c.pl --vtable

Create F<src/pmc/foo.c> and C<pmc_foo.h> from F<src/pmc/foo.dump>:

    % perl tools/build/pmc2c.pl -c src/pmc/foo.pmc ...

=head2 Other Options

Print a class tree for the specified PMCs:

    % perl tools/build/pmc2c.pl --tree src/pmc/*.pmc

Create fooX.c and pmc_fooX.h from fooX.dump files, also create libfoo.c
containing the initialization function for all fooX PMCs.

    % perl tools/build/pmc2c.pl --library libfoo -c \
           src/pmc/foo1.pmc src/pmc/foo2.pmc ...

=head1 DESCRIPTION

The job of the PMC compiler is to take .pmc files and create C files
that can be compiled for use with the Parrot interpreter.

=head1 COMMAND-LINE OPTIONS

=over 4

=item C<--debug>

Increase debug level

=item C<--verbose>

Increase verbose level

=item C<--no-lines>

Omit source line info

=item C<--no-body>

Emit an empty body in the dump. This may be useful for debugging.

=item C<--include=/path/to/pmc>

Specify include path where to find PMCs.

=item C<--library=libname>

Specify the library name. This will create F<E<lt>libnameE<gt>.c> and
F<pmc_E<lt>libnameE<gt>.h>. The initialization function will be named
after libname and will initialize all PMCs in the library.

=back

=head2 Internals

To see the internal data structures please run:

    % perl tools/build/pmc2c.pl --c --debug --debug sarray.pmc | less

=head2 Compiling PMCs

First, the program determines the names of the .c and .h files from
the basename of the .pmc file (e.g. F<perlint.pmc> -> F<perlint.c> and
F<perlint.h>).

Next, the file is searched for C</pmclass \w*/> which attempts to find the
class being declared.

Once the class is found, all of its superclasses are scanned and their
methods added to the methods of the current PMC. PMCs default to
inheriting from 'default'. Only single inheritance is supported.

Once the superclass is determined, it is processed and its method names
are extracted and saved.

Next, each method body is processed with various directives (see below)
getting replaced by their appropriate values.

Finally, the .c and .h files are generated. The appropriate base class
header files are included.

If the C<noinit> flag was used, then no init function is generated.
Otherwise, one is generated which sets up the vtable and enters it into
the C<vtables> array.

The .c file is generated by appending the functions after the various
directives have been replaced.

=head2 PMC File Syntax

The basic syntax of a PMC file is

=over 4

=item 1.

A preamble, consisting of code to be copied directly to the .c file

=item 2.

The C<pmclass> declaration:

    pmclass PMCNAME [flags] {

where C<flags> are:

=over 4

=item C<extends PMCPARENT>

All methods not defined in PMCNAME are inherited from the PMCPARENT class.
If no parent class is defined, methods from F<default.pmc> are used.

=item C<abstract>

This class cannot be instantiated. Abstract classes are shown with lower
case class names in the class tree.

=item C<noinit>

Used with C<abstract>: No C<class_init> code is generated.

=item C<const_too>

Classes with this flag get 2 vtables and 2 enums, one pair with
read/write set methods, and one with read-only set methods.

=item C<need_ext>

The class needs a C<PMC_EXT> structure. For instance, any class using
C<PMC_data> will have C<need_ext>.

=item C<does interface>

The class 'does' the given interfaces (the collection of methods
which the class implements).

The default is "scalar". Other currently used interfaces are:

    array    : container PMC with numerically-keyed elements
    event    : PMC that can be used with event queue
    hash     : container PMC with string-keyed elements
    library  : PMC that corresponds to a dynamic library
    ref      : PMC that references another PMC
    string   : PMC that behaves similarly to the base string type
    boolean  : PMC that does true/false only.
    integer  : PMC that behaves similarly to the base int type
    float    : PMC that behaves similarly to the base number type
    scalar   : (only used by the sample src/dynpmc/foo.pmc)

This is not a canonical list, but merely a snapshot of what's in use.

=item C<dynpmc>

The class is a dynamic class. These have a special C<class_init>
routine suitable for dynamic loading at runtime. See the F<src/dynpmc>
directory for an example.

=item C<group GROUP>

The class is part of a group of interrelated PMCs that should be
compiled together into a single shared library of the given name. Only
valid for dynamic PMCs.

=item C<lib LIB>

The class needs an external library.

=item C<hll HLL>

The High level language this PMC corresponds to.

=item C<maps Type>

The basic parrot PMC type that this PMC correspond to for C<.HLL>
usage. For example:

    pmcclass TclInt hll Tcl maps Integer

allows this PMC to automatically be used when autoboxing C<I> registers to PMCs.

Requires the C<hll> flag.

=back

=item 3.

A list of vtable method implementations

=item 4.

The final close C<}>

=back

=head2 Method Body Substitutions

The vtable method bodies can use the following substitutions:

=over 4

=item C<SELF>

Converted to the current PMC object of type C<PMC *>.

=item C<INTERP>

Converted to the interpreter object.

=item C<OtherClass.SELF.method(a,b,c)>

Calls the static vtable method 'method' in C<OtherClass>.

=item C<SELF.method(a,b,c)>

Calls the vtable method 'method' using the static type of C<SELF> (in
other words, calls another method defined in the same file).

=item C<DYNSELF.method(a,b,c)>

Calls the vtable method 'method' using the dynamic type of C<SELF>.

=item C<DYNSELF(a,b,c)>

Same as above, but calls the current method.

=item C<OtherClass.SUPER(a,b,c)>

Calls the overridden implementation of the current method in
C<OtherClass>.

=item C<SUPER(a,b,c)>

Calls the overridden implementation of the current method in the nearest
superclass, using the static type of C<SELF>.

=item C<DYNSUPER(a,b,c)>

As above, but uses the actual dynamic type of C<SELF>.

=back

=head1 AUTHOR

Leopold Toetsch.

Cleaned up by Matt Diephouse.

Many thanks to the author of F<pmc2c.pl>, many useful code pieces got
reused.

=cut

__END__
# Local Variables:
#   mode: cperl
#   cperl-indent-level: 4
#   fill-column: 100
# End:
# vim: expandtab shiftwidth=4:
# %opt = map { $_ => 0 } qw(nobody nolines debug verbose);
