#!/usr/bin/perl -w
#
# perl6 driver:  parse assemble compile and run .p6 files
#
# perl6 -h   for help - pod is at end of file
#
# (c) 2002 Leopold Toetsch <lt@toetsch.at>
# s. LICENCES in parrot root dir for licence
#
# TODO's:
# s. pod

use 5.005_03;	# _02 might work too, untested.
use strict;
use FindBin;
use lib "$FindBin::Bin/../../lib";
use Getopt::Long;
use Parrot::Config;
use P6C::Tree;
use P6C::Parser;

use vars qw($IMCC $ASM $PARROT $PBC2C $HERE $CD $VERSION $PERL $slash $exe);
use vars qw($PARROT_ROOT @temp_files $LIB $TEST_GLOB $TEST_IMPORT);
$VERSION = '0.09';

do 'perl6-config' or	# read pconfig, which was generated by Makefile
die "'perl6-config' not found: $!";

$slash = $PConfig{slash};
$exe = $PConfig{exe};
$LIB = $PConfig{a};
# somewhen we need install paths
$IMCC   = "..${slash}imcc${slash}imcc";
$PERL	= $PConfig{perl};
$ASM    = "$PERL ..${slash}..${slash}assemble.pl";
$PARROT = "$PARROT_ROOT${slash}parrot$exe";
$CD = "cd $PARROT_ROOT; ";
$PBC2C = "$CD $PERL pbc2c.pl";
#
# imported meth's for Test::More
$TEST_IMPORT = 'skip is';
# glob pattern for test to run
$TEST_GLOB = 't/{compiler,rx}/*.t';

sub usage($) {
    my $fh = shift;
    print($fh <<'EOF'
    usage:  perl6 [ p6c-options ] [ imcc-options ]
    [ asm-options ] [ run-options ]
    [ global-options ] file [arguments ... ]
	    perl6 --clean *.p6
	    perl6 --test [testfiles]

    p6c-options:

    Output options:
    -C,--compile-pbc compile to executable
    -B,--pbc         stop after creating .pbc file
    -S,--pasm        stop after creating .pasm file
    -I,--imc         stop after creating .imc file
    --tree           stop after creating parse tree
    --raw-tree       output raw parser tree
    --keep-xxx       keep intermediate file .xxx
    -k,--keep-all    keep all intermediate files
    --rm-exe         remove executable (mainly for testnative)
    --test-parser    interactive parser-testing mode

    -g,--debug-info  generate debug info, i.e. produce and keep #line comments
    -Ox		     optimize flag (currently only gcc)
                     Note: these does not optimize parrot's obj file.

    --clean          delete all possible produced files for all mentioned
    		     .p6 source file

    --test	     run tests like "make test"

    Parse::RecDescent control:
    --trace          set $::RD_TRACE (or construct trace-enabled parser)
    --grammar NAME   use precompiled grammar NAME (default = Perl6grammar)

        only useful when constructing parser:
    --hitem          keep track of %item hash
    --force-grammar  Rebuild grammar even if it exists.

    Misc:
    --add-main       suround code by the main() function
    --rule NAME      start with rule NAME (default = 'prog')
    (only useful in interactive mode)

    imcc-options:

    --debug          write various debug messages to STDERR
    --yydebug        debug bison
    --verbose	     shows count of lines compiled

    asm-options:

    -E               Preprocess input files and terminate processing
    -h,--help        Print this message
    -o,--output F    Write output to file F
    -c,--checksyntax Check syntax only, do not generate bytecode

    run-options:

    -Rx,--parrot-options=bdhjpPgtv.
    pass option(s) to parrot, s. parrot -h
    -Rb.           e.g. call parrot -b -.
    -C,--compile-pbc compile and run C executable
    --shared         use dynamic parrot lib
    --ignore-exitcode don't report non zero exit codes
    -q,--quick       run .pbc directly, if present and newer then .p6

    global-options:

    -h --help        Print this message and exit
    -v --verbose     Print mesages about compile stages
    -vv            be more verbose
    -V --version     Print versions and exit
    -w --warnings    Print warnings
    -ww            Print diagnostics (N/Y)

EOF
    );
    exit(1);
}

use vars '%o';

Getopt::Long::Configure(qw(bundling));
GetOptions(\%o,qw{
    test-parser test
    trace hitem tree raw-tree
    add-main rule=s grammar=s force-grammar
    debug yydebug life-info
    debug-info|g
    verbose|v+
    warnings|w+
    parrot-options|R=s
    compile-pbc|C quick|q ignore-exitcode rm-exe shared
    optimize|O=s
    pbc|B pasm|S imc|I
    keep-imc keep-pasm keep-pbc keep-c keep-o keep-all|k keep-warn
    keep-tree clean
    help|h version|V
}) or usage(\*STDERR);

# print version of parts and exit
sub version {
    print "perl6 driver $VERSION\n\n";
    system("$PARROT -v");
    exit(0);
}

################
usage(\*STDOUT) if ($o{help});
version() if ($o{version});

$::RD_TRACE = $o{trace};
$::RD_NO_HITEM = !$o{hitem};
$::RD_NO_TRACE = !$o{trace};
$::rule = $o{rule} || 'prog';
$o{grammar} ||= 'Perl6grammar';
$o{'parrot-options'} ||= '';
$o{verbose} = 0 unless (defined $o{verbose});
$o{tree} = 1 if $o{'test-parser'};

my $filebase = 'a';		# basename for output files.

######## run parser and following steps

if ($o{test}) {
    run_tests();
}
else {
    run();
}
clean_temps();
########

###### utils
#
sub clean_temps {
    return if ($o{'keep-all'});
    for my $f (@temp_files) {
	my $ext;
	($ext = $f) =~ s/.*\.//;
	$f =~ s/$exe$//;
	next unless (-e $f);
	if ($o{verbose} > 1) {
	    print STDERR "unlink($f)\n" unless ($o{"keep-$ext"});
	}
	unlink($f) unless ($o{"keep-$ext"});
    }
}

sub clean_files($) {
    my $base = shift;
    push @temp_files, map {"$base.$_"} qw(imc pasm pbc c o warn tree trace dis);
    push(@temp_files, "$base$exe");
}

sub verbose($@) {
    my ($level, @t) = @_;
    if ($level <= $o{verbose}) {
	print STDERR "@t\n";
    }
}

#
# catch warnings of sub $sub and redirect them to file
#
my $wn = 0;
sub warnings($$) {
    my ($sub, $file) = @_;

    unless ($o{warnings}) {
	$wn++;

	if ($wn == 1) {
	    verbose(1, "Writing warnings to '$file'");
	    push(@temp_files, $file);
	}
	# redirect STDERR to file
	open(OERR, '>&STDERR');
	open(STDERR, ">>$file");
	select(STDERR); $|=1;
	select(STDOUT); $|=1;
	# and all warn messages too
	$SIG{'__WARN__'} = sub { print STDERR @_; };
	$SIG{'__DIE__'} = sub {
	    # print to file
	    print STDERR @_;
	    close(STDERR);
	    open(STDERR, '>&OERR');
	    # and to old dest, i.e. term
	    print STDERR "\n", @_;
	    die "\n",@_
	};
    }

    my $ret = &$sub;
    if ($wn) {
	# restore above redirects
	close(STDERR);
	open(STDERR, '>&OERR');
	close(OERR);	# avoid perl warning
	$SIG{'__WARN__'} = sub { warn @_; };
	$SIG{'__DIE__'} = sub { die @_; };
    }
    $ret;
}

sub mydie($$) {
    my ($ret, $prog) = @_;
    my $exit = $ret >> 8;
    my $sig = $ret & 127;
    my $dcore = $ret & 128;
    print STDERR "Error: '$prog' failed";
    if ($sig) {	# FIXME && OS ne Win?
	use Config;
	print STDERR "\n\tdied with signal $sig (SIG",(split(' ',$Config{sig_name}))[$sig],")\n";
	if ($dcore) {
	    print STDERR "\tand dumped core\n";
	    if ($o{verbose} > 1) {
		my ($prog) = split(' ', $prog);
		print STDERR "\tplease run 'gdb $prog core' and type 'bac' for reason\n";
	    }
	}
    }
    else {
	print STDERR " with exit code $exit\n";
    }
    die('Stopped');
}

##########################
# Pass 1 P6C parser
#        output file.imc [ file.tree ]
#

# dump tree or write imc
#
sub output_tree {
    my $tree = shift;
    my $file = shift;
    my $fw = shift || 0;
    if ($o{tree}) {
	my $tf;
	if ($file eq '-') {
	    $tf = '&STDOUT';
	} else {
	    $tf = "$filebase.tree";
	}
	verbose(2, "Dump tree to '$tf'");
	open(OUT, ">$tf") or die("Can't write '$tf': $!");
	print OUT Dumper($tree) if ($o{'raw-tree'});
	my $x = $tree->tree;
	print OUT Dumper($x);
	close OUT;
    } else {
	if ($o{'add-main'}) {
	    P6C::IMCC::add_function('main');
	    P6C::IMCC::set_function('main');
	}
	my $x = $tree->tree;
	verbose(2, "compiling tree");
	warnings(sub { P6C::IMCC::compile($x) }, $fw);
	my $f = "$filebase.imc";
	verbose(2, "Writing '$f'");
	open(OOUT, '>&STDOUT');
	open(STDOUT, ">$f");
	warnings(sub { P6C::IMCC::emit() }, $fw);
	close(STDOUT);
	open(STDOUT, '>&OOUT');
	close(OOUT);
	return if ($o{imc});
	push(@temp_files, $f);
	pass2($f, $fw);
    }
}

# load Perlgrammar or generate new
# make new parser
#
sub get_parser() {
    my $parser;
    # load needed moduls
    if (defined $o{tree}) {
	eval <<'END';
	use Data::Dumper;
	$Data::Dumper::Terse = 1;
	$Data::Dumper::Indent = 1;
END
	die $@ if $@;
    } else {
	eval 'use P6C::IMCC qw(:external)';
	die $@ if $@;
    }
    if (!$o{'force-grammar'} && eval("require $o{grammar}")) {
	$parser = eval "new $o{grammar}" or die "$o{grammar}: $@";
    } else {
	warn $@ if $@;
	verbose(1,"Constructing parser for $o{grammar}...");
	if ($o{grammar}) {
	    P6C::Parser->Precompile($o{grammar});
	    eval "require $o{grammar}" or die $@;
	    $parser = $o{grammar}->new;
	} else {
	    $parser = P6C::Parser->new();
	}
	verbose(1, "Done");
    }
    if (defined $o{'debug-info'}) {
	if ($parser->can('Debug')) {
	    $parser->Debug(1);
	}
	else {
	    $parser->Replace(q!stmts:  __stmt[$arg[0]](s?) !);
	}
    }
    $parser;
}

sub pass1($$$) {
    my ($parser, $f, $fw) = @_;
    my $in = '';
    local $/ = undef;
    verbose(1, "P6C '$f'");
    open(IN, $f) or die("Can't read '$f': $!");
    $in = <IN>;
    close(IN);
    verbose(2, "Parsing");
    P6C::IMCC::init() unless $o{tree};
    my $result = warnings(sub {$parser->$::rule($in,0,$f)}, $fw);
    output_tree($result, $f, $fw);
}

sub pbc_is_newer($) {
    my $base = shift;
    my $mp6  = (stat("$base.p6"))[9];
    my $mpbc = (stat("$base.pbc"))[9];
    return $mpbc >= $mp6;
}

sub p6_is_newer($) {
    my $base = shift;
    my $mp6  = (stat("$base.p6"))[9];
    my $test;
    ($test = $base) =~ s/_\d+$//;
    my $mt  = (stat("$test.t"))[9];
    return $mp6 >= $mt;
}
sub run {
    my $parser;

    if ($o{'test-parser'}) {
	run_interactive();
	return;
    }
    $ARGV[0] = '-' unless(@ARGV);
    while (@ARGV) {
    my $f = shift @ARGV;
    print STDERR "processing file '$f'\n" if($o{verbose}>1);
    if ($f eq '-') {
	$filebase = 'a';
    } else {
	($filebase = $f) =~ s/\.[^.]*$//;
    }
	# special, clean all generated files
    if ($o{clean}) {
	    clean_files($filebase) if ($f =~ /\.p6$/ || $f eq '-');
	next;
    }

	# normal processing, passes rest of ARGV to running prog
    # run next passes
    my $fw = "$filebase.warn";
    unlink($fw);
    if ($o{quick} && -e "$filebase.pbc" && pbc_is_newer($filebase)) {
	pass4("$filebase.pbc", $fw);
    }
    elsif ($f =~ /\.imc$/) {
	pass2($f, $fw);
    }
    elsif ($f =~ /\.pasm$/) {
	pass3($f, $fw);
    }
    elsif ($f =~ /\.(?:pb)?c$/) {
	pass4($f, $fw);
    }
    else {
	$parser = get_parser() unless ($parser);
	pass1($parser, $f, $fw);
    }
	return;
    }
}


# run tests like "make test"
sub output_is($$;$);
sub run_tests {
    my @testfiles = @ARGV ? @ARGV : glob($TEST_GLOB);
    undef $/;
    my $parser = get_parser();
    *output_is = sub($$;$) {
	my ($test, $out, $desc) = @_;
	my $n = Test::Builder->current_test+1;
	print STDERR "$n ";
	$filebase =~ s/(?:_\d+)?$/_$n/;
	my $fw = "$filebase.warn";
	my $result = warnings(sub {
	    $parser->$::rule($test,0,'-')}, $fw);
	my $file = "$filebase.p6";
	my $outf = "$filebase.out";
	$ARGV[0] = "> $outf";
	if ($o{quick} && -e "$filebase.pbc" &&
	    -e "$filebase.p6" &&
	    p6_is_newer($filebase) &&
	    pbc_is_newer($filebase)) {
	    pass4("$filebase.pbc", $fw);
	}
	else {
	    # reinit IMCC
	    P6C::IMCC::init();
	    # write .p6 file for reuse
	    # XXX if --keep only ??
	    open(OUT, ">$file");
	    print OUT $test;
	    close(OUT);
	    # run all steps
	    output_tree($result, $file, $fw);
	}
	# XXX should we delete test.out, test.warn?
	open(IN, $outf) or warn("Can't read '$outf': $!");
	my $res = <IN>;
	close(IN);
	$res =~ s/\cM//g;
	$out =~ s/\cM//g;
	# send result to Test::Builder
	is ($res, $out, $desc);
    };
    $|=1;
    my $Test;
    my @tests;
    print "Test details:\n";
    eval(<<EOF);
    use Test::Builder;
    use Test::More;
    \$Test = Test::Builder->new();
EOF
    for my $f (@testfiles) {
	open (IN, $f) or die("Can't read '$f': $!");
	my $contents = <IN>;
	close(IN);
	($filebase = $f) =~ s/\.[^.]*$//;
	my ($i, $nr, $ok, $nok) = (0)x4;
	my $ntot;
	print STDERR "$f ... ";
	# get # of tests from 'tests => ...'
	# and delete all use .. TEST ... stuff
	if ($contents =~ s/use\s+.*?tests\s*=>\s*(\d+).*?[\r\n]+//) {
	    $ntot = $1;
	}
	# set file name for test results
	my $fh = $Test->output("$filebase.test");
	push(@tests, "$filebase.test");
	# print header for Test::Harness
	print $fh "#!perl\n";
	print $fh qq(print <<"EOF";\n);
	$Test->plan(tests => $ntot, import => [qw($TEST_IMPORT)]);
	# reset test counter
	$Test->current_test(0);
	$contents =~ s/use\s+TEST.*?[\r\n]+//;
	eval(<<"EOFTEST");
	$contents
EOFTEST
        print STDERR ("\n");
	print STDERR $@ if($@);
	# end footer
	print $fh "EOF\n";
	# close .test file, else last one is missing below
	close($fh);
    }

    print "\nTest summary:\n";
    system($PERL, "t/harness", @tests);
}

sub run_interactive {
    my $in;
    # Delay loading Term::ReadLine if we don't need it.
    eval <<'END';
    use Term::ReadLine;

    my $term = new Term::ReadLine $0 or die $!;
    my $prompt = '> ';

    while (defined(my $l = $term->readline($prompt))) {
	if ($in =~ /^:(.*)/) {
	    print eval $1, "\n";
	    $in = '';
	    next;
	}
	unless ($l =~ /^$/) {
	    $in .= "$l\n";
	    $prompt = '? ';
	    next;
	}
	print "as $::rule:\n";
	my $result = $parser->$::rule($in);
	print STDERR "done\n";
	if ($result) {
	    output_tree($result, '-');
	} else {
	    print "parse error\n";
	}
	print "\n";
	$in = '';
	$prompt = '> ';
    }
END
    die $@ if $@;
}

#
# compile intermediate compile code .imc => .pasm
#
sub pass2($$) {
    my $file = shift;
    my $fw = shift;
    my $debug = join(' ', map { defined $o{$_} && $o{$_} ? "--$_" : '' }
	qw(debug yydebug verbose life-info));
    my $outfile = "$filebase.pasm";
    my $cmd = "$IMCC $debug $file $outfile";
    verbose(1, $cmd);
    warnings(sub {
	if (system($cmd)) {
	    mydie($?, $cmd);
	}
    }, $fw);
    return if $o{pasm};          # stop after generating pasm.
    push(@temp_files, $outfile);
    pass3($outfile, $fw);
}

#
# assemble byte code .pasm => .pbc
#
sub pass3($$) {
    my $file = shift;
    my $fw = shift;

    my $outfile = "$filebase.pbc";
    my $opt = '';
    $opt .= ' -E' if ($o{E});
    $opt .= ' -c' if ($o{checksyntax});
    my $cmd = "$ASM $opt $file -o $outfile";
    verbose(1, "assembling $cmd");
    warnings(sub {
	if (system($cmd)) {
	    mydie($?, $cmd);
	}
    }, $fw);
    return if $o{pbc};         # stop after generating .pbc
    pass4($outfile, $fw);
}

#
# compile and run
# or run byte code
#
sub pass4($$) {
    my $file = shift;
    my $fw = shift;

    if ($o{'compile-pbc'}) {
	die $@ if $@;
	my $cmd;
	$cmd = "$PBC2C $HERE/$file";    # FIXME
	push(@temp_files, $file);
	push(@temp_files, "$filebase.c");
	push(@temp_files, "$filebase$PConfig{o}");
	verbose(1, "compiling $cmd");
	my $c;
	warnings(sub {
	    $c = `$cmd`;
	}, $fw);
	open(C, ">$filebase.c") or die("Can't write '$filebase.c'");
	print C $c;
	close(C);
	my $opt = $o{optimize} ? '-O'.$o{optimize} : '';
	$cmd = "$CD $PConfig{cc} $PConfig{ccflags} $opt ".
	"$PConfig{cg_flag} $PConfig{cc_inc} ".
	"$PConfig{cc_warn} -c $HERE/$filebase.c $PConfig{'cc_o_out'} ".
	"$HERE/$filebase$PConfig{o}";
	verbose(1, "compiling $cmd");
	if (system($cmd)) {
	    mydie($?, $cmd);
	}
	# XXX running --shared needs
	#
	# export LD_LIBRARY_PATH=../../blib/lib
	#
	# in advance
	#
	my $lib = !$o{shared} ? "libparrot$LIB" : '-L blib/lib -lparrot';
	$cmd = "$CD $PConfig{ld} $PConfig{ldflags} ".
	"$PConfig{ld_out} $HERE/$filebase $HERE/$filebase$PConfig{'o'} ".
	"$lib ".
	"$PConfig{libs}";
	verbose(1, "linking $cmd");
	if (system($cmd)) {
	    mydie($?,"Linking");
	}
	$filebase = "./$filebase" if($filebase !~ m!/!); # XXX and unix
	verbose(1, "running $filebase @ARGV");
	if (system("$filebase @ARGV") && !$o{'ignore-exitcode'}) {
	    mydie($?, $filebase);
	}
	unlink($filebase) if (-e $filebase && $o{'rm-exe'});

    }
    else {
	my @opt = map { "-$_" } split(//, $o{'parrot-options'});
	my $cmd = "$PARROT @opt $file @ARGV";
	verbose(1, "running: $cmd");
	if (system($cmd) && !$o{'ignore-exitcode'}) {
	    mydie($?, $cmd);
	}
    }
}
__END__
=head1 NAME

perl6 - perl6 driver program

=head1 SYNOPSIS

perl6 [ p6c-options ] [ imcc-options ] [ asm-options ]
      [ run-options ] [ global-options ] file ...

perl6 --clean *.p6

perl6 --test [testfiles...]

=head1 DESCRIPTION

perl6 calls all the appropriate stages to parse, assemble and run a perl6
source file. As this steps evolve this program will. Or it will get garbage
collect somewhere in the future.

If called with a .imc, .pasm or .pbc file, the appropriate pass(es) will be run.

=head1 OPTIONS

=head2 p6c-options

These options are for the parser P6C and for output generation.

=head2 Output options

=over 4

=item -C,--compile-pbc

Compile to executable and run native. s. also Run options below

=item -B,--pbc

Stop after creating .pbc file.

=item -S,--pasm

Stop after creating .pasm file.

=item -I,--imc

Stop after creating .imc file.

=item --tree

Stop after creating parse tree, doesn't generate .imc output.

=item --raw-tree

Output raw parser tree, additionally to parse tree.

=item --keep-imc --keep-pasm --keep-pbc --keep-c --keep-o --keep-warn --keep-exe

Keep intermediate file.ext. If perl6 stops with an error or with above
options, temp files are always kept.
The last output step (.pmc or executable) is of course kept.

=item -k,--keep-all

Keep all intermediate files.

=item --clean

Unlink all files, perl6 might have generated (s. FILES below), except those
to --keep. E.g.

	perl6 file.p6 --clean --keep-exe

=item --test

Run tests like "make test". As the program startup and parser generation
are done only once, with this option, tests run much faster.

=item --test-parser

Interactive parser-testing mode. The parser enter an interaktive mode, an
empty line sends input to the parser. Additionally this sets --add-main,
so you don't have to provide a sub main().

=item -g,--debug-info

Generate debug info. This adds #line n "file" and source comments to the
.imc file.

=back

=head2 Parse::RecDescent control

=over 4

=item --trace

Set $::RD_TRACE. You know what it is, when you want this.

=item --hitem

Keep track of %item hash.
(only useful when constructing parser)

=item --force-grammar

Rebuild grammar even if it exists.

=item --grammar NAME

Use precompiled grammar NAME (default = Perl6grammar)

=back

=head2 Misc

=over 4

=item --add-main

Suround code by the main() function.

=item --rule NAME

Start with rule NAME (default = 'prog')
(only useful in interactive mode)

=back

=head2 imcc-options

=over 4

=item --debug

Write various debug messages to STDERR.

=item --yydebug

Show bison's debug output

=back

=head2 asm-options

=over 4

=item -E

Preprocess input files and terminate processing.

=item -h,--help

Print this message.

=item -o,--output F

Write output to file F.

=item -c,--checksyntax

Check syntax only, do not generate bytecode.

=back

=head2 run-options

=over 4

=item -q, --quick

Run the .pbc file directly if it does exist and is not older then the
.p6 source file.

=item -R.. --parrot-options=bdhjpPgtv.

pass option(s) to parrot, s. parrot -h

    e.g. "perl6 -Rb. ..."  calls "parrot -b -. ..."

=item --shared

Run against shared dynamic libparrot - you must build it currently manually
in parrot root with:

	cd ../..
	make libparrot.a	# static lib
	make shared		# dynamic lib
	cd -			# back to perl6
	# and set this LD_LIBRARY_PATH
	# as libparrot.so is not installed during testing
	#
	export LD_LIBRARY_PATH=../../blib/lib

=item --ignore-exitcode

don't report non zero exit codes. This is needed e.g. for make test,
when native code is tested.

=item --rm-exe

Remove executables after running. This is useful for testnative.

=back

=head2 global-options

=over 4

=item -h --help

Print this message and exit

=item -v --verbose

Print mesages about compile stages

=item -vv

Be more verbose, print intermediate stages.

=item -V --version

Print versions to STDOUT and exit

=item -w --warnings

Print warnings. If -w is off, warnings are collected in file.warn.

=item -ww

Print diagnostics. N/Y.

=back

=head1 RETURN VALUE

Zero means successful compilation/run.

=for =head1 ERRORS

=head1 EXAMPLES

=over 4

=item perl6 foo.pl

Parse, assemble and run foo.pl, warnings and errors will go to foo.warn.
Intermediate files are foo.*, s. FILES below.

=item echo 'my $a=2; print $a _ "\n"' | perl6 --add-main -vvw

Show inidiviudal steps, display warning, intermediate files are named
a.*.

=item perl6 mops.pasm

Assemble and run mops.pasm.

=back

=head1 ENVIRONMENT

As perl6 is written in perl5, s. perldoc perlrun. No environment vars
are used currently.

=head1 FILES

Perl6 process the following files:

	file.p6 ... perl6 source
	file.imc ... intermediate compiler code
	file.pasm ... parrot assember code
	file.pbc ... parrot byte code

The following files may be generated too:

	file.warn ... various warnings and errors during all stages
	file.tree ... parser tree (--tree)
	file.c
	file.o
	file	 ...  with option -C or
	file.exe      depending on $^O

	file.out  ... perl6 --test result file
	file.test ... perl6 --test Test::Harness input

Additionally the following files are cleaned by --clean

	file.trace	$ ../../parrot -t file.pbc 2> file.trace
	file.diss	$ ../../disassemble file.pbc > file.diss

If STDIN in processed, the filebase "a" will be used.

=head1 SEE ALSO

Have a look at the individual stages:

	P6C  ... perl6 parser, imc generator

	imcc ... intermediate code compiler

	assemble.pl ... parrot assembler

	parrot ... byte code interpreter

=head1 BUGS

Parrot::Config doesn't provide all info needed to run. So there are
some hard coded values at the beginning of the program.

When a intermediate stage dumps core, the message is not in file.warn.

=head1 TODO

- Check for core files, and optionally get bt.
- clean up source file
- more use of Parrot::Config
- use assemble.pl's classes directly
- filter warnings/diagnostics ...
  -Wofile -W/frompat/../topat/ (grep expr)
- --version option for all parts

=head1 AUTHOR

Leopold Ttsch <lt@toetsch.at>

With a lot of help Sean O'Rourke and parts from his prd-perl6.pl.

=cut

# vim: set sw=4:
