L4 Syntax Reference

L4's syntax is designed to be readable by legal professionals while maintaining the precision needed for computation. This section documents syntax patterns, rules, and special features.

Overview

Key syntax features:

  • Layout-sensitive - Uses indentation like Python
  • Natural language style - Reads like structured English
  • Annotations - Metadata for documentation and generation
  • Directives - Compiler commands for testing and evaluation
  • Special symbols - Backticks, ditto marks, ellipsis, etc.

Core Syntax Features

Layout Rules

Indentation-based grouping instead of braces.

Key Concepts:

  • Blocks defined by indentation level
  • Consistent indentation required
  • Replaces { } and ; separators
  • Pythonic style

Example:

-- Example: Layout rules (indentation-based grouping)
-- Demonstrates how indentation defines code blocks

DECLARE Person
  HAS name IS A STRING    -- Indented: part of declaration
      age IS A NUMBER     -- Same level: another field
      
john MEANS Person WITH
  name IS "John Doe"
  age  IS 30

#EVAL john's name

Comments

Documentation and notes in code.

Example:

-- Example: Comments in L4
-- This demonstrates line and block comments

-- This is a line comment
ASSUME age IS A NUMBER  -- inline comment

{- This is a
   multi-line
   block comment -}

ASSUME name IS A STRING

#EVAL age

Note: Both {- -} and /* */ styles work for block comments.


Identifiers

Names for variables, functions, and types.

Example:

-- Example: Identifiers in L4
-- Demonstrates regular and quoted identifiers

-- Regular identifiers
ASSUME age IS A NUMBER
ASSUME taxRate IS A NUMBER

-- Quoted identifiers with spaces
ASSUME `total tax` IS A NUMBER
ASSUME `Section 2(a)` IS A STRING

#EVAL age

Regular: Start with letter, continue with letters/numbers/underscore
Quoted: Use backticks for spaces/special characters

Case Sensitivity:

  • Keywords: UPPERCASE only
  • Identifiers: Case-sensitive (ageAge)

Annotations

Metadata attached to declarations.

@desc

Human-readable descriptions.

Example:

-- Example: Annotations in L4
-- Demonstrates @desc, @nlg, and @ref annotations

@desc "Person's age in years"
ASSUME age IS A NUMBER

@nlg "the applicant's age"
ASSUME applicantAge IS A NUMBER

@ref "Section 4(1)(a) of the Act"
ASSUME eligible IS A BOOLEAN

#EVAL age

@nlg

Natural language generation hints.

Inline form: The applicant [is %age% years old].

See

-- Example: Annotations in L4
-- Demonstrates @desc, @nlg, and @ref annotations

@desc "Person's age in years"
ASSUME age IS A NUMBER

@nlg "the applicant's age"
ASSUME applicantAge IS A NUMBER

@ref "Section 4(1)(a) of the Act"
ASSUME eligible IS A BOOLEAN

#EVAL age

@ref

Cross-references to legal sources.

Inline form: The applicant <<must be at least 18 years old>>.

See

-- Example: Annotations in L4
-- Demonstrates @desc, @nlg, and @ref annotations

@desc "Person's age in years"
ASSUME age IS A NUMBER

@nlg "the applicant's age"
ASSUME applicantAge IS A NUMBER

@ref "Section 4(1)(a) of the Act"
ASSUME eligible IS A BOOLEAN

#EVAL age

@ref-src / @ref-map

Source references and mappings.

See

-- Example: Annotations in L4
-- Demonstrates @desc, @nlg, and @ref annotations

@desc "Person's age in years"
ASSUME age IS A NUMBER

@nlg "the applicant's age"
ASSUME applicantAge IS A NUMBER

@ref "Section 4(1)(a) of the Act"
ASSUME eligible IS A BOOLEAN

#EVAL age

@export

Mark declarations for export.

Example: @export "public_api"


Directives

Compiler commands for testing and evaluation. Directives begin with # and appear at the top level of a file.

#EVAL

Evaluate an expression and display the result. Used for testing functions and inspecting computed values.

Syntax:

#EVAL expression

Examples:

#EVAL `is adult` 21        -- evaluates to TRUE
#EVAL `tax owed` 75000     -- evaluates to the computed number
#EVAL 2 PLUS 2             -- evaluates to 4

See also:

-- Example: Annotations in L4
-- Demonstrates @desc, @nlg, and @ref annotations

ASSUME `person age` IS A NUMBER

@nlg "the applicant's age"


@ref "Section 4(1)(a) of the Act"


#EVAL `person age`

#EVALTRACE

Evaluate an expression and display the full execution trace, showing each step of the evaluation.

Syntax:

#EVALTRACE expression

#TRACE

Evaluate a deontic (regulative) expression and display the obligation trace. Shows the sequence of obligations, which parties must act, deadlines, and the resulting state (FULFILLED or BREACH).

Syntax:

#TRACE deonticExpression AT startTime WITH
  PARTY partyName DOES action AT eventTime
  ...

Examples:

#TRACE paymentObligation AT 0 WITH
  PARTY Alice DOES pay 100 AT 15

#TRACE saleContract AT 0 WITH
  PARTY Seller DOES delivery AT 2
  PARTY Buyer DOES payment 100 AT 5

See also: Regulative Rules for the deontic keywords used with #TRACE

#CHECK

Type check an expression without evaluating it.

Syntax:

#CHECK expression

#ASSERT

Assert that an expression evaluates to TRUE. Used for automated testing.

Syntax:

#ASSERT expression

Example:

#ASSERT 2 PLUS 2 EQUALS 4

Special Syntax

Ditto

Copy from line above using ^.

Example:

-- Example: Ditto (^) syntax
-- Copy tokens from previous line (one ^ per token)

eligible MEANS TRUE

john  MEANS eligible
mary  ^     ^        -- Copies "MEANS eligible"
alice ^     ^        -- Also copies "MEANS eligible"

#EVAL john
#EVAL mary
#EVAL alice

Rules:

  • One ^ per token to copy
  • Copies tokens from line directly above
  • Useful for repetitive declarations

OF (Positional Argument Syntax)

Multi-purpose structural keyword that introduces comma-separated argument lists. Without OF, arguments must be space-separated on the same line or indented on subsequent lines.

Contexts where OF appears:

Context Example
Function application add OF 3, 4
Sum type declaration IS ONE OF Red, Green, Blue
Type constructor LIST OF Person
Record construction Pair OF 10, 20
Pattern matching WHEN Pair OF x, y THEN ...

Examples:

-- With OF: comma-separated args on one line
result1 MEANS add OF 3, 4
result2 MEANS foldr OF add, 0, numbers

-- Without OF: space-separated on same line
result3 MEANS add 3 4

OF is optional in function application -- add OF 3, 4 and add 3 4 are equivalent. But for multi-argument calls, OF with commas is often clearer than relying on whitespace parsing.

See also: Types reference for OF in type contexts


TO (Function Type Syntax)

Used in function type annotations to separate input types from the return type.

Syntax:

FUNCTION FROM Type1 AND Type2 TO ReturnType

Note: TO is a reserved keyword used only in function type annotations. In deontic rules, to appearing in an action (e.g. deliver goods to buyer) is part of the mixfix expression, not the TO keyword.


Genitive

Record field access using 's.

Example:

