[ANN] Acme::Pythonic 0.33

From: Xavier Noria (fxn_at_hashref.com)
Date: 06/28/04


Date: 28 Jun 2004 07:32:55 -0700

Acme::Pythonic 0.33 is out. Since the last announcement changes has
been done mostly to the documentation of the module:

0.33
    - Minor documentation improvements.
    - The section about labels was rewritten.
    - Added Acme::Dot to SEE ALSO.

0.32 Sat Jun 19 16:09:44 2004
    - Added OVERVIEW to POD.
    - Minor documentation enhancements.

0.31 Sat Jun 12 14:58:32 2004
    - Test::More required version relaxed to 0.45.
    - Perl required version relaxed to 5.8.0.

-- fxn

NAME
    Acme::Pythonic - Python whitespace conventions for Perl

SYNOPSIS
     use Acme::Pythonic; # this semicolon yet needed

     sub delete_edges:
         my $G = shift
         while my ($u, $v) = splice(@_, 0, 2):
             if defined $v:
                 $G->delete_edge($u, $v)
             else:
                 my @e = $G->edges($u)
                 while ($u, $v) = splice(@e, 0, 2):
                     $G->delete_edge($u, $v)

DESCRIPTION
    Acme::Pythonic is a source filter that brings Python whitespace
    conventions to Perl.

    This module is thought for those who embrace contradictions. A
humble
    aid for walkers of the Whitespace Matters Way in their pursuit of
    highest realization, only attained with SuperPython.

OVERVIEW
    Acme::Pythonic provides *grosso modo* these conventions:

    * Blocks are marked by indentation and an opening colon instead of
    braces.
    * Simple statements are separated by newlines instead of
semicolons.
    * EXPRs in control flow structures do not need parentheses around.

    Additionally, the filter understands the keywords "pass" and "in".

        foreach my $n in 1..100:
            while $n != 1:
                if $n % 2:
                    $n = 3*$n + 1
                else:
                    $n /= 2

DETAILS
  Labels
    The syntax this module provides introduces an ambiguity: Given

        if $flag:
            do_this()
        else:
            do_that()

    there's no way to know whether that is meant to be

        if ($flag) {
            do_this();
        } else {
            do_that();
        }

    or rather

        if ($flag) {
            do_this();
        }
        else: {
            do_that();
        }

    where the second half is a labeled block, and so "do_that()" is
    unconditionally executed.

    To solve this labels in Pythonic code have to be in upper case.

    In addition, to be able to write a BEGIN block as

        BEGIN:
            $foo = 3

    "BEGIN", "CHECK", "INIT", "END" cannot be used as labels.

    Let's see some examples. This is the Pythonic version of the
snippet in
    perlsyn:

        OUTER: for my $wid in @ary1:
            INNER: for my $jet in @ary2:
                next OUTER if $wid > $jet
                $wid += $jet

    And here we have a labeled block:

        my $k = 7
        FOO:
            --$k
            last FOO if $k < 0
            redo FOO

    Note that if we put a label in the line before in a control
structure
    indentation matters. This would be a non-equivalent reformat of
the
    example above:

        OUTER:
            for my $wid in @ary1: # NOT WHAT WE WANT
                INNER:
                for my $jet in @ary2: # GOOD, ALIGNED
                    next OUTER if $wid > $jet
                    $wid += $jet

    Since the first "for" is indented with respect to "OUTER:" we get
a
    labeled block containing a "for" loop, instead of a labeled "for".

  "do/while"-like constructs
    Acme::Pythonic tries to detect statement modifiers after a do
BLOCK.
    Thus

        do:
            do_something()
            do_something_else()
        while $condition

    is seen as a do/while, whereas

        do:
            do_something()
            do_something_else()
        while $condition:
            handle_some_stuff()

    is not.

  New Keywords
   pass
    "pass" is a NO-OP, it is meant to explicit empty blocks:

        sub abstract_method:
            pass

   in
    This works:

        foreach my $foo @array:
            do_something_with $foo

    However "in" is supported in case you find the following more
readable

        foreach my $foo in @array:
            do_something_with $foo

    This keyword can be used if there's no variable to its left too,
which
    means we are dealing with $_ as usual:

        foreach in @array:
            s/foo/bar/

    but can't be used when the loop acts as a modifier:

        print foreach in @array # ERROR

  &-Prototyped subroutines
    "&"-prototyped subroutines can be used like this:

        sub mygrep (&@):
            my $code = shift
            my @result
            foreach @_:
                push @result, $_ if &$code
            return @result

        @array = mygrep:
            my $aux = $_
            $aux *= 3
            $aux += 1
            $aux % 2
        reverse 0..5

    If the prototype is exactly "&", however, Acme::Pythonic needs to
know
    it because it might need to add a semicolon after the closing
bracket in
    the generated code.

    Thus, if any module defines such a subroutine "use()" it *before*
    Acme::Pythonic:

        use Thread 'async';
        use Acme::Pythonic; # now Acme::Pythonic knows async() has
prototype "&"

        async:
            do_this()
            do_that()

    If such a subroutine is defined in the very code being filtered
declare
    it before Acme::Pythonic is "use()"d:

        sub twice (&); # declaration
        use Acme::Pythonic; # now Acme::Pythonic knows twice() has
prototype "&"

        # the definition itself can be Pythonic
        sub twice (&):
             my $code = shift
             $code->() for 1..2

        twice:
             do_this_twice()

    Nevertheless, the module is not smart enough to handle optional
    arguments as in a subroutine with prototype "&;$".

  Line joining
    As in Python, you can break a logical line in several physical
lines
    using a backslash at the end:

        my $total = total_products() + \
                    total_delivery() + \
                    total_taxes()

    and in that case the indentation of those additional lines is
    irrelevant.

    Unlike Python, backslashes in a line with a comment are allowed

        my $foo = 1 + \ # comment, no problem
            2

    In Python that's a syntax error, but I think that's more in the
line of
    Perl forgiveness.

    If a line ends in a comma or arrow ("=>") it is conceptually
joined with
    the following as well:

        my %authors = (Perl => "Larry Wall",
                       Python => "Guido van Rossum")

    As in Python, comments can be intermixed there:

        my %hello = (Catalan => 'Hola', # my mother tongue
                     English => 'Hello',)

    Acme::Pythonic munges a source that has already been processed by
    Filter::Simple. In particular, Filter::Simple blanks out
quotelikes
    whose content is not even seen by Acme::Pythonic so backslashes in
    "qw//" and friends won't be removed:

        # Do not put backslashes here because qw// is bypassed
        my @colors = qw(Red
                        Blue
                        Green)

LIMITATIONS
    Keywords followed by code in the same line are "not" supported.
This
    would be valid in Python:

        if $n % 2: $n = 3*$n + 1
        else: $n /= 2

    but it does not work in Acme::Pythonic. The reason for this is
that it
    would be hard to identify the colon that closes the expression
without
    parsing Perl, consider for instance:

        if keys %foo::bar ? keys %main:: : keys %foo::: print "foo\n"

DEBUG
    You can pass a "debug" flag to Acme::Pythonic like this:

        use Acme::Pythonic debug => 1;

    In debug mode the module prints to standard output the code it has
    generated and substitutes everything with a dummy "1;", so nothing
gets
    executed. This way the resulting source can be inspected.

    The module tries to generate human readable code following
perlstyle.
    Blank lines and comments are preserved.

    This happens *before* Filter::Simple undoes the blanking out of
PODs,
    strings, and regexps. Those parts are marked with the label
    "BLANKED_OUT" for easy identification.

BUGS
    This module uses a regexp approach and the superb help of
    Filter::Simple. The regexp part of this means it is broken from
the
    start, though I've tried hard to make it as robust as I could. Bug
    reports will be very welcome, just drop me a line!

THANKS
    Damian Conway gave his full blessing if I wanted to write a module
like
    this based on his unpublished Language::Pythonesque. The code that
    handles indentation is inspired by his.

    Also, Dr. Conway is the author of Filter::Simple, which aids a lot
    blanking out PODs, strings, etc. so you can munge the source with
    certain confidence. Without Filter::Simple this module would be
    infinitely more broken.

SEE ALSO
    perlfilter, Filter::Simple, SuperPython, Acme::Dot.

AUTHOR
    Xavier Noria (FXN), <fxn@cpan.org>

COPYRIGHT AND LICENSE
    Copyright (C) 2004 by Xavier Noria

    This library is free software; you can redistribute it and/or
modify it
    under the same terms as Perl itself, either Perl version 5.8.2 or,
at
    your option, any later version of Perl 5 you may have available.



Relevant Pages

  • Re: Why I dont believe in static typing
    ... The Mercury distribution includes one Perl program, mtags, which is now ... I can give you an analysis of the bugs that occurred ... because statically typed languages will ...
    (comp.lang.lisp)
  • Questions about the Class::Contract module
    ... a simple syntax for specifying a class's interface; ... useful for writing well-designed OO modules or applications in Perl? ... reasonable workarounds for any serious bugs? ...
    (comp.lang.perl.modules)
  • Re: Privilege-escalation attacks on NT-based Windows are unfixable
    ... >C compilers have had histories of bugs... ... Any software involved is a risk; ... but if you write set-uid perl scripts I'd ... many that it's completely impossible to write a secure set-uid C-shell ...
    (comp.security.misc)
  • Re: Privilege-escalation attacks on NT-based Windows are unfixable
    ... >C compilers have had histories of bugs... ... Any software involved is a risk; ... but if you write set-uid perl scripts I'd ... many that it's completely impossible to write a secure set-uid C-shell ...
    (comp.os.ms-windows.nt.admin.security)
  • Questions about the Class::Contract module
    ... a simple syntax for specifying a class's interface; ... useful for writing well-designed OO modules or applications in Perl? ... reasonable workarounds for any serious bugs? ...
    (comp.lang.perl.misc)