Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PPI differs from perl: // parseed as defined-or instead of regexp #302

Open
happy-barney opened this issue Nov 20, 2024 · 9 comments
Open

Comments

@happy-barney
Copy link
Contributor

happy-barney commented Nov 20, 2024

In expression identifier // (when identifier is not method call), Perl treats // as:

  • defined-or operator, if identifier represents keyword or function with () prototype
  • regexp-match otherwise

For example, parsing ref // 1:

  • current result
	PPI::Token::Word       => 'ref'
	PPI::Token::Whitespace => ' '
	PPI::Token::Operator   => '//'
	PPI::Token::Whitespace => ' '
	PPI::Token::Number     => '1'
  • expected result
	PPI::Token::Word          => 'ref'
	PPI::Token::Whitespace    => ' '
	PPI::Token::Regexp::Match => '//'
	PPI::Token::Whitespace    => ' '
	PPI::Token::Number        => '1'

But current result should be preserved for parsing eg: my sub ref (); ref // 1

@wchristian
Copy link
Member

Can you provide the example code as valid perl? I get this error trying to compile it:

$ perl -e 'ref // 1'
Warning: Use of "ref" without parentheses is ambiguous at -e line 1.
Number found where operator expected at -e line 1, near "// 1"
        (Missing operator before  1?)
syntax error at -e line 1, near "// 1"
Execution of -e aborted due to compilation errors.

@happy-barney
Copy link
Contributor Author

valid perl will be:

  • ref () // 1
  • sub foo :prototype() {}; foo // 1

@wchristian
Copy link
Member

In those examples Perl seems to treat // as the undef-or operator.

$ cat marp.pl
sub foo :prototype() {}; print(foo // 1)
$ perl marp.pl
1
$ cat marp.pl
sub foo :prototype() {2}; print(foo // 1)
$ perl marp.pl
2

@wchristian
Copy link
Member

wchristian commented Nov 20, 2024

Ah hm, it doesn't seem to for the first example. Impressively odd behavior.

Nevermind that, in the ref example it also treats it as the undef-or operator, because ref returns the empty string "".

$ perl -e 'print(length(ref () ))'
0
$ perl -e 'print(defined(ref () ))'
1

@wchristian
Copy link
Member

So, in conclusion: Right now i need an example of working Perl code where // is treated by Perl as a regex match, and evidence for this being the case. :)

@happy-barney
Copy link
Contributor Author

OK, probably some clarification: ref // 1 type of expressions will always be invalid.
This issues is only about treating objects like Perl does.

IMHO it is fine when PPI creates broken expressions from invalid code.
It should not create valid expression from invalid code. (using current behaviour creates valid expression of potential interpreter using PPI to parse code similar to Perl.

@wchristian
Copy link
Member

wchristian commented Nov 20, 2024

Note that you wrote:

Perl treats // as: [...] regexp-match otherwise

Can you clarify what your evidence for this is? (I find it hard to understand, given that Perl just crashes when presented with such code, instead of actually running it.)

@happy-barney
Copy link
Contributor Author

Note that you wrote:

Perl treats // as: [...] regexp-match otherwise

Can you clarify what your evidence for this is?

Perl/perl5#18117

@wchristian
Copy link
Member

wchristian commented Nov 22, 2024

I think this one is the same issue as #304, which is that we don't know the prototype of the function, and we take a different default path than the Perl parse, but changing the default would overall lead to less useful output.

The only solution would be to actually track prototypes, and also force users to provide external data on prototypes where the single input file isn't enough to decide.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants