Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

How to do perl -c inside perl?

by rockyb (Beadle)
on Aug 28, 2012 at 15:43 UTC ( #990269=perlquestion: print w/ replies, xml ) Need Help??
rockyb has asked for the wisdom of the Perl Monks concerning the following question:

O great monks, I come yet again to drink from the fountain of wisdom.

Again related to this silly debugger Devel::Trepan, I would like to run from inside this perl program perl -c 'code' and sometimes perl -ce 'expression' in order to check validity of various statements and expressions.

This of course works using system() and backtick, but I wonder if there isn't a way inside perl to run a compile check without having to reinvoke perl at the outset. After all, eval() has to go through pretty much the same steps too, and it probably does not use either system or backtick.

Let me finally note that for my purpose using backtick is less code and cleaner to to write than system() with additional code to capture output. I don't want output to be shown. However I have found that backtick sometimes isn't supported well enough on Windows, whereas system() more often is.

Comment on How to do perl -c inside perl?
Re: How to do perl -c inside perl?
by daxim (Chaplain) on Aug 28, 2012 at 15:55 UTC
Re: How to do perl -c inside perl?
by BrowserUk (Pope) on Aug 28, 2012 at 16:04 UTC
    However I have found that backtick sometimes isn't supported well enough on Windows, whereas system() more often is.

    Que? backticks (and qx//) are both fully supported on windows. What makes you think otherwise?

    Eg.:

    C:\test>perl -E"say `perl -c -Mstrict -we\"my \$l = 365.25***3\"` " -e syntax OK

    Of course, Aok from the syntax check doesn't always mean the code does what you expect or want :)


    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".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    RIP Neil Armstrong

    div

      I stand corrected. Checking from Devel::Trepan test t/10test-condition.t, it is fork() followed by exec() that doesn't work on some versions of Strawberry Perl. I believe this is so from past CPANTS failures.

      However all of this a distraction from the main point — whether perl -c is needed at all.

        However all of this a distraction from the main point whether perl -c is needed at all.

        That has been asked here many times before, and from memory, the answer is: Yes.

        Ie. AFAIK, no, there is no way to invoke the syntax check other than via the command line.


        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".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        RIP Neil Armstrong

      Now pass an arbitrary chunk of Perl code to "perl -e" in a portable manner. Capture both STDOUT and STDERR from it. Not so trivial. I suspect I could manage that in relatively few lines of Perl code, but the complexities there are enough that I doubt I would get it completely right on the first try (and many of the details involved are not things I've actually found to be correctly documented).

      - tye        

        Now pass an arbitrary chunk of Perl code to "perl -e" in a portable manner.

        I was only demonstrating that windows supported backticks, not championing the idea of using them and -e as a useful mechanism.

        Capture both STDOUT and STDERR from it. Not so trivial.

        Capturing stderr also is trivial:

        C:\test>perl -E"say `perl -c -Mstrict -we\"my \$l = 365.25*\" 2>&1` " syntax error at -e line 1, at EOF -e had compilation errors.

        But I would have thought feeding the code to a piped-open and checking the exit code would suffice if all that is required is a yay or nay.

        And if you need to actually capture the error messages produced, then this might do the trick:

        #! perl -slw use strict; use Win32::Socketpair qw[ winopen2_5 ]; my( $pid, $sock ) = winopen2_5( 'perl.exe', '-c' ); print $sock <<'EOP'; my $x = 365.25**3; my $y = qx[ perl -c -e"say 'boo'"; ]; my $z = sub { print $sock <<; my $x = 365.25**3; my $y = qx[ perl -c -e"say 'boo'"; ]; my $z = sub { print $sock <<; my $x = 365.25**3; my $y = qx[ perl -c -e"say 'boo'"; ]; my $z = sub { 1; }; }; }; EOP shutdown $sock, 1; print while <$sock>; close $sock; ( $pid, $sock ) = winopen2_5( 'perl.exe', q[-E"say 'hello'; warn; die; +"] ); shutdown $sock, 1; print while <$sock>; close $sock; __END__ C:\test>winopen2_5 - syntax OK Warning: something's wrong at -e line 1. Died at -e line 1. hello

        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".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        RIP Neil Armstrong

        /iblockquote
Re: How to do perl -c inside perl?
by Anonymous Monk on Aug 28, 2012 at 18:12 UTC

      Diving through the (surprising number of) layers, it looks like Test::Compile just does "require Foo" and sees if that fails, rather than actually preventing the code of the module from being run. Though it does run "perl -c" for a non-module file (and doesn't handle Perl code in a string).

      - tye        

Re: How to do perl -c inside perl?
by dave_the_m (Parson) on Aug 28, 2012 at 19:55 UTC
    You might be able to get away with something like:
    for my $code ('$x+$y', '$x+') { printf "code=[%-5s] syntax=%s\n", $code, eval('return 1; ' . $code) ? "ok" : "bad: $@"; }

    But you need to consider the effects of things like BEGIN blocks.

    Dave.

Re: How to do perl -c inside perl?
by philiprbrenan (Monk) on Aug 28, 2012 at 21:22 UTC

    Please prepend 'exit;', eval the string, then check $@ for errors. exit() prevents syntactically correct perl from being executed.

    use feature ":5.14"; use warnings FATAL => qw(all); use strict; use Data::Dump qw(dump pp); my $i = 'exit(); say "Hello" op'; eval $i; say $@;

    Produces

    Bareword found where operator expected at (eval 1) line 1, near ""Hello" op"
    
      exit() prevents syntactically perl from being executed.

      C:\test>perl -E"eval q[ exit(); BEGIN{ system 'echo oops!' }]" oops!

      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".
      In the absence of evidence, opinion is indistinguishable from prejudice.

      RIP Neil Armstrong

        I think what was meant is that exit() sometimes can prevent syntactically (correct) code from being executed. It is also true that sometimes it does not. Human language can be frustratingly ambiguous and imprecise: the quoted statement could have implied sometimes but not all, or it could have been intended to mean all.

        One can gain a few Karma points on PerlMonks here and there by finding mistakes, possibly by a imposing a slightly different or more rigourous interpretation, and possibly attached to side points. Where it to be so easy to reach true Nirvana that way.

        What I have been seeking a deeper understanding what is going on inside Perl and perl -c with the hope to coming to a simpler, more reliable means to test whether a string is a Perl statement or expression. After all, eval() has to go through a syntax check its course its existance. If this question has been asked several times before and the best that had been suggested has been perl-c (which is really not that bad or the end of the world), then I think we can do very small bit better by creating a simple Syntax::Check module. That this might be of help to the broader community is more important to me than the PerlMonks Karma points in correcting someone here or there.

        I am also optimistic that there might (one day) be a way to just ask Perl to do syntax check part that it does for eval() without the evaluation part.

        With all of this behind, it has become clear that yet again, I have not fully explained my situtation and the problem I'm trying to solve.

        I really do want to just check whether something is syntactically correct. No evaluation should be done. Therefore solutions with eval() which can have side effects are probably not good. And devilish kinds of expressions and Perl programs probably also have to be properly handled

        So let me make try to again to explain this in a very specific setting without trying generalize. In contrast to the stock Perl debugger perl5db, Devel::Trepan has a front-end program called trepan.pl that does the setup for Perl debugger invocation. This allows one to specify simple debugger options like whether terminal highlighting is desired. But before trepan.pl takes the plunge into exec to reinvoke Perl with the appropriate flags, it checks to see if the eval string or Perl program is valid. That way it can report back a more reasonable and controllable error message.

        There are a couple of other situations where syntax-only checking is needed. Breakpoints can have conditional expressions associated with them that determine whether to respect or ignore the breakpoint. These expression are evaluated in a context that can be totally different from the context inside the debugger where a programmer specifies what to test for. So an eval inside the debugger of say $a may result in an unbound variable, whereas at the point a breakpoint occurs that variable may be defined and have a value. Similarly, one can ask the debugger to run specific Perl statements in the context of the current stopping point of the program. In gdb terms these are called display expressions. In perl5db, they are called actions.

Re: How to do perl -c inside perl? (op-hook)
by tye (Cardinal) on Aug 31, 2012 at 04:56 UTC

    I just realized that this may be quite easy to implement using existing features. Where 'this' is to run 'eval' in order to check for syntax errors while preventing any code from being run, even if a form of 'BEGIN' is used in the code.

    I believe that there are ways to hook Perl's "run loop". So the steps would be:

    1. fork to get a new Perl interpreter instance (will work even on Windows)
    2. In the child instance, hook the "run loop"
    3. Call "eval $code"
    4. The run loop hook would allow Perl opnodes to execute until the 'eval' op hit
    5. If any other ops try to run after that, die
    6. CORE::exit to destroy the Perl interpreter that might have had some functions defined that we don't want to call by accident

    Unfortunately, I don't know how you hook Perl's run-loop. And there might be complications to overcome when getting into the details of making this work.

    But I can see real value in such a feature.

    Disabling the running of code may be as simple as just defining "sub DB::sub" and "sub DB::DB" (you probably need to put your code that calls eval() into 'package DB' so it wouldn't be subject to the debugging hooks). But you can also look at what Enbugger does to enable debugging or what Devel::NYTProf does to profile opcodes.

    - tye        

      Something along these lines but perhaps simpler has been noted here.

      And as I commented there, I'll be experimenting with these ideas — this wasn't just idle curiosity. The very specific places I would use this are noted in 990598. I'll report back what eventually works.

      Heartfelt thanks to all who have made suggestions.

Re: How to do perl -c inside perl?
by rockyb (Beadle) on Sep 11, 2012 at 01:15 UTC

    The solution that satisfies the most is to wrap the code I want to try inside a eval "sub {$code}".

    Starting with commit 0067b6c, I have been using this approach and have been most pleased with it. It will catch things like prototype mismatches which is not strictly a syntax checking thing. That may be good or bad depending on your needs.

    This code: $x=1; __END__ $y= will be tagged as a syntax error when it is not. But this is not of great concern to me.

      Thats more or less the approach I use in my patched perldb ("IPL") to automatically check for multiline input.

      Is that your use case?

      Sorry I thought you're looking for something more elaborate... :)

      Cheers Rolf

        There were a couple of use cases of which this is one.

        Another use is where you want to write a front-end to call a debugger, profiler, code coverage tool, or anything else that adds some sort of instrumentation (and thus, modules and options to Perl) before runnining it. In this situation, one may want to do a syntax check first before taking the plunge. So being able to correctly handle:

        __END__ $x =
        does matter.

        But in the situation inside the debugger where one needs to be able to check for valid expressions or statements, wrapping inside a sub{ .. } is useful.

        I hadn't thought about using this inside the debugger eval command to automatically figure out if a continuation is needed. So I will probably add that. Thanks!

        It can also be used as a more fool-proof way to determine a source-code line that is shown is complete over the method currently in use by perl5db.pl which is confused by:

        eval " # not a comment ";
        which thinks that the line inside the eval is a comment.

        If "the more or less" code you use is interesting and useful, please expand upon that. Also, I don't understand what you mean by thinking of something "more elaborate". All I was looking for was something to get the job done. If it is interesting, elaborate on what you mean by "more elaborate".

        It's only by having people work out various approaches that we've been able to weight the pros and cons of each and thus understand what the right thing is for particular situations. Thanks.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://990269]
Approved by kcott
Front-paged by tye
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (13)
As of 2014-09-16 13:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (19 votes), past polls