So, I considered the comments (thank you, all), and thought I’d have another go at making the ending ‘dot’ optional.

I decided to introduce another token, ‘GAP’, to denote an empty line. Most likely, the scanner, in its current state, will not be able to handle empty lines with white space in them, etc, and the code is starting to look a bit confused. Oh well…

The toplevel rule for a function now becomes:


form -> function dot : '$1'.
form -> function 'GAP' : '$1'.

and the rule for alternative function clauses is as before:

function_clauses -> function_clause : ['$1'].
function_clauses ->
   function_clause ';' function_clauses : ['$1'|'$3'].
function_clauses -> 
  function_clause 'OUT' : ['$1'].
function_clauses ->
  function_clause 'END' function_clauses : ['$1'|'$3'].

The first two rules are the original rules for indentation-insensitive code. The last two are for the indentation tokens. The ‘OUT’ token is for symmetry, to match the ‘IN’ token after the arrow in function_body. Remember that indentation tokens are normalized in the scanner.

The test program now looks like this:

-module(test).

-compile(export_all).
-scan(indentation).

f(X) ->
    X+2

g(X) ->
    X+4
.

h(X) ->
    Y = case X of
          a ->
            {a}
          b ->
            {b}
    end
    Y

i(a) -> a
i(b) -> b

test() ->
    2 = f(0),
    4 = f(2),
    4 = g(0),
    8 = g(4),
    {a} = h(a),
    {b} = h(b),
    a = i(a),
    b = i(b),
    ok.

A little bit better. The ‘end’ tokens are still needed, though. One thing at a time…