Statements & syntax

A newline ends a statement. There are no semicolons.

name = "Ecko"
count = 1

Continuation

An expression continues across a newline only when one of these is true:

  • the line ends with a binary operator
  • the next line starts with |> or .
  • you are inside (...) or [...], where newlines are insignificant
total = 1 +
    2                    # trailing operator

result = data
    |> filter(pred)      # leading |>
    |> map(transform)

xs = [
    1,
    2,
]                        # inside brackets

These three rules cover the shapes that read well multi-line - arithmetic, pipelines, and collection literals - without needing a line-continuation character. Anything else is a new statement, so a missing operator is a syntax error rather than a silently different program.

Blocks are expressions

{ ... } evaluates to its last expression, which is why if and match can be assigned:

status = if age >= 18 { "adult" } else { "minor" }

for and while evaluate to null; loop evaluates to its break value.

Comments

# to end of line. No block comment form. ## is a documentation comment.

Formatting is not a choice

ecko fmt has one canonical style and no options. Any new syntax in the language must round-trip through it byte-identically, which is enforced by the compiler's own test suite over every example in the repository.

Precedence, loosest to tightest

|>  <  or  <  and  <  comparisons  <  bor  <  bxor  <  band
    <  shl/shr  <  ..  <  + -  <  * / %  <  unary

|> binds loosest of everything, which is what makes a pipeline read as a sequence of steps rather than needing parentheses at each stage. Bitwise operators are words because | belongs to pipelines and lambdas, and ecko fmt adds clarifying parentheses wherever bitwise mixes with arithmetic.