C-TinyCompiler
view release on metacpan or search on metacpan
lib/C/TinyCompiler.pm view on Meta::CPAN
Error: right parenthesis expected in package specification '::Perl::SV(basic,'
Again, these are OK:
$context->apply_packages qw( ::Perl::SV(basic) );
$context->apply_packages '::Perl::SV (basic)';
but this is an error:
$context->apply_packages qw( ::Perl::SV (basic) );
and will complain saying:
Error: package specification cannot start with parenthesis: '(basic)'
Is this supposed to be an option for the previous package?
For more discussion on packages, see L</MANAGING PACKAGES>.
=cut
sub apply_packages {
my ($self, @packages) = @_;
# Run through all the packages and apply them:
PACKAGE: for my $package_spec (@packages) {
# Check for errors:
croak("Error: right parenthesis expected in package specification '$package_spec'")
if ($package_spec =~ /\(/ and $package_spec !~ /\)/);
croak("Error: package specification cannot start with parenthesis: '$package_spec'\n"
. "\tIs this supposed to be an option for the previous package?")
if ($package_spec =~ /^\s*\(/);
# strip spaces
$package_spec =~ s/\s//g;
# Add C::TinyCompiler if it starts with ::
$package_spec = 'C::TinyCompiler' . $package_spec
if index ($package_spec, ':') == 0;
# Pull out the package options:
my @options;
if ($package_spec =~ s/\((.+)\)$//) {
my $options = $1;
@options = split /,/, $options;
}
# Skip if already applied
next PACKAGE if $self->is_package_known($package_spec);
# Pull in the package if it doesn't already exist:
unless ($package_spec->can('apply')) {
# All this mumbo jumbo is used to ensure that we get proper line
# number reporting if the package cannot be use'd.
eval '#line ' . (__LINE__-1) . ' "' . __FILE__ . "\"\nuse $package_spec";
croak($@) if $@;
}
# Make sure we don't have any conflicting packages:
if ($package_spec->conflicts_with($self, keys %{$self->{applied_package}})
or grep {$_->conflicts_with($self, $package_spec)} keys %{$self->{applied_package}}
) {
# If there's a conflict, then mark the package as blocked
$self->block_package($package_spec);
}
else {
# Apply the package, storing the options (for use later under the
# symbol application).
$package_spec->apply($self, @options);
$self->{applied_package}->{$package_spec} = [@options];
}
}
}
=head1 MANAGING PACKAGES
Certain packages require other packages, and some packages do not play nicely
together. The current package management system is not very sophisticated, but
it does provide a means for packages to indicate dependencies and conflicts with
others. In general, all of this should be handled by the packages and manual
intervention from a user should usually not be required.
As far as the compiler is concerned, a package can be in one of three
states: (1) applied, (2) blocked, or (3) unknown. An applied package is any
package that you have applied directly or which has been pulled in as a package
dependency (but which has not been blocked). A blocked package is one that
should should not be applied. An unknown package is one that simply has not
been applied or blocked.
As an illustration of this idea, consider the L<C::TinyCompiler::Perl> package and the
light-weight sub-packages like L<C::TinyCompiler::Perl::Croak>. The light-weight packages
provide a exact subset of L<C::TinyCompiler::Perl>, so if L<C::TinyCompiler::Perl> is loaded, the
sub-packages need to ensure that they do not apply themselves or, if they have
already been applied, that they remove themselves. This check and manipulation
occurs during the sub-packages' call to C<conflicts_with>
=head2 is_package_applied, is_package_blocked, is_package_known
Three simple methods to inquire about the status of a package. These return
boolean values indicating whether the package (1) is currently being applied,
(2) is currently blocked, or (3) is either being applied or blocked.
=cut
sub is_package_applied {
my ($self, $package) = @_;
return exists $self->{applied_package}->{$package};
}
sub is_package_blocked {
my ($self, $package) = @_;
return exists $self->{blocked_package}->{$package};
}
sub is_package_known {
my ($self, $package) = @_;
return ($self->is_package_applied($package)
or $self->is_package_blocked($package));
}
=head2 block_package
Blocks the given package and removes its args from the applied package list if
it was previously applied.
=cut
sub block_package {
my ($self, $package) = @_;
delete $self->{applied_package}->{$package};
$self->{blocked_package}->{$package} = 1;
}
=head2 get_package_args
Returns the array ref containing the package arguments that were supplied when
the package was applied (or an empty array ref if the package was never applied
or has subsequently been blocked). This is the actual array reference, so any
manipulations to this array reference will effect the reference returned in
future calls to C<get_package_args>.
=cut
sub get_package_args {
my ($self, $package) = shift;
return $self->{applied_package}->{$package} || [];
}
=head1 COMPILE METHODS
These are methods related to compiling your source code. Apart from C<compile>,
you need not worry about these methods unless you are trying to create a C::TinyCompiler
package.
=head2 compile
Concatenates the text of the three code sections, jit-compiles them, applies all
symbols from the included packages, and relocates the code so that symbols can
be retrieved. In short, this is the transformative step that converts your code
from ascii into machine.
This step does far more than simply invoke libtcc's compile function. At the
time of writing, tcc only supports a single uncompiled compiler state at a time.
To properly handle this, C::TinyCompiler defers creating the actuall TCCState
object as long as possible. Calling the C<compile> method on your compiler
context actually performs these steps:
=over
=item 1. Create TCCState
An actual TCCState struct is created, to which the following operations are
applied.
=item 2. Apply preprocessor definitions, paths, libraries
All preprocessor defintions, include paths, library paths, and libraries are
added to the compiler state.
=item 3. Invoke preprocessing methods of all C::TinyCompiler packages
Packages can perform preprocessing on the compiler context (and in particular,
the code strings) just before the actual compilation step. This allows them to
dynmically add or remove elements to your code, like source-filters. Or they
could hold off to perform other changes to the compiler context until just
before the compilation step, although this is generally not needed.
=item 4. Code assembly and compilation
The code is assembled and compiled.
=item 5. Apply symbols and relocate the machine code
Symbols (such as dynamically loaded functions) are applied, the final machine
code is relocated, and the memory pages holding that code are marked as
executable.
=back
( run in 3.411 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )