Home > Net >  Why is division parsed as regular expression?
Why is division parsed as regular expression?

Time:09-17

This is part of my code:

        my $suma =  U::round $item->{ suma };  # line 36 
        $ts    =  $suma;
        $tnds  =  U::round $suma /6;
    }

    return( $ts, $tnds );
}



sub create { #line 46
    my( $c ) =  shift;

    my $info =  $c->req->json;
    my $header  =  @$info[0];
    my $details =  @$info[1];

    my $agre =  D::T Agreement =>  $header->{ agreement_id };
    my( $total_suma, $total_nds ) =  total( $details );

    my $saldo    =  0;
    my $iid      =  @$details[0]->{ period };
    my $interval =  D::T Period => $iid //7; # line 58
    # This is first Invoice if operator do not provide activation date
    my $is_first =  !$details->[0]{valid_from}  &&  $iid  &&  $interval;

When this module is loaded I gen an error:

Can't load application from file "lib/MaitreD/Controller/ManualDocument.pm line 38, near "my $interval =  D::T Period => $iid /"
Unknown regexp modifier "/6" at lib/MaitreD/Controller/ManualDocument.pm line 38, at end of line
Global symbol "$pkg" requires explicit package name (did you forget to declare "my $pkg"?) at lib/MaitreD/Controller/ManualDocument.pm line 41.
...

Is this indirect object call guilty?

Because when I put parentheses at U::round( $suma /6 ) there is no errors

CodePudding user response:

Here are some thoughts on this, and a plausible explanation. A simple reproduction

perl -wE'sub tt { say "@_" }; $v = 7; tt $v /3'

gives me

Search pattern not terminated at -e line 1.

So it tries to parse a regex in that subroutine call, as stated, and the question is: why?

With parenthesis around argument(s) it works as expected. With more arguments following it it fails the same way, but with arguments preceding it it works

perl -wE'sub tt { say "@_" }; $v = 7; tt $v /3, 3'  # fails the same way
perl -wE'sub tt { say "@_" }; $v = 7; tt 3, $v /3'  # works

Equipping the tt sub with a prototype doesn't change any of this.

By the error it appears that the / triggers the search for the closing delimiter and once it's not found the whole thing fails. So why is this interpreted as a regex and not division?

It seems that tt $v are grouped in parsing, and interpreted as a sub and its arguments, since they're followed by a space; then /3 is taken separately and then that does look like a regex. That would still fail as a syntax error but perhaps the regex parsing failure comes first.

Then the difference between other comma-separated terms coming before or after is clear -- with tt 3, ... the following $v /3 is a term for the next argument, and is parsed as division.

This still leaves another issue. All builtins that I tried don't have this problem, be they list or unary operators, with a variety of prototypes (push, chr, splice, etc) -- except for print, which does have the same looking problem. And which fails both with and without parens.

perl -wE'$v=110; say for unpack "A1A1", $v /2'  #--> 5 5
perl -wE'$v=200; say chr $v /2'                 #--> d
perl -wE'$v=3; push @ary, $v /2; say "@ary"'    #--> 1.5

perl -wE'$v = 7; say $v /3'                     # fails, the same way
perl -wE'$v = 7; say( $v /3 )'                  # fails as well, same way

A difference is that print obeys "special" parsing rules, and which allow the first argument to be a filehandle. (Also, it has no prototype but that doesn't appear to matter.)

Then the expression print $v /3... can indeed be parsed as print filehandle EXPR, and the EXPR starting with / is parsed as a regex. The same works with parenthesis.

All this involves some guesswork as I don't know how the parser does it. But it is clearly a matter of details of how a subroutine call is parsed, what (accidentally?) includes print as well.

An obvious remedy of using parens on (user-defined) subroutines is reasonable in my view. The other fix is to be consistent with spaces around math operators, to either not have them on either side or to use them on both sides -- that is fine as well, even as it's itchy (spaces? really?).

I don't know what to say about there being a problem with say( $v /3 ) though.

A couple more comments on the question.

By the text of the error message in the question, Unknown regexp modifier "/6", it appears that there the / is taken as the closing delimiter, unlike in the example above. And there is more in that message, which is unclear. In the end, we do have a very similar parsing question.

As for

Is this indirect object call guilty?

I don't see an indirect object call there, only a normal subroutine call. Also, the example from this answer displays very similar behavior and rules out the indirect object syntax.


Another possibility may be that $v /3 is parsed as a term, since it follows the (identifiable!) subroutine name tt. Then, the regex binding operator =~ binds more tightly than the division, and here it is implied by clearly attempting to bind to $_ by default.

I find this less likely, and it also can't explain the behavior of builtins, print in particular.


Then one can infer that other builtins with an optional comma-less first argument (and so without a prototype) go the same way but I can't readily think of any.

CodePudding user response:

Perl thinks that the symbol / is a start of a regular expression and not a division operator. https://perldoc.perl.org/perlre - You can check the perldoc for regular expressions. You can try adding a whitespace character before 6 like so: $tnds = U::round $suma / 6;

  • Related