Indentation Syntax
x2c can be written without braces or semicolons. Indentation groups the
statements of a block, a line that opens a block ends with :, and a line
break ends a statement. Name the file .xp, or put #pragma indent at the
top of a .x file. The two spellings mean the same program, so an indented
file can include, import, and call brace-form code and the reverse.
Here is a small program in brace form:
typedef enum Shape { CIRCLE, SQUARE } Shape;
double area(Shape shape, double size) {
switch (shape) {
case CIRCLE: return 3.14159 * size * size;
default: return size * size;
}
}
int main(void) {
double total = 0;
for (int i = 1; i <= 3; i++) {
if (i == 2) continue;
total += area(i == 1 ? CIRCLE : SQUARE, i);
}
printf("%.2f\n", total);
return 0;
}
12.14
The same program in the indentation syntax:
#pragma indent
typedef enum Shape:
CIRCLE,
SQUARE
Shape
double area(Shape shape, double size):
switch shape:
case CIRCLE: return 3.14159 * size * size
default: return size * size
int main(void):
double total = 0
for (int i = 1; i <= 3; i++):
if i == 2: continue
total += area(i == 1 ? CIRCLE : SQUARE, i)
printf("%.2f\n", total)
return 0
12.14
Conditions need no parentheses, except that a for header keeps its
three clauses in them, and a short body can follow its colon on the same
line. foreach separates its declaration from the collection with in or
a comma, as in brace form. The enum keeps its commas, and its name after the dedent
completes the typedef.
Long lines
A line break inside parentheses, brackets, or braces never ends a
statement. Outside them, a line indented deeper than the one before it
continues that line. A line that starts with . continues a method chain:
#pragma indent
int main(void):
List words = %("indentation" "groups" "blocks")
int letters = 0
foreach String word in words:
letters += word.len()
String report = %"${words.len()} words, " +
%"$letters letters"
List lengths = words
.map(%!(Var word) => word.str().len())
printf("%s: %s\n", report, lengths.str())
return 0
3 words, 23 letters: ( 11 6 6 )
Scopes and decorators
do: opens a bare scope when its block is not followed by a while line,
which is how an indented macro keeps its temporaries to itself. In
indentation syntax a decorator line starts with @, so the layout wraps the
next statement instead of ending the line with ;. Brace form writes the
decorator without @:
#pragma indent
#include "system-macros.x"
#include <time.h>
int main(void):
int total = 0
do:
int step = 2
total += step
@$time("sum")
for (int i = 0; i < 1000; i++):
total += i
printf("%d\n", total)
return 0
Converting a file
tools/indent-convert FILE... rewrites brace-form files in place, adding
#pragma indent so each keeps its name; an executable script stays
runnable by name. Every block header, including one whose body had no
braces, ends with a colon. The converter proves each conversion by
comparing the compiler’s AST for the result with the original’s, and it
leaves a file unchanged when they differ, as they do when indentation
misrepresents which statement an else or a body belongs to. --check
reports without writing.
A .xp file writes macros the same way. The
language reference lists
every layout rule. examples/tours/indentation.xp is a complete program.