C-TinyCompiler
view release on metacpan or search on metacpan
lib/C/TinyCompiler.pm view on Meta::CPAN
If you have a compiler error, line numbers will be meaningless if you do not
tell the compiler the line on which the code is run. To do this properly, use
L</line_number>, discussed below.
working here - note that warnings are not issued for changing code values after
the compilation phase, but such changes can have no effect.
=cut
# Valid locations are defined in %is_valid_location, created near the
# constructor.
sub code :lvalue {
my ($self, $location) = @_;
# Canonicalize the location:
$location = ucfirst lc $location;
# Make sure they supplied a meaningful location:
croak("Unknown location $location; must be one of "
. join(', ', keys %is_valid_location))
unless exists $is_valid_location{$location};
$self->{$location};
}
=head2 line_number
Build a line number directive for you. Use like so:
$context->code('Body') .= C::TinyCompiler::line_number(__LINE__) . q{
void test_func (void) {
printf("Success!\n");
}
};
Suppose you have an error in your code and did not use this (or some other
means) for indicating your line numbers. The offending code could be
$context->code('Body') .= q{
void test_func (void {
printf("Success!\n");
}
};
which, you will notice, forgets to close the parenthesis in the function
definition. This will raise an error that would look like this:
Unable to compile at Body line 2: parameter declared as void
Although it tells you the section in which the error occurred, if you have a
complex script that adds code in many places, you may have no idea where to find
offending addition in your Perl code. Fortunately, C (and Perl) allows
you to give hints to the compiler using a C<#line> directive, which is made even
easier with this function. Without C<line_number>, you would say something like:
$context->code('Body') .= "\n#line " . (__LINE__+1) . ' "' . __FILE__ . q{"
... code goes here ...
};
and then your error reporting would say where the error occurred with respect to
the line in your script. That formula is long-winded and error prone, so you can
use this useful bit of shorthand instead:
$context->code('Body') .= C::TinyCompiler::line_number(__LINE__) . q{
... code goes here ...
};
Still not awesome, but at least a little better.
=cut
sub line_number {
my ($line) = @_;
# The line needs to be incremented by one for the bookkeeping to work
$line++;
# Get the source filename using caller()
my (undef, $filename) = caller;
# Escape backslashes:
$filename =~ s/\\/\\\\/g;
return "\n#line $line \"$filename\"";
}
=head2 apply_packages
Adds the given packages to this compiler context. The names should be the name
of the Perl package that has the functions expected by the C::TinyCompiler
package mechanisms:
$context->apply_packages qw(C::TinyCompiler::Perl::SV C::TinyCompiler::Perl::AV);
The C<C::TinyCompiler> is optional, so this is equivalent to:
$context->apply_packages qw(::Perl::SV ::Perl::AV);
Options are package-specific strings and should be specified after the
package name and enclosed by parentheses:
$context->apply_packages qw(::Perl::SV(most) ::Perl::AV(basic))
You can call this function multiple times with different package names. However,
a package will only be applied once, even if you specify different package
options. Thus, the following will not work:
$context->apply_packages '::Perl::SV(basic)';
$context->apply_packages '::Perl::SV(refs)';
Instead, you should combine these options like so:
$context->apply_packages '::Perl::SV(basic, refs)';
B<Note> that you can put spaces between the package name, the parentheses, and
the comma-delimited options, but C<qw()> will not do what you mean in that case.
In other words, this could trip you up:
$context->apply_packages qw( ::Perl::SV(basic, refs) );
and it will issue a warning resembling this:
Error: right parenthesis expected in package specification '::Perl::SV(basic,'
Again, these are OK:
( run in 0.558 second using v1.01-cache-2.11-cpan-bbcb1afb8fc )