Basic Syntax

Identifiers

Identifiers, such as function names and record attributes, are either single words such as identifier or X, or are quoted using backticks if they are more complex. Where other programming languages might use camelCase or snake_case, L4 allows the use of `space separated words` to form a single identifier.

Comments

Comments are written using the -- syntax. Such comments extend to the end of the current line.

-- This is a comment

You can also use {- .... -} syntax to comment out an entire range of lines.

Textual Annotations

Annotations are paratextual: they are not an essential part of an L4 program, but inform various transformations of the program.

Annotations are enclosed within [ square brackets ].

Annotations can be added to sections and other constructs.

§ `Section Head` [NLG annotation to section names are valid.]

References

References can be added to various constructs using three related annotation commands.

References are inserted into the code using the @ref annotation. Such an annotation takes a "reference identifier" as an argument, e.g.

@ref FOO-Section2

The reference identifier has to be mapped to a URL. The URL is then available as a link in the IDE. The mapping from reference identifiers to URLs can be specified in an external file or directly in the source code:

  • @ref-src@ takes a filename of a CSV file as an argument. The CSV file should contain a mapping from reference identifiers to URLs.

  • @ref-map@ takes a reference identifier and a URL as an argument and defines one such mapping directly within the source file.

Indentation in Expressions

Like most languages, L4 supports the use of ( parentheses ) for grouping, and , commas as a list separator.

Unlike most languages, L4 encourages the use of indentation for grouping, and newlines as a list separator.

In a conventional language, parentheses are used to group boolean and arithmetic expressions:

/**
 * Determines if the given numbers are considered "big".
 * @param {number} x - The first number.
 * @param {number} y - The second number.
 * @returns {boolean} - True if the numbers are big, false otherwise.
 */
function numbersAreBig(x: number, y: number): boolean {
  return (x > 1000 && y > 250 * (2 + 2)) || x > 10000 || y > 20000;
}

In L4, indentation replaces parentheses:

GIVEN x IS A NUMBER
      y IS A NUMBER
DECIDE `numbers are big`
    IF     x GREATER THAN 1000
       AND y GREATER THAN   250
                          *   2
                            + 2
    OR x GREATER THAN 10000
    OR y GREATER THAN 20000

This method of grouping was inspired by legal sub-paragraphs and sub-lists. Generally, operators bind stronger if they are indented more, and arguments to operators should be indented more than the operators themselves.

Example:

    FALSE
AND    TRUE
    OR TRUE

yields FALSE, whereas

       FALSE
   AND TRUE
OR TRUE

yields TRUE.

Ditto Syntax

Strunk & White said: "Omit needless words". Edward Tufte talked about "data-ink".

L4 introduces "ditto syntax". A caret (^) expands to the word appearing directly above it, in the same column.

Judicious use of this convention improves the readability of multiline expressions that would otherwise be over-noised with boilerplate. Linguistically, this reads as an example of "conjunction reduction", or "ellipsis". We use a caret instead of a literal ellipsis ("...").

AKA

Aliases can be created inline by inserting an AKA xxx after an expression.

Last updated