The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

standard - Enforce Standard Perl syntax with Guacamole

VERSION

version 0.008

SYNOPSIS

    use standard;
    # Now you will get a warning if you don't conform to Standard Perl

DESCRIPTION

Standard Perl aims to use only the syntax that makes Perl easy to parse. A Perl static parser such as Guacamole isn't that hard if we avoid a small set of constructs that cause parser ambiguities.

These changes are described below. Over time, this documentation will explain the standard itself versus the differences between this subset and what the perl interpreter supports.

DIFFERENCES

Things not supported

This list covers constructs that the perl interpreter understands (for whatever value of "understand" is) but that that Standard Perl does not support.

  • Auto-quoting

    Perl's auto-quoting rules are... rather elaborate and awkward. Much of it is unknown and can even depend on lowercase vs. uppercase and specific letters with special meaning to the interpreter and not the user.

    Thus, a string in Standard Perl is always quoted.

        $foo{key}   # not ok
        $foo{'key'} # ok
    
        %hash = ( foo   => 'bar' ); # not ok
        %hash = ( 'foo' => 'bar' ); # ok
  • HEREDOCs

    HEREDOCs are a monstrosity for parsers and cannot be expressed with a BNF. It is thus not supported.

        # This will fail
        my $value = << '_END_OF_VALUE';
        ...
        _END_OF_VALUE
    
        # This is an alternative
        my $value =
        q{...
        };
    
        # This is another alternative:
        my $value = q{
        ...
        } =~ s/^\n//r;
  • Indirect object notation

        my $instance = new Class;    # not ok
        my $instance = Class->new(); # ok
  • Bareword filehandles

        open FOO, ...    # not ok
        open my $fh, ... # ok
        open $fh, ...    # ok
    
        print STDOUT $foo; # ok
        print STDERR $foo; # ok
    
        while ( <FOO>   ) {...} # not ok
        while ( <$foo>  ) {...} # ok
        while ( <STDIN> ) {...} # ok

    The following bareword filehandles are supported:

    • STDIN

    • STDOUT

    • STDERR

    • ARGV

    • ARGVOUT

    • DATA

  • Printing to filehandles with no brace

        print $fh $foo;   # not ok
        print {$fh} $foo; # ok
  • _ outside file operations

        if ( -f $foo && -r _ ) {...} # ok
        print {$fh} _                # not ok

    _ should only be used as a bareword identifier within -X file operations. In the print example, Perl understands it as printing an underscore character ("_") to the filehandle, which is just odd, so we do not support that.

  • given / when / default

    Not supported.

  • Anonymous hashes vs. bare block as top-level expressions

        # not ok
        package Foo {
            { 'bar' => 'baz' };
        }

    The above shows a useless use of anonymous hash (per the Perl warning on it) as a top-level expression (in this case, inside a package block).

    Standard Perl does not support this since it can be confused with a bare code block. Instead, you should add some top-level token to disambiguate:

        # ok
        package Foo {
            +{ 'bar' => 'baz' }
        }

    It's still useless (and Perl would warn about it), but it's allowed.

        # not ok:
        sub foo {
            { 'a' => 'b' };
        }
    
        # ok
        sub foo {
            +{ 'a' => 'b' }; # "+" is a top-level token
        }
    
        # ok
        sub foo {
            return { 'a' => 'b' }; # used as argument to "return"
        }

Things we changed

The following are limitations that Standard Perl has which the perl interpreter doesn't.

Q-Like values

Q-Like values are one of the following: q, qq, qw, qx, qr

However, the following limitations also apply to: m//, s/// tr///, and y///.

  • No nested delimiters

        $val = q< <> >;    # not ok
        $val = q< \<\> >;  # ok

    If you want to use the delimiter within delimited space, escape it.

  • Limited delimiters

    Only the following delimiters are supported:

    (), [], {}, < >, //, !!, and ||.

        $val = q(...) # ok
        $val = q[...] # ok
        $val = q{...} # ok
        $val = q<...> # ok
        $val = q/.../ # ok
        $val = q!...! # ok
        $val = q|...| # ok
    
        $val = q@...@    # not ok
        $val = q#...#    # not ok
        $val = q Z ... Z # not ok

    If you want to advocate for another set of delimiters, open a ticket.

  • No spaces between before delimiters in Q-like values:

        q <foo>   # not ok
        q < foo > # not ok
        q ()      # not ok
    
        q<foo>    # ok
        q< foo >; # ok
        q()       # ok

Subroutines

  • All subroutines must use parentheses

        foo $bar   # not ok
        foo($bar)  # ok

    There is an exception for methods:

        $foo->bar()         # ok
        $foo->bar           # ok
    
        $foo->bar()->baz()  # ok
        $foo->bar->baz      # ok
  • Subroutines can have attributes and signatures

    Standard Perl accepts both attributes and signatures.

  • All subroutine prototypes must be declared using an attribute

        sub foo ($)           {...} # signature, not prototype
        sub foo :prototype($) {...} # prototype, not signature
  • Prototypes do not change the parsing rules

        first {...} @foo         # not ok
        first( sub {...}, @foo ) # ok

    There is preliminary support for adding your own keywords by hooking into the grammar of the Guacamole parser, but it is ALPHA stage, so it's not widely docuemnted.

    This will be useful for stuff like List::Util, Dancer2, Mojolicious::Lite, Try::Tiny, Moose, etc.

    Having said that, Standard Perl will likely never prototypes directly, nor should it.

Class names

  • Left of arrow is always an invocant, never a function

        Foo->new(); # always a class, never a function "Foo"

    This is tricky because the perl interpreter might see a function called Foo in the same scope and call that instead. This would mean that Standard Perl and the perl interpreter would report different results.

    We have a shim layer in standard that checks for this and alerts if this will happen, so you never hit this issue when using standard.

    We advise other parsers who use Standard Perl BNF to include this part.

  • Namespaces cannot end with a double colon

        Foo->bar();   # ok
        Foo::->bar(); # not ok

    This might be changed in the future.

Dereferencing

  • Prefixed dereferencing is only supported with braces

        @$foo    # not ok
        @{$foo}  # ok
        $foo->@* # ok

Expressions

  • map that attempts to return a pair must use parenthesis

        map {   $_ => 1   }, @foo  # not ok
        map { ( $_ => 1 ) }, @foo  # ok

SEE ALSO

Guacamole

AUTHORS

  • Sawyer X

  • Vickenty Fesunov

COPYRIGHT AND LICENSE

This software is Copyright (c) 2022 by Sawyer X.

This is free software, licensed under:

  The MIT (X11) License