Indentation-based syntax
From Nemerle Homepage
This was one of the open projects.
Contents |
Enabling
There are two ways of enabling the indentation syntax. One is to use the -i compiler option. This enables it for all the files passed to the compiler.
The other is to use #pragma indent at the top of the file (comments and whitespace before are OK, anything else is NOT!).
The algorithm
We maintain a stack of indentation strings. Whenever a new, non-empty line is processed we check if:
- its indentation is the same as the one on the top of the stack, in which case we add a semicolon to close the previous line
- otherwise the indentation has the top-one as prefix, in which case we push it on the stack and add an open brace
- otherwise, if the new indentation is somewhere on the stack, we pop elements looking for it and generate a close brace for each indentation popped
- otherwise it is an error
Exceptions
When the line ends with backslash, in which case it is effectively merged with the next one.
When the line ends with ; or the next one begins with {, the ; is not added.
Inside [], () and {} the indentation processing is off.
Further reading
Most of the comments in Python: Myths about Indentation also applies to our indentation syntax.
Example
using System.Console [Qux] \ class FooBar public static Main () : void WriteLine ("Hello") static Foo (x : int) : void if (x == 3) def y = x * 42 Foo (x) else [x].Map (fun (x) { x * 2 }) static Bar () : int def foo = 2 \ + 7 \ * 13 foo
is translated to:
using System.Console; [Qux] class FooBar { public static Main () : void { WriteLine ("Hello") } static Foo (x : int) : void { if (x == 3) { def y = x * 42; Foo (x) } else { [x].Map (fun (x) { x * 2 }) } } static Bar () : int { def foo = 2 + 7 * 13; foo } }
Alternative clauses in a match
If you use alternative clauses in a match, to match multiple cases to one result,
match (s) { | "a" | "aa" => 1 | "b" | "bb" => 2 | _ => 0 }
in indententation based syntax :
match (s) | "a" | "aa" => 1 | "b" | "bb" => 2 | _ => 0
it won't compile, you need to use line continuation ('\')
match (s) | "a" \ | "aa" => 1 | "b" \ | "bb" => 2 | _ => 0
or just use standard syntax with { .. } for this specific match:
match (s) { | "a" | "aa" => 1 | "b" | "bb" => 2 | _ => 0 }