Hi there,
I have included a script that I think addresses TODO #32365 --
which was, in short, allow easy shortcuts to build information. The
script generates a file called parrot-config.pbc in the root directory
that can search through build information and shortcuts.
parrot parrot-config.pbc --dump # gives you all the build information
parrot parrot-config.pbc --shortcuts # describes all the shortcuts.
Having a build-* script to generate parrot-config is advantageous
because it allows easy addition of new shortcuts. It should be "easy"
to add new shortcuts that grok the build data in whatever way the user
wants. Also the build script allows all (actually most) shortcuts to be
frozen into .fpmc on disk with build information making quick lookup.
If this patch looks like it satisfies the constraints of TODO 32365, it
should probably be inserted in the main Makefile. Line 696 of that file reads
runtime/parrot/include/config.fpmc : myconfig config_lib.pasm $(TEST_PROG)
@echo Invoking Parrot to generate runtime/parrot/include/config.fpmc
--cross your fingers
./parrot config_lib.pasm
@echo If the next line prints $(VERSION), it did help.
./parrot parrot-config.imc VERSION DEVEL
Could be replaced with
runtime/parrot/include/parrot-config.fpmc : $(???SOME
DIRECTORY???)/build-parrot-config.pl
perl $(???SOME DIRECTORY???)/build-parrot-config.pl
@echo If the next line prints $(VERSION), it did help.
./parrot parrot-config.pbc VERSION DEVEL
One thing I didn't address is what kind of shortcuts folks want. I just
have a couple of example shortcuts in the script.
Let me know what needs to be done to make the script better/more inline
with what was requested in TODO #32365.
Best,Pete
ps: I've included it in this message in case people have a fear of
atmnts.
pss: The current file writes parrot-config-temp rather than
parrot-config so that one does not accidentally destroy parrot-config
during the test period.
===========================================================================
=head1 NAME
build-parrot-config.pl
=head1 SYNOPSIS
This script builds the file parrot-config.pbc in the root build
directory. parrot-config.pbc displays information that was obtained
during build process.
=head1 DESCRIPTION
parrot-config.pbc is a program to access build information from
the command line. The current script automatically generates
parrot-config.pbc. The auto-generation is useful because it allows
and easy, extendible way to add I<shortcuts> to build information.
For example, the build process produces two tags for build
information: B<cc_inc> and B<ld_share_flags> (this information is
obtained during the build process). So to obtain this information from
the command line one would write
$ parrot parrot-config.imc cc_inc ld_share_flags
But suppose one wanted (for whatever reason) to make a
shortcut to these two flags, one could define a shortcut called
B<--my-flag> that would print out the same data as would be printed
from the above command. Instead of above, we could write
$ parrot parrot-config.imc --my-flag
Defining shortcuts is straight forward. There is a hash named
%shortcut which contains all the shortcuts to be included in
parrot-config. An example is shown below
=begin text
my %shortcut = (
"--a", [[$TY_LIT,"SOME TEXT BABY"]],
"--b", shortcut_allkeys( qw{ cc_inc ld_share_flags } ),
"--c",
[[$TY_KEY,"cc_inc"],[$TY_LIT,"with-literal"],[$TY_KEY,"ld_share_flags"]],
"--dump", shortcut_code($dump_sub_code,"Dump all build values"),
"--shortcuts",shortcut_code($shortcut_sub_code,"Write all the shortcuts"),
"--usage",shortcut_code($usage_sub_code,"Write usage information")
);
=end text
We see that the value of shortcut is a list reference. The list may either
contain
=over 4
=item Literal and/or keys list
A list of pairs [TYPE,TEXT]. This is used to include I<literal>s verbatim or
I<keys> are looked up in the existing build data hash (PConfig). There is a
function
called C<shortcut_allkeys> which takes a list of literal keys and generates the
appropriate [$TY_KEY,TEXT] list.
=item Code segment
The result of a call to the subroutine shortcut_code(CODE-BODY,CODE-USAGE) where
CODE-BODY is the body of a parrot subroutine and CODE-USAGE is a one line
description
of the shortcut. The CODE-BODY is written like the normal body of a .pcc_sub
that
has been passed a hash called conf_hash -- which contains the contents of
PConfig and
%shortcut. See code for --dump or --shortcut below for example.
=back
One hopes that with literal,key and code types one can easily grok any
combination
of build data.
XXX The one addition would be to allow arguments to be passed at the command
line
to the subroutines. At some point though one has to worry about overkill :-).
Executing the script leaves only parrot-config.pbc in the root build directory.
See
the config variables below to leave various files in the build directory for
inspection.
parrot-config basically works by opening up a frozen pmc (generated by this
script)
and searching it for build data.
=head1 PROBLEMS
Lots of ugly HERE-DOCS are in this script.
=head1 SEE ALSO
Depends on F<lib/Parrot/Config.pm>.
Generates F<./parrot-config.pbc> and
F<runtime/parrot/include/parrot-config.fpmc>
=head1 AUTHORS
1/2005:
Pete Christopher wrote current script but stole loads of code from
config/gen/config_pm.pl (written by ??) and (the original code for)
parrot-config.imc (written by Leopold Toetsch)
=cut
#########################################
# CONFIGURATION VARIABLES:
# configures this script
#########################################
$this_script_name = 'build-parrot-config.pl';
$fpmc_location = 'runtime/parrot/include/parrot-config.fpmc';
$pconfig_location = 'lib/Parrot/Config.pm';
$output_basename = 'parrot-config-temp';
$leave_fpmc_script = 0; #leave the script that builds the fpmc in ROOT directory
$leave_config_imc_script = 0; #leave $output_basename.imc in ROOT directory
#########################################
# SUBROUTINE DEFS:
# defs for shortcut subroutines
#########################################
$dump_sub_code = <<EOF;
.local pmc iter
new iter, .Iterator, conf_hash
iter = .ITERATE_FROM_START
iter_loop:
unless iter goto iter_end
shift \$S0, iter
print \$S0
print " => '"
\$S1 = conf_hash[\$S0]
print \$S1
print "'\\n"
goto iter_loop
iter_end:
EOF
$shortcut_sub_code = <<EOF;
.local pmc iter
.local string dashdash,str_result
.local int string_type
.local pmc hash_result,undf
.local int hash_type
find_type string_type,"PerlString"
new iter, .Iterator, conf_hash
new undf,.Undef
iter = .ITERATE_FROM_START
dashdash = ""
iter_loop:
unless iter goto iter_end
shift \$S0, iter
length \$I0,\$S0
if \$I0 < 2 goto iter_loop
substr dashdash,\$S0,0,2
unless dashdash == "--" goto iter_loop
print \$S0
print " => "
hash_result = conf_hash[\$S0]
typeof hash_type,hash_result
if hash_type == string_type goto handle_string
str_result = hash_result(undf)
print "SUB: '"
print str_result
print "'"
goto bottom_hash_type_if
handle_string:
print "'"
print hash_result
print "'"
bottom_hash_type_if:
print "\\n"
goto iter_loop
iter_end:
EOF
$usage_sub_code = <<EOF;
print "parrot-config config-key [config-key, ....]\\n"
EOF
#######################################################
# PARROT_CONFIG BODY:
# contains most of the body of the parrot_config script
#######################################################
$parrot_config_script_body = <<EOF;
#+++++++++++++++++++++++++++++++++++++++
#THIS FILE MACHINE GENERATED FROM SCRIPT
# $this_script_name
# Don't modify this file
#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.include "iterator.pasm"
.sub _main [EMAIL PROTECTED]
.param pmc argv
.local int argc
.local pmc conf_hash
.local pmc hash_result
.local string key
.local int i,fail
.local int string_type,hash_type
#fetch the frozen pmc hash
conf_hash = _config()
argc = argv
if argc >= 2 goto argc_good
#call usage
hash_result = conf_hash["--usage"]
unless hash_result goto usage_botched
typeof hash_type,hash_result
find_type \$I0,"Sub"
unless hash_type == \$I0 goto usage_botched
hash_result(conf_hash)
exit 1
usage_botched:
printerr "INTERNAL ERROR: No --usage sub defined\\n"
printerr "Anyway you must have at least 2 args to this program\\n"
exit 1
argc_good:
#set string type
#XXX when a switch from PerlString String is made,
# must change this to "String"
find_type string_type,"PerlString"
# Check that the keys are defined
i = 1
fail = 0
loop1:
#do
key = argv[i]
\$I0 = defined conf_hash[key]
if \$I0 goto found1
print " no such key: '"
print key
print "'\\n"
set fail,1
found1:
inc i
if i < argc goto loop1
#endloop
if fail == 0 goto nofail
exit 1
nofail:
i = 1
loop2:
key = argv[i]
hash_result = conf_hash[key]
typeof hash_type,hash_result
if hash_type == string_type goto handle_string
hash_result(conf_hash)
goto bottom_loop2
handle_string:
print hash_result
bottom_loop2:
inc i
if i < argc goto loop2
print "\\n"
end
.end
.pcc_sub _config
.local pmc CONF
# XXX: this works only if parrot is run from its root directory
.const string conf_file = "$fpmc_location"
open CONF, conf_file, "<"
\$I0 = defined CONF
if \$I0 goto ok1
printerr "Can't read '"
printerr conf_file
printerr "': "
err \$S0
printerr \$S0
printerr "\\n"
exit 1
ok1:
.local string image
# If it gets above 64k, we've got bigger problems.
read image, CONF, 60000
close CONF
.local pmc conf_hash
thaw conf_hash, image
# XXX hash should probably be marked read-only...
#HERE WE GO AND FILL IN THE subs from the hash table
.local pmc glb
#START MACHINE GENERATED
<<ADD-SUBROUTINES-TO-HASH>>
#END MACHINE GENERATED
.pcc_begin_return
.return conf_hash
.pcc_end_return
miserable_fail:
printerr "Failed to find a subroutine: probably messed up\\n"
printerr "parrot-config-build.pl.\\n"
end
.end
#START MACHINE GENERATED
<<ADD-SUBROUTINE-BODIES>>
#END MACHINE GENERATED
EOF
##################################
# GENERATE FROZEN PMC SCRIPT BODY
##################################
$gen_frozen_pmc_script_body = <<EOF;
new P0, .PerlHash
new P1, .PerlUndef
<<HERE>>
# XXX: this works only if parrot is run from its root directory
open P1, "$fpmc_location", ">"
freeze S0, P0
print P1, S0
close P1
end
EOF
#########################################
# Define some (internal) global vars
#########################################
my ($TY_KEY,$TY_LIT,$TY_CODE) = (0,1,2);
my $code_data_shortcut = 0;
my %shortcut = (
"--a", [[$TY_LIT,"SOME TEXT BABY"]],
"--b", shortcut_allkeys( qw{ cc_inc ld_share_flags } ),
"--c",
[[$TY_KEY,"cc_inc"],[$TY_LIT,"with-literal"],[$TY_KEY,"ld_share_flags"]],
"--dump", shortcut_code($dump_sub_code,"Dump all build values"),
"--shortcuts",shortcut_code($shortcut_sub_code,"Write all the shortcuts"),
"--usage",shortcut_code($usage_sub_code,"Write usage information")
);
#########################################
# INTERNAL SUBS:
# Subs that do various things
#########################################
sub error_to_many_in_code {
my $flag = shift;
my $m = "Can only have one CODE object for flag $flag";
return $m;
}
#This just fetches the PConfig dump from Config.pm
#puts the result into global namespace.
#XXX probably more elegant way to do this, but
# I'm not very knowledgeable about perl.
sub fetch_PConfig {
my $fn = $pconfig_location;
my (@lines,$i,$j,$buffer);
open(IN,$fn) or die;
@lines = <IN>;
close(IN);
for($i=0; $i<$#lines; $i++){
$_ = $lines[$i];
last if /%PConfig = \(/;
}
$buffer = join('',@lines[$i .. $#lines]);
return eval $buffer;
}
sub proc_shortcut {
my $add_subs_to_hash = "";
my $next_sub_label = 0;
my $add_to_sub_def = "";
while( ($flag,$v) = each %shortcut ){
if($v->[0][0] == $TY_CODE){
#Handle code
die error_to_many_in_code($flag) unless @$v == 1;
my $sub_name = "_proc_shortcut_sub_" . $next_sub_label++;
my $code_body = $v->[0][1];
my $usage_line = $v->[0][2];
$add_subs_to_hash .= <<EOF;
find_global glb,"$sub_name"
unless glb,miserable_failiure
conf_hash["$flag"] = glb
EOF
$add_to_sub_def .= <<EOF;
.pcc_sub $sub_name
.param pmc conf_hash
.const string __usage_data = "$usage_line"
if conf_hash goto [EMAIL PROTECTED]
.return(__usage_data)
[EMAIL PROTECTED]:
$code_body
.return(S0) #don't use this value
.end
EOF
next;
}
#Ok must be a normal KEY,LIT list
my $buff = "";
for $e (@$v){
my $add;
my @elst = @$e;
if($elst[0] == $TY_KEY){
$add = $PConfig{$elst[1]};
die "Unkown key '$elst[1]' in shortcut" unless $add;
$buff .= " " . $add . " ";
}
elsif($elst[0] == $TY_LIT){
$add = $elst[1];
$buff .= " " . $add . " ";
}
elsif($elst[0] == $TY_CODE){
die error_to_many_in_code($flag) unless @$v == 1;
}
else {
die "Unhandled type in proc_shortcut";
}
}
$buff =~ s/[ ]+/ /g; #This could ass your $TY_LIT's, but I like single
spaces.
$PConfig{$flag} = $buff;
}
if($add_subs_to_hash){
$code_data_shortcut = [$add_subs_to_hash,$add_to_sub_def];
}
}
sub shortcut_code {
die "shortcut_code must have exaclty 2 args" unless @_ == 2;
my ($c,$u) = @_;
return [[$TY_CODE,$c,$u]];
}
sub shortcut_allkeys {
my $r = [];
for $s (@_){
push(@$r,[$TY_KEY,$s]);
}
return $r;
}
sub gen_frozen_pmc {
my ($k,$i,$buff);
my $random_name = $output_basename . "_fpmc_script.pasm";
my @gen_pmc_in = split(/\n/,$gen_frozen_pmc_script_body);
$buff = "";
for($i=0;$i<@gen_pmc_in; $i++){
$_ = $gen_pmc_in[$i];
if(/<<HERE>>/){
my @lst = sort { lc $a cmp lc $b || $a cmp $b } keys(%PConfig);
my $t = keys %PConfig;
for $k (@lst) {
my $v=$PConfig{$k};
if(defined $v) {
$v =~ s/(["\\])/\\$1/g; # "
$v =~ s/\n/\\n/g;
$buff .= qq(\tset P0["$k"], "$v"\n);
}
else {
$buff .= qq(\tset P0["$k"], P1\n);
}
}
}
else {
$buff .= $_ . "\n";
}
}
open(OUT,">" . $random_name) or die "Failed to open " . $random_name;
print OUT "$buff\n";
close(OUT);
system("parrot $random_name");
my $status = $?;
system("rm $random_name") unless $leave_fpmc_script;
die "Failed to compile parrot-config.fpmc" if $status != 0;
}
sub write_parrot_config {
open(OUT,">" . $output_basename . '.imc') or die;
if($code_data_shortcut){
my $add_subs_to_hash = $code_data_shortcut->[0];
my $add_to_sub_def = $code_data_shortcut->[1];
$parrot_config_script_body =~
s/<<ADD-SUBROUTINES-TO-HASH>>/$add_subs_to_hash/;
$parrot_config_script_body =~ s/<<ADD-SUBROUTINE-BODIES>>/$add_to_sub_def/;
}
else {
$parrot_config_script_body =~ s/<<ADD-SUBROUTINES-TO-HASH>>//;
$parrot_config_script_body =~ s/<<ADD-SUBROUTINE-BODIES>>//;
}
print OUT "$parrot_config_script_body\n";
close(OUT);
system("parrot -o $output_basename.pbc $output_basename.imc");
die "Failed to compile $output_basename.pbc" if $? != 0;
system("rm $output_basename.imc") unless $leave_config_imc_script;
}
sub main {
#go and fetch configuration data
fetch_PConfig();
proc_shortcut();
gen_frozen_pmc();
write_parrot_config();
}
#call main
main();
=head1 NAME
build-parrot-config.pl
=head1 SYNOPSIS
This script builds the file parrot-config.pbc in the root build
directory. parrot-config.pbc displays information that was obtained
during build process.
=head1 DESCRIPTION
parrot-config.pbc is a program to access build information from
the command line. The current script automatically generates
parrot-config.pbc. The auto-generation is useful because it allows
and easy, extendible way to add I<shortcuts> to build information.
For example, the build process produces two tags for build
information: B<cc_inc> and B<ld_share_flags> (this information is
obtained during the build process). So to obtain this information from
the command line one would write
$ parrot parrot-config.imc cc_inc ld_share_flags
But suppose one wanted (for whatever reason) to make a
shortcut to these two flags, one could define a shortcut called
B<--my-flag> that would print out the same data as would be printed
from the above command. Instead of above, we could write
$ parrot parrot-config.imc --my-flag
Defining shortcuts is straight forward. There is a hash named
%shortcut which contains all the shortcuts to be included in
parrot-config. An example is shown below
=begin text
my %shortcut = (
"--a", [[$TY_LIT,"SOME TEXT BABY"]],
"--b", shortcut_allkeys( qw{ cc_inc ld_share_flags } ),
"--c",
[[$TY_KEY,"cc_inc"],[$TY_LIT,"with-literal"],[$TY_KEY,"ld_share_flags"]],
"--dump", shortcut_code($dump_sub_code,"Dump all build values"),
"--shortcuts",shortcut_code($shortcut_sub_code,"Write all the shortcuts"),
"--usage",shortcut_code($usage_sub_code,"Write usage information")
);
=end text
We see that the value of shortcut is a list reference. The list may either
contain
=over 4
=item Literal and/or keys list
A list of pairs [TYPE,TEXT]. This is used to include I<literal>s verbatim or
I<keys> are looked up in the existing build data hash (PConfig). There is a
function
called C<shortcut_allkeys> which takes a list of literal keys and generates the
appropriate [$TY_KEY,TEXT] list.
=item Code segment
The result of a call to the subroutine shortcut_code(CODE-BODY,CODE-USAGE) where
CODE-BODY is the body of a parrot subroutine and CODE-USAGE is a one line
description
of the shortcut. The CODE-BODY is written like the normal body of a .pcc_sub
that
has been passed a hash called conf_hash -- which contains the contents of
PConfig and
%shortcut. See code for --dump or --shortcut below for example.
=back
One hopes that with literal,key and code types one can easily grok any
combination
of build data.
XXX The one addition would be to allow arguments to be passed at the command
line
to the subroutines. At some point though one has to worry about overkill :-).
Executing the script leaves only parrot-config.pbc in the root build directory.
See
the config variables below to leave various files in the build directory for
inspection.
parrot-config basically works by opening up a frozen pmc (generated by this
script)
and searching it for build data.
=head1 PROBLEMS
Lots of ugly HERE-DOCS are in this script.
=head1 SEE ALSO
Depends on F<lib/Parrot/Config.pm>.
Generates F<./parrot-config.pbc> and
F<runtime/parrot/include/parrot-config.fpmc>
=head1 AUTHORS
1/2005:
Pete Christopher wrote current script but stole loads of code from
config/gen/config_pm.pl (written by ??) and (the original code for)
parrot-config.imc (written by Leopold Toetsch)
=cut
#########################################
# CONFIGURATION VARIABLES:
# configures this script
#########################################
$this_script_name = 'build-parrot-config.pl';
$fpmc_location = 'runtime/parrot/include/parrot-config.fpmc';
$pconfig_location = 'lib/Parrot/Config.pm';
$output_basename = 'parrot-config-temp';
$leave_fpmc_script = 0; #leave the script that builds the fpmc in ROOT directory
$leave_config_imc_script = 0; #leave $output_basename.imc in ROOT directory
#########################################
# SUBROUTINE DEFS:
# defs for shortcut subroutines
#########################################
$dump_sub_code = <<EOF;
.local pmc iter
new iter, .Iterator, conf_hash
iter = .ITERATE_FROM_START
iter_loop:
unless iter goto iter_end
shift \$S0, iter
print \$S0
print " => '"
\$S1 = conf_hash[\$S0]
print \$S1
print "'\\n"
goto iter_loop
iter_end:
EOF
$shortcut_sub_code = <<EOF;
.local pmc iter
.local string dashdash,str_result
.local int string_type
.local pmc hash_result,undf
.local int hash_type
find_type string_type,"PerlString"
new iter, .Iterator, conf_hash
new undf,.Undef
iter = .ITERATE_FROM_START
dashdash = ""
iter_loop:
unless iter goto iter_end
shift \$S0, iter
length \$I0,\$S0
if \$I0 < 2 goto iter_loop
substr dashdash,\$S0,0,2
unless dashdash == "--" goto iter_loop
print \$S0
print " => "
hash_result = conf_hash[\$S0]
typeof hash_type,hash_result
if hash_type == string_type goto handle_string
str_result = hash_result(undf)
print "SUB: '"
print str_result
print "'"
goto bottom_hash_type_if
handle_string:
print "'"
print hash_result
print "'"
bottom_hash_type_if:
print "\\n"
goto iter_loop
iter_end:
EOF
$usage_sub_code = <<EOF;
print "parrot-config config-key [config-key, ....]\\n"
EOF
#######################################################
# PARROT_CONFIG BODY:
# contains most of the body of the parrot_config script
#######################################################
$parrot_config_script_body = <<EOF;
#+++++++++++++++++++++++++++++++++++++++
#THIS FILE MACHINE GENERATED FROM SCRIPT
# $this_script_name
# Don't modify this file
#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.include "iterator.pasm"
.sub _main [EMAIL PROTECTED]
.param pmc argv
.local int argc
.local pmc conf_hash
.local pmc hash_result
.local string key
.local int i,fail
.local int string_type,hash_type
#fetch the frozen pmc hash
conf_hash = _config()
argc = argv
if argc >= 2 goto argc_good
#call usage
hash_result = conf_hash["--usage"]
unless hash_result goto usage_botched
typeof hash_type,hash_result
find_type \$I0,"Sub"
unless hash_type == \$I0 goto usage_botched
hash_result(conf_hash)
exit 1
usage_botched:
printerr "INTERNAL ERROR: No --usage sub defined\\n"
printerr "Anyway you must have at least 2 args to this program\\n"
exit 1
argc_good:
#set string type
#XXX when a switch from PerlString String is made,
# must change this to "String"
find_type string_type,"PerlString"
# Check that the keys are defined
i = 1
fail = 0
loop1:
#do
key = argv[i]
\$I0 = defined conf_hash[key]
if \$I0 goto found1
print " no such key: '"
print key
print "'\\n"
set fail,1
found1:
inc i
if i < argc goto loop1
#endloop
if fail == 0 goto nofail
exit 1
nofail:
i = 1
loop2:
key = argv[i]
hash_result = conf_hash[key]
typeof hash_type,hash_result
if hash_type == string_type goto handle_string
hash_result(conf_hash)
goto bottom_loop2
handle_string:
print hash_result
bottom_loop2:
inc i
if i < argc goto loop2
print "\\n"
end
.end
.pcc_sub _config
.local pmc CONF
# XXX: this works only if parrot is run from its root directory
.const string conf_file = "$fpmc_location"
open CONF, conf_file, "<"
\$I0 = defined CONF
if \$I0 goto ok1
printerr "Can't read '"
printerr conf_file
printerr "': "
err \$S0
printerr \$S0
printerr "\\n"
exit 1
ok1:
.local string image
# If it gets above 64k, we've got bigger problems.
read image, CONF, 60000
close CONF
.local pmc conf_hash
thaw conf_hash, image
# XXX hash should probably be marked read-only...
#HERE WE GO AND FILL IN THE subs from the hash table
.local pmc glb
#START MACHINE GENERATED
<<ADD-SUBROUTINES-TO-HASH>>
#END MACHINE GENERATED
.pcc_begin_return
.return conf_hash
.pcc_end_return
miserable_fail:
printerr "Failed to find a subroutine: probably messed up\\n"
printerr "parrot-config-build.pl.\\n"
end
.end
#START MACHINE GENERATED
<<ADD-SUBROUTINE-BODIES>>
#END MACHINE GENERATED
EOF
##################################
# GENERATE FROZEN PMC SCRIPT BODY
##################################
$gen_frozen_pmc_script_body = <<EOF;
new P0, .PerlHash
new P1, .PerlUndef
<<HERE>>
# XXX: this works only if parrot is run from its root directory
open P1, "$fpmc_location", ">"
freeze S0, P0
print P1, S0
close P1
end
EOF
#########################################
# Define some (internal) global vars
#########################################
my ($TY_KEY,$TY_LIT,$TY_CODE) = (0,1,2);
my $code_data_shortcut = 0;
my %shortcut = (
"--a", [[$TY_LIT,"SOME TEXT BABY"]],
"--b", shortcut_allkeys( qw{ cc_inc ld_share_flags } ),
"--c",
[[$TY_KEY,"cc_inc"],[$TY_LIT,"with-literal"],[$TY_KEY,"ld_share_flags"]],
"--dump", shortcut_code($dump_sub_code,"Dump all build values"),
"--shortcuts",shortcut_code($shortcut_sub_code,"Write all the shortcuts"),
"--usage",shortcut_code($usage_sub_code,"Write usage information")
);
#########################################
# INTERNAL SUBS:
# Subs that do various things
#########################################
sub error_to_many_in_code {
my $flag = shift;
my $m = "Can only have one CODE object for flag $flag";
return $m;
}
#This just fetches the PConfig dump from Config.pm
#puts the result into global namespace.
#XXX probably more elegant way to do this, but
# I'm not very knowledgeable about perl.
sub fetch_PConfig {
my $fn = $pconfig_location;
my (@lines,$i,$j,$buffer);
open(IN,$fn) or die;
@lines = <IN>;
close(IN);
for($i=0; $i<$#lines; $i++){
$_ = $lines[$i];
last if /%PConfig = \(/;
}
$buffer = join('',@lines[$i .. $#lines]);
return eval $buffer;
}
sub proc_shortcut {
my $add_subs_to_hash = "";
my $next_sub_label = 0;
my $add_to_sub_def = "";
while( ($flag,$v) = each %shortcut ){
if($v->[0][0] == $TY_CODE){
#Handle code
die error_to_many_in_code($flag) unless @$v == 1;
my $sub_name = "_proc_shortcut_sub_" . $next_sub_label++;
my $code_body = $v->[0][1];
my $usage_line = $v->[0][2];
$add_subs_to_hash .= <<EOF;
find_global glb,"$sub_name"
unless glb,miserable_failiure
conf_hash["$flag"] = glb
EOF
$add_to_sub_def .= <<EOF;
.pcc_sub $sub_name
.param pmc conf_hash
.const string __usage_data = "$usage_line"
if conf_hash goto [EMAIL PROTECTED]
.return(__usage_data)
[EMAIL PROTECTED]:
$code_body
.return(S0) #don't use this value
.end
EOF
next;
}
#Ok must be a normal KEY,LIT list
my $buff = "";
for $e (@$v){
my $add;
my @elst = @$e;
if($elst[0] == $TY_KEY){
$add = $PConfig{$elst[1]};
die "Unkown key '$elst[1]' in shortcut" unless $add;
$buff .= " " . $add . " ";
}
elsif($elst[0] == $TY_LIT){
$add = $elst[1];
$buff .= " " . $add . " ";
}
elsif($elst[0] == $TY_CODE){
die error_to_many_in_code($flag) unless @$v == 1;
}
else {
die "Unhandled type in proc_shortcut";
}
}
$buff =~ s/[ ]+/ /g; #This could ass your $TY_LIT's, but I like single
spaces.
$PConfig{$flag} = $buff;
}
if($add_subs_to_hash){
$code_data_shortcut = [$add_subs_to_hash,$add_to_sub_def];
}
}
sub shortcut_code {
die "shortcut_code must have exaclty 2 args" unless @_ == 2;
my ($c,$u) = @_;
return [[$TY_CODE,$c,$u]];
}
sub shortcut_allkeys {
my $r = [];
for $s (@_){
push(@$r,[$TY_KEY,$s]);
}
return $r;
}
sub gen_frozen_pmc {
my ($k,$i,$buff);
my $random_name = $output_basename . "_fpmc_script.pasm";
my @gen_pmc_in = split(/\n/,$gen_frozen_pmc_script_body);
$buff = "";
for($i=0;$i<@gen_pmc_in; $i++){
$_ = $gen_pmc_in[$i];
if(/<<HERE>>/){
my @lst = sort { lc $a cmp lc $b || $a cmp $b } keys(%PConfig);
my $t = keys %PConfig;
for $k (@lst) {
my $v=$PConfig{$k};
if(defined $v) {
$v =~ s/(["\\])/\\$1/g; # "
$v =~ s/\n/\\n/g;
$buff .= qq(\tset P0["$k"], "$v"\n);
}
else {
$buff .= qq(\tset P0["$k"], P1\n);
}
}
}
else {
$buff .= $_ . "\n";
}
}
open(OUT,">" . $random_name) or die "Failed to open " . $random_name;
print OUT "$buff\n";
close(OUT);
system("parrot $random_name");
my $status = $?;
system("rm $random_name") unless $leave_fpmc_script;
die "Failed to compile parrot-config.fpmc" if $status != 0;
}
sub write_parrot_config {
open(OUT,">" . $output_basename . '.imc') or die;
if($code_data_shortcut){
my $add_subs_to_hash = $code_data_shortcut->[0];
my $add_to_sub_def = $code_data_shortcut->[1];
$parrot_config_script_body =~
s/<<ADD-SUBROUTINES-TO-HASH>>/$add_subs_to_hash/;
$parrot_config_script_body =~ s/<<ADD-SUBROUTINE-BODIES>>/$add_to_sub_def/;
}
else {
$parrot_config_script_body =~ s/<<ADD-SUBROUTINES-TO-HASH>>//;
$parrot_config_script_body =~ s/<<ADD-SUBROUTINE-BODIES>>//;
}
print OUT "$parrot_config_script_body\n";
close(OUT);
system("parrot -o $output_basename.pbc $output_basename.imc");
die "Failed to compile $output_basename.pbc" if $? != 0;
system("rm $output_basename.imc") unless $leave_config_imc_script;
}
sub main {
#go and fetch configuration data
fetch_PConfig();
proc_shortcut();
gen_frozen_pmc();
write_parrot_config();
}
#call main
main();