-- Example: Genitive ('s) for field access
-- Demonstrates possessive syntax for record fields

DECLARE Person
  HAS `full name` IS A STRING
      age         IS A NUMBER

DECIDE `the applicant` IS Person WITH
  `full name` IS "John Doe"
  age         IS 30

-- Using genitive (reads like English)
DECIDE `applicant age using genitive` IS `the applicant`'s age

-- Equivalent to using THE ... OF
DECIDE `applicant age using THE OF` IS age OF `the applicant`

#EVAL `applicant age using genitive`
#EVAL `applicant age using THE OF`

Section Markers (§)

Organize code into named, nested scopes using §, similar to sections in legislation. Definitions in different sections do not shadow each other; the compiler creates fully qualified name bindings for disambiguation.

Levels:

  • § -- Top-level section
  • §§ -- Subsection
  • §§§ -- Sub-subsection

Example:

-- Example: Section markers (§)
-- Demonstrates organizing code into sections

§ `Eligibility Rules`

age MEANS 21
citizen MEANS TRUE

§§ `Age Requirements`

ageEligible MEANS age >= 18

§§ `Citizenship Requirements`

citizenshipEligible MEANS citizen EQUALS TRUE

#EVAL ageEligible
#EVAL citizenshipEligible

Qualified access: When the same name exists in multiple sections, consumers must qualify to disambiguate. This parallels how legislation scopes definitions ("for purposes of subsection 2, X means ...").

§ `Part VII`

§§ `Subsection 2`
`age of majority` MEANS 18

§§ `Subsection 3`
`age of majority` MEANS 21

-- Consumer must qualify:
DECIDE `is adult under sub 2` IF
    age >= `Part VII`'s `Subsection 2`'s `age of majority`

Section aliases: Use AKA to create shorter names for qualified references:

§ `Definitions for Part VII` AKA defs
  taxableIncome MEANS 50000

result MEANS defs.taxableIncome   -- via alias

Literals

Numbers

Integers: 42, -17, 0
Rationals: 3.14, -0.5, 2.718

Strings

Basic: "hello world", "L4 language"
Escape Sequences: \n (newline), \" (quotes), \\ (backslash)

Booleans

TRUE, FALSE

Lists

LIST 1, 2, 3, EMPTY, 1 FOLLOWED BY 2 FOLLOWED BY EMPTY


Symbols

Parentheses

( ) - Grouping and tuples.

Examples: (age PLUS 5) TIMES 2, PAIR OF 1, 2

Brackets

[ ] - Inline NLG annotations.

Example: The applicant [is %age% years old].

Angles

<< >> - Inline reference annotations.

Example: The applicant <<must be 18 or over>>.

Braces

{ } - Block comments (alternative).

Example: {- Block comment -}

Other Symbols

  • , - Separator
  • ; - Statement separator (rarely needed with layout)
  • . - Decimal point
  • : - Type signature separator
  • % - Percent numbers, NLG expression delimiter
  • ^ - Ditto (copy above)
  • ... - Asyndetic AND
  • .. - Asyndetic OR

Syntax Conventions

Naming Conventions

Variables and Functions:

  • camelCase: taxRate, calculateTotal
  • snake_case: tax_rate, calculate_total
  • Spaces with backticks: `tax rate`

Types:

  • PascalCase: Person, TaxBracket
  • Prefer nouns

Constants:

  • UPPERCASE: MAX_AGE, DEFAULT_RATE

Indentation

  • 2 spaces or 4 spaces (choose one, be consistent)
  • No tabs
  • Align related items vertically

Line Length

  • Recommended: 80-100 characters
  • Legal text may be longer for readability

Style Guide

Readability

  • Use whitespace liberally
  • Add comments for complex logic
  • Prefer textual operators in legal contexts

Consistency

  • Follow project conventions
  • Use linter/formatter when available
  • Be consistent within a file
  • Structure code to mirror legal text
  • Use legal terminology in identifiers
  • Preserve section/subsection hierarchy

Common Patterns

Type Declarations

Example:

-- Example: Record type declaration
-- Demonstrates product types with named fields

DECLARE Person
  HAS `full name` IS A STRING
      age         IS A NUMBER

-- Example: Creating a person record
`the applicant` MEANS Person WITH
  `full name` IS "John Doe"
  age         IS 30

#EVAL `the applicant`'s `full name`
#EVAL `the applicant`'s age

Function Definitions

Example:

-- Example: Function type
-- Demonstrates function type signature

GIVEN x IS A NUMBER
      y IS A NUMBER
GIVETH A NUMBER
add x y MEANS x PLUS y

#EVAL add 5 3

Pattern Matching

Example:

-- Example: Enum type declaration
-- Demonstrates sum types with named constructors

DECLARE Color IS ONE OF
  Red
  Green
  Blue

-- Example usage
`my favorite color` MEANS Red

`name of the color` MEANS
  CONSIDER `my favorite color`
  WHEN Red   THEN "red"
  WHEN Green THEN "green"
  WHEN Blue  THEN "blue"

#EVAL `name of the color`

See Also