Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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.