kurilasyn - Perl Kurila syntax


kurilasyn - Perl Kurila syntax


A Perl Kurila program consists of a sequence statements which run from the top to the bottom. Loops, subroutines and other control structures allow you to jump around within the code.

Perl Kurila is a layout dependent language, the indentation is an important part of the syntax.

Perl Kurila borrows syntax and concepts from many languages: Perl 5, awk, sed, C, Bourne Shell, Smalltalk, Lisp, Haskell and even English. So if you have programmed in another language you will see familiar pieces in Perl Kurila. They often work the same, but see the perltrap manpage for information about how they differ.


Text from a "#" character until the end of the line is a comment, and is ignored. Exceptions include "#" inside a string or regular expression.



Blocks are usually made using layout. When a block is expected the column of the first token of block, determines the indentation of the block.

The next token after when a block is expected determines the starting column. A statement is terminated if the next line is equally or less indented as the block. The block is terminated if a line is indented less than the indentation of the block.

Each file or eval string is started with an implicit block with zero indentation.

Empty lines, Comments, Pod and heredocs are ignored for the layout.


The operators @:, %: and <: start a layout based lists.

Similar as with blocks the next token after the operator determines the starting column. And a new list item is started starts at the same starting column. The list is terminated if a line indented less than the starting column.

Layout insensitivity

Instead of using layout to make blocks, they can also be created by using a { to start a block. If this is done layout is ignored, and statements have to be terminated by a semicolon ;. The block has to be ended with with a closing brace }, after which the previous layout rule is restored.


An example of layout based blocks and statements,

    if ($cond)
            + cont_statement2()

or equivalent,

    if ($cond) statement1()
               statement2() + cont_statement2()
    else else_statement1()

or using layout insensitive syntax,

    if ($cond) {
      statement2() + cont_statement2();
    } else {

Simple Statements

The only kind of simple statement is an expression evaluated for its side effects. A statement can be terminated with a semicolon. Note that there are some operators like try {} and do that look like compound statements, but aren't (they're just TERMs in an expression), and thus need an explicit termination if used as the last item in a statement.

Truth and Falsehood

The number 0, the strings '0' and '', the empty list (), an empty array @(), an empty hash %() and undef are all false in a boolean context. All other values are true. Negation of a true value by ! or not returns a special false value. When evaluated as a string it is treated as '', but as a number, it is treated as 0.

Statement Modifiers

Any simple statement may optionally be followed by a SINGLE modifier. The possible modifiers are:

    if EXPR
    unless EXPR
    while EXPR
    until EXPR
    foreach EXPR

The EXPR following the modifier is referred to as the "condition". Its truth or falsehood determines how the modifier will behave.

if executes the statement once if and only if the condition is true. unless is the opposite, it executes the statement unless the condition is true (i.e., if the condition is false).

    print $^STDOUT, "Basset hounds got long ears" if length $ear +>= 10;
    go_outside() and play() unless $is_raining;

The foreach modifier is an iterator: it executes the statement once for each element of the array EXPR (with $_ aliased to each item in turn).

    print $^STDOUT, "Hello $_!\n" foreach qw(world Dolly nurse);

while repeats the statement while the condition is true. until does the opposite, it repeats the statement until the condition is true (or while the condition is false):

    # Both of these count from 0 to 10.
    print $i++ while $i +<= 10;
    print $j++ until $j +>  10;

The while and until modifiers have the usual "while loop" semantics (conditional evaluated first). Note also that the loop control statements described later will NOT work in this construct, because modifiers don't take loop labels.

NOTE: The behaviour of a my statement modified with a statement modifier conditional or loop construct (e.g. my $x if ...) is undefined. The value of the my variable may be undef, any previously assigned value, or possibly anything else. Don't rely on it. Future versions of perl might do something different from the version of perl you try it out on. Here be dragons.

Compound Statements

In Perl, a sequence of statements that defines a scope is called a block. Sometimes a block is delimited by the file containing it (in the case of a required file, or the program as a whole), and sometimes a block is delimited by the extent of a string (in the case of an eval).

But generally, a block is delimited by the layout, or delimited by curly brackets, also known as braces. We will call this syntactic construct a BLOCK.

The following compound statements may be used to control flow:

    if (EXPR) BLOCK
    if (EXPR) BLOCK else BLOCK
    if (EXPR) BLOCK elsif (EXPR) BLOCK ... else BLOCK
    LABEL while (EXPR) BLOCK
    LABEL while (EXPR) BLOCK continue BLOCK
    LABEL until (EXPR) BLOCK
    LABEL until (EXPR) BLOCK continue BLOCK
    LABEL for VAR (EXPR) BLOCK continue BLOCK
    LABEL loop BLOCK while (EXPR)
    LABEL loop BLOCK until (EXPR)

The if statement is straightforward. If you use unless in place of if, the sense of the test is reversed.

The while statement executes the block as long as the expression is true. The until statement executes the block as long as the expression is false. The LABEL is optional, and if present, consists of an identifier followed by a colon. The LABEL identifies the loop for the loop control statements next, last, and redo. If the LABEL is omitted, the loop control statement refers to the innermost enclosing loop. This may include dynamically looking back your call-stack at run time to find the LABEL. Such desperate behavior triggers a warning if you use the use warnings pragma or the -w flag.

If there is a continue BLOCK, it is always executed just before the conditional is about to be evaluated again. Thus it can be used to increment a loop variable, even when the loop has been continued via the next statement.

Loop Control

The next command starts the next iteration of the loop:

    LINE: while (~< $^STDIN)
        next LINE if m/^#/       # discard comments

The last command immediately exits the loop in question. The continue block, if any, is not executed:

    LINE: while (~< $^STDIN)
        last LINE if m/^$/      # exit when done with header

The redo command restarts the loop block without evaluating the conditional again. The continue block, if any, is not executed. This command is normally used by programs that want to lie to themselves about what was just input.

For example, when processing a file like /etc/termcap. If your input lines might end in backslashes to indicate continuation, you want to skip ahead and get the next record.

    while (~< *ARGV)
        if (s/\\$//)
            $_ .= ~< *ARGV
            redo unless eof()
        # now process $_

which is Perl Kurila short-hand for the more explicitly written version:

    LINE: while (defined($line = ~< *ARGV))
        if ($line =~ s/\\$//)
            $line .= ~< *ARGV
            redo LINE unless eof() # not eof(ARGV)!
        # now process $line

Note that if there were a continue block on the above code, it would get executed only on lines discarded by the regex (since redo skips the continue block).

If the word while is replaced by the word until, the sense of the test is reversed, but the conditional is still tested before the first iteration.

The loop control statements don't work in an if or unless, since they aren't loops.

For Loops

The for loop iterates over an array and sets the variable VAR to be each element of the list in turn. If the variable is preceded with the keyword my, then it is lexically scoped, and is therefore visible only within the loop. Otherwise, the variable is implicitly local to the loop and regains its former value upon exiting the loop. If the variable was previously declared with my, it uses that variable instead of the global one, but it's still localized to the loop. This implicit localisation occurs only in a for loop.

The foreach keyword is a synonym for the for keyword.

If the array is an lvalue, you can modify it by modifying VAR inside the loop. Conversely, if the array is NOT an lvalue, any attempt to modify that element will fail. In other words, the for loop index variable is an implicit alias for each element in the array that you're looping over.


    for (@ary) s/foo/bar/
    for my $elem (@elements)
        $elem *= 2
    for $count (10,9,8,7,6,5,4,3,2,1,'BOOM')
        print $^STDOUT, $count, "\n"; sleep(1)
    for (1..15) print $^STDOUT, "Merry Christmas\n"
    foreach $item (split(qr/:[\\\n:]*/, env::var('TERMCAP')))
        print $^STDOUT, "Item: $item\n"

PODs: Embedded Documentation

Perl Kurila has a mechanism for intermixing documentation with source code. While it's expecting the beginning of a new statement, if the compiler encounters a line that begins with an equal sign and a word, like this

    =head1 Here There Be Pods!

Then that text and all remaining text up through and including a line beginning with =cut will be ignored. The format of the intervening text is described in the perlpod manpage.

This allows you to intermix your source code and your documentation text freely, as in

    =item snazzle($)
    The snazzle() function will behave in the most spectacular
    form that you can possibly imagine, not even excepting
    cybernetic pyrotechnics.
    =cut back to the compiler, nuff of this pod stuff!
    sub snazzle($thingie)

Note that pod translators should look at only paragraphs beginning with a pod directive (it makes parsing easier), whereas the compiler actually knows to look for pod escapes even in the middle of a paragraph. This means that the following secret stuff will be ignored by both the compiler and the translators.

    =secret stuff
     warn "Neither POD nor CODE!?"
    =cut back
    print $^STDOUT, "got $a\n"

You probably shouldn't rely upon the warn() being podded out forever. Not all pod translators are well-behaved in this regard, and perhaps the compiler will become pickier.

One may also use pod directives to quickly comment out a section of code.

Plain Old Comments (Not!)

Perl Kurila can process line directives, much like the C preprocessor. Using this, one can control Perl's idea of filenames and line numbers in error or warning messages (especially for strings that are processed with eval()). The syntax for this mechanism is the same as for most C preprocessors: it matches the regular expression

    # example: '# line 42 "new_filename.plx"'
    /^\#   \s*
      line \s+ (\d+)   \s*
      (?:\s("?)([^"]+)\2)? \s*

with $1 being the line number for the next line, and $3 being the optional filename (specified with or without quotes).

There is a fairly obvious gotcha included with the line directive: Debuggers and profilers will only show the last source line to appear at a particular line number in a given file. Care should be taken not to cause line number collisions in code you'd like to debug later.

 kurilasyn - Perl Kurila syntax