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

I am writing a multipass compiler that is internateralized, and sometimes I need to warn the user about things that I did not notice in the first pass. The first pass parses the program and converts it to an intermediate representation (which has refrences to the file name and line number so I know where to point fingers). but I would like to use the internal warning mechinism to warn with the input line and file. I have tried setting $. and $ARGV, but the magic is not triggered. Does anyone know what I missed? Asside from reimplementation?

Replies are listed 'Best First'.
Re: Here there be cammels!
by BrowserUk (Patriarch) on Feb 28, 2015 at 22:31 UTC
    I have tried setting $. and $ARGV,

    If you are retaining enough information to be able to set $. and $ARGV, you have enough information to add:

    my $place = " at $file line $line"; ... print ....., $place;

    Expending energies to trick the system into producing something so simple on your behalf is a waste of time.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
    In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
Re: Here there be camels!
by LanX (Saint) on Feb 28, 2015 at 22:01 UTC
    A bit cryptic, I need to guess what you mean.

    You want to throw warnings, but with different line number and file reported?

    update

    I think there should be more straight forward methods, but neither warn nor Carp mention "line".

    So, here a hack, till someone comes with something cleaner.

    sub warn_from { my ($line,$file,$text) =@_; eval <<"__CODE__"; #line $line $file; warn \$text; __CODE__ } warn_from(42,'captain.pl', "I say what!");
    -->
    /usr/bin/perl -w /home/lanx/warn_new.pl I say what! at captain.pl; line 42.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)

    PS: Je suis Charlie!

      if you do this:
      foreach(<>){ warn $_; }
      you get <text> at dummy.pl line 5, <> line 6 I want to do that.
Re: Here there be cammels!
by AppleFritter (Vicar) on Feb 28, 2015 at 22:09 UTC

    Howdy, and welcome to the Monastery!

    Perl's internal warning mechanism only relates to the code that Perl is executing, i.e. your script, and (probably) cannot be repurposed for the code your compiler will be processing. You'll have to roll your own, or look at CPAN for suitable modules. (Other monks may be able to provide pointers.)

Re: Here there be cammels!
by Anonymous Monk on Feb 28, 2015 at 22:19 UTC
      #line is fun I paticularly like it in embeded scripts, but I want both line numbers.
      #!/bin/bash lineno=$LINENO;perl='#line '"$LINENO"' "'"$0"'" warn 'error'; ' perl -e "$perl"
        please reap, nonsense.
Re: Here there be cammels!
by Anonymous Monk on Feb 28, 2015 at 22:39 UTC

    You can get a more customizable effect via %SIG handlers. A quick proof-of-concept:

    use IO::Handle; my $filename = "/etc/passwd"; open my $fh, '<', $filename or die $!; my $customerr = sub { my $msg = shift; $msg =~ s/\.?\s*$//; return "$msg ($filename line ".$fh->input_line_number.")\n"; }; local $SIG{__WARN__} = sub { warn $customerr->(shift) }; local $SIG{__DIE__} = sub { die $customerr->(shift) }; while (<$fh>) { warn "BEEP!" if /root/; die "ACK!" if /nobody/; } close $fh; __END__ BEEP! at - line 12, <$fh> line 1 (/etc/passwd line 1) ACK! at - line 13, <$fh> line 7 (/etc/passwd line 7)

    It may be a little more work than using Perl's built-in mechanisms, but it works great in other cases too - for example if you're going over the rows of a spreadsheet, you can include the row number in the error message.

Re: Here there be cammels!
by Anonymous Monk on Feb 28, 2015 at 23:36 UTC

    Apparently the extra "<$fh> line X" message is added by Perl_mess_sv in util.c and is based on PL_last_in_gv. Apparently that is only set by readline, tell, eof and seek. If the file you want to report the line numbers on is closed, it doesn't seem like trying to trick/hack Perl into generating that extra message for you is worth it, and it's much cleaner to implement a message yourself.

      Furthermore does readline depend on the chunk-size determined of the input-record-separator $/

      The only possibility to fake this is to reopen and reread line by line.

      I have no idea how seek could be able to set $. without lots of magic.

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)

      PS: Je suis Charlie!

        I have no idea how seek could be able to set $. without lots of magic.

        It doesn't update $. itself; it does update PL_last_in_gv.

        open my $fa, '<', '/etc/passwd' or die $!; open my $fb, '<', '/etc/group' or die $!; <$fa>; $.=9; <$fa>; warn "One"; <$fb>; $.=17; <$fb>; warn "Two"; seek $fa,256,1; warn "Three"; seek $fb,256,1; warn "Four"; <$fa>; warn "Five"; <$fb>; warn "Six"; __END__ One at - line 3, <$fa> line 10. Two at - line 4, <$fb> line 18. Three at - line 5, <$fa> line 10. Four at - line 6, <$fb> line 18. Five at - line 7, <$fa> line 11. Six at - line 8, <$fb> line 19.

        See pp_sysseek in pp_sys.c.

Re: Here there be cammels!
by Anonymous Monk on Feb 28, 2015 at 23:46 UTC
    I have tried setting $.

    Interestingly:

    while (<DATA>) { chomp; warn "<$_>"; } warn "One"; $. = 123; warn "Two"; close DATA; warn "Three"; $. = 456; warn "Four"; __DATA__ Zero

    Gives:

    <Zero> at - line 1, <DATA> line 1. One at - line 2, <DATA> line 1. Two at - line 4, <DATA> line 123. Three at - line 6. Four at - line 8, <DATA> line 456.

    And yet, it's a hack. Better to implement the message yourself.

      > And yet, it's a hack.

      Looks like a bug for me, though DATA is closed it's reported at FOUR.

      Only b/c a line-number is set.

      > Better to implement the message yourself.

      Well, yeah, undocumented behavior. :)

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)

      PS: Je suis Charlie!

        I do not think is a bug: is a edge case of use of very particular features...
        diamond <> never close the handle and __DATA__ is very near to be $0 in this case (if i remember you can seek it and print the main program too). Because you can adjust $. and you had not closed DATA handle you end with the beahviour observed.
        from perldata
        Text after __DATA__ may be read via the filehandle PACKNAME::DATA , where PACKNAME is the package that was current when the __DATA__ token was encountered. The filehandle is left open pointing to the line after __DATA__. The program should close DATA when it is done reading from it.
        
        PS. thanks for the line directive hint: never eard about..
        L*

        There are no rules, there are no thumbs..
        Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.