chorankates has asked for the wisdom of the Perl Monks concerning the following question:

i'm trying to use variables in #line directives so that i can pass the proper line/file on. essentially, i've written a wrapper to Test::More, and instead of seeing which line/file the tests fail on, it displays the line in my wrapper library.

short version of what i'm trying:
test.pl
#!/usr/bin/perl -w use strict; use warnings; use lib '.'; use test; my $l = 200; my $ld = 'foo'; #line $l $ld ; test::test(); exit;
test.pm
package test; use strict; use warnings; require Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw(); sub test { my @caller = caller(); print "@caller\n"; print "DBGZ" if 0; } 1;
i'm seeing:
$ perl test.pl main test.pl 13
i want to see:
$ perl test.pl main foo 200

the llama book says: Technically, it matches the pattern /^#\s*line\s+(\d+)\s*(?:\s"(^"+)")?\s*$/, with $1 providing the line number for the next line, and $2 providing the optional filename specified within quotes. (A null filename leaves __FILE__ unchanged.)

making me think this is not possible, but then i see AutoSplit.pm:

#line $lineno "$filename (autosplit into $path)"
can anyone point me in the right direction to allow variables in #line directives? or at least confirm that it is not possible..

Replies are listed 'Best First'.
Re: variable based #line directives?
by Corion (Patriarch) on Aug 20, 2011 at 20:46 UTC

    I think you can do the appropriate faking of #line numbers only through eval. #line directives are only evaluated at compile time of code, so they cannot use variables.

    If you want to wrap/warp Test::More, you want to look at Test::Builder. It also tells you how to skip levels in reporting the error location - see caller.

      thanks very much for suggesting i look at Test::Builder, was able to modify Test::Builder::Level in my wrapping module and i am now getting the correct line/script number.

      just for my edification, can you point me in the direction of some eval #line directive examples? all of the formats i tried before going to Test::Builder did not affect caller() at all. i tried (same code as originally posted, but adding this on line 13 of test.pl):

      • eval "#line $l $ld";
      • eval("#line $l $ld");
      • eval qq{#line $l $ld} or die $!;
      when i tried the last one, i got 'bad file descriptor', which i don't understand either..

        The #line directive takes hold only for the code compiled within the eval string. So you can only "set" the line number by doing

        my $code = <<CODE; #line 200 die "Hello world"; CODE eval $code; warn $@; __END__ Hello world at (eval 1) line 200.
        i got 'bad file descriptor', which i don't understand
        eval returns the value of the last evaluated expression. In your case, there is no expression, so eval returns undef, which triggers die. Use something like
        eval qq{#line $l $ld\n1;} or die "$!";
        $@ is more common (and meaningful) after eval than $! (see perlvar).
Re: variable based #line directives?
by chromatic (Archbishop) on Aug 21, 2011 at 08:24 UTC
    ... or at least confirm that it is not possible..

    It is not possible to use a variable in a #line directive. See S_incline() in toke.c; the function returns unless the first token after the #line directive contains only digits.

      exactly what i needed to stop my unending codesearch.google.com searches, thanks!
Re: variable based #line directives?
by TomDLux (Vicar) on Aug 20, 2011 at 23:00 UTC

    If you have #line 200 foo, it works.

    As Occam said: Entia non sunt multiplicanda praeter necessitatem.

      right, but i want to use variables in my #line directive. the literal version you show works fine, but is not what i am looking for here