in reply to Syntax Error Checking

The only way I'm aware of to compile but not execute code in a variable is to wrap it in an anonymous subroutine block:
my $goodcode = <<'CODE'; print "Hello, how are you?\n" CODE my $badcode = <<'CODE'; pront "Hello, how are you\n?' CODE { no strict; local $^W = 0; eval "sub {\n$goodcode\n}"; } print "Goodcode error: $@\n" if $@; { no strict; local $^W = 0; eval "sub {\n$badcode\n}"; } print "Badcode error: $@\n" if $@;
You can get more elaborate if you like, writing your own warning handler to capture them instead of printing them. It's late and I shouldn't be posting.

Oh, and the newlines are in there in case you have comments somewhere in your code string. I did once, and it commented out the ending brace of the sub. Beware.

Update: If you want to suppress or log warnings, you can get rid of the 'no strict' and 'local' lines, and use a variant of this instead: local $SIG{__WARN__} = sub {};

It'll create and throw away a new anonymous sub (unless eval() checks for void context -- I dunno), but it'll do the compile-but-not-execute waltz.

Replies are listed 'Best First'.
Danger!
by Fastolfe (Vicar) on Jan 01, 2001 at 21:46 UTC
    Be very wary of using this with untrusted data. In the general case, sure, it might be a useful way to see if code compiles cleanly in the event you aren't prepared to execute it yet, but DO NOT use this method as any form of secure "compile only" test. What if the user provided "1 }; system("do something evil");" as their code?

    My first thought was to extend this eval method into using a 'reval' with a Safe compartment (with an obscenely strict opcode mask), which would prevent any "extra" code from being executed, but it seems as though the opcode mask is checked at compile time, which means the compilation would fail for legitimate stuff.

DANGER - was Re: Re: Syntax Error Checking
by merlyn (Sage) on Jan 01, 2001 at 22:04 UTC
    That won't stop an embedded BEGIN block from executing.
    my $coderef = eval <<'END'; sub { print "hello world\n"; BEGIN { print "you lose!\n"; } print "goodbye world\n"; } END
    That prints "you lose". Too bad.

    -- Randal L. Schwartz, Perl hacker

      Too bad, true. But I still don't understand why it doesn't print the two other lines.

      In my Great Foolishness(tm), I had always thought that there could only be one BEGIN block by package. So as I was reading merlyn's answer to the question, I thought to myself: "Ah! easy! I just have to embed the eval'd block in another BEGIN block, to make sure it'll be evaluated first."

      Alas, the "you lose!" block was the first printed in the block and then the "hello/goodbye" lines. Mmmh, too bad.

      Then, I realized that anything outside the BEGIN block in the sub was not executed.

      What is happening exactly? Does a BEGIN code inside a sub never returns? Can someone point me a node where all these mysteries are unveiled? Thanks!

      <kbd>--
      PerlMonger::Paris(http => 'paris.pm.org');</kbd>
        A BEGIN block is equivalent to a subroutine definition of a subroutine called BEGIN, followed immediately by an invocation and removal of that subroutine at compile time. So for example, in the case of:
        sub fred { blah blah; sub barney { print "hey there"; } foo foo; }
        we'd get the barney subroutine defined, with no connection (except closures if any) with the fred subroutine. Invoking fred would do nothing to or about barney. Replace barney with BEGIN, and you get the same behavior with respect to fred, except that BEGIN is now executed immediately even before compiling foo foo. Drop the "sub" keyword, and the same behavior applies.

        -- Randal L. Schwartz, Perl hacker