This document specifies the default syntax of the Mech programming system, which is designed for developing reactive systems like robots, games, and user interfaces. The syntax specified herein is one of many possible syntaxes and interfaces for Mech, but it may be thought of as the default texual representation of Mech.
This specification starts by defining the most atomic elements of the language, and then builds up to more complex structures.
This document is for:
Language designers who want to implement a parser for Mech.
Tool developers who want to build tools that work with Mech code.
Developers who want to understand the syntax and structure of Mech programs.
The grammar is specified using extended Extended Backus-Naur Form (EBNF):
╭────────┬──────────┬────────────────────────────╮ │ Symbol │ Meaning │ Semantics │ ├────────┼──────────┼────────────────────────────┤ │ "abc" │ terminal │ string literal "abc" │ │ p1, p2 │ sequence │ p1 followed by p2 │ │ p1 | p2│ choice │ p1 or p2 │ │ [p, q] │ list │ list of p deliniated by q │ │ *p │ repeat 0 │ p for 0 or more times │ │ +p │ repeat 1 │ p for 1 or more times │ │ ?p │ optional │ p for 0 or 1 time │ │ >p │ peek │ p; do not consume input │ │ ¬p │ not │ does not match p │ │ (...) │ group │ incrase precedence │ ╰────────┴──────────┴────────────────────────────╯
The grammar grammar:
Mech source code can be stored in files with either the
.mec
or
.🤖
extension.
Source code is ecoded with UTF-8, which allows for Unicode support directly in the code. This choice has several benefits:
Makes code more accessible to non-English speakers
Enables domain experts to use notation from their fields directly in code
Allows for more expressive and intuitive naming conventions
Supports mathematical notation that closely resembles standard written forms
Literate programming, introduced by Donald Knuth, presents programs as structured documents where explanations take precedence over code. In Mech, we support this concept through a format called Mechdown, a superset of Markdown with extensions to support embedded Mech syntax. This document is formatted with Mechdown to demonstrate how it is used.
For more information, see the Mechdown Section .
Whitespace in Mech is used to separate tokens and is generally ignored. This includes spaces, tabs, and newlines. However, whitespace can be significant in certain contexts:
In lists, whitespace is used to separate items.
In matrix and table definitions, whitespace deliniates columns and rows.
In formulas, whitespace is required around operators.
Semicolons and commas are treated as whitespace in most cases. Except in these contexts:
Semicolons can be used to separate statements so they can be written inline.
Semicolons can be used in a matrix to separate rows, so they can be written inline.
For more information, see the Whitespace design document .
Tokens are the smallest units of meaning in Mech. They include letters, digits, punctuation, and special symbols.
Some Unicode characters are reserved for box drawing, and therefore are excluded from includsion in valid identifiers.
Identifiers start with letters or most UTF-8 encoded emoji characters, and can contain alphanumeric, most emojis, /, *, +, -, and ^ characters.
Examples:
There are only two keywords in Mech:
true false
Combined with Mech's Unicode support, this allows users to write code in their native language without the need to learn English keywords.
Punctutation:
. ! ? , : ; ' "
Symbols:
& | @ / # = \ ~ + - * ^ _
Grouping symbols:
( ) < > { } [ ]
Operators:
Assign := = += -= *= /= ^= Arithmetic + - * / ^ % Split >- -< Matrix ** · ⨯ \ ' Logic | & xor ⊕ ⊻ ! ¬ Set ∪ ∩ ∖ ∁ ⊆ ⊇ ⊊ ⊋ ∈ ∉ Range .. ..= Condition != ¬= ≠ == > < >= ≤ ≥ Transition => -> ~> Guard | │ ├ └
Examples:
An integer literal is a sequence of digits representing a whole number. Mech supports decimal, binary, octal, and hexadecimal integer literals, each distinguished by a unique prefix:
Decimal: A sequence of digits without a prefix (e.g., 42, 123456).
Binary: Prefixed with 0b, containing only 0 and 1 (e.g., 0b1010).
Octal: Prefixed with 0o, containing digits 0-7 (e.g., 0o755).
Hexadecimal: Prefixed with 0x, containing digits 0-9 and a-f or A-F (e.g., 0x1A3F).
Examples:
Examples:
Examples:
Examples:
Examples:
Examples:
Data structures in Mech can be broadly classified into two categories: ordered collections that allow duplicated elements, and unordered collections that do now allow duplicated elements.
Ordered elements, duplicates allowed
Vector (Nx1)
Row Vector (1xN)
Matrix (N-D)
Tuple
Unordered elements, no duplicates
Record
Table
Set
Map
Each data structure has its own semantics, which will be described in this section.
A matrix is a numbered sequence of elements of a single kind, arranged in rows and columns. The number of elements is called the length of the matrix and is never negative. The number of rows and columns is called the shape of the matrix. The shape is always a pair of non-negative integers.
The shape is part of the matrix's kind; it must evaluate to a non-negative constant representable by a tuple of kind
(index,index)
. The shape of matrix
A
can be discovered using the built-in function
matrix/shape()
. The elements can be addressed by index indices
(1,1)
through
matrix/shape(A)
.
Matrix kinds are always two-dimensional, so row vectors and column vectors are also represented as matrices with a single row or column, respectively.
Examples:
Fancy matrix syntax is supported so that formatted output from the Mech REPL can be used as program source or input.
┏ ┓ ┃ 1 2 3 ┃ ┃ 4 5 6 ┃ ┗ ┛
The elements of a matrix are indexed in the following ways:
1D - by their position in the matrix, starting from 1, in a column-major order starting at the top left corner of the matrix and proceeding down and to the right. The last element of the matrix, called the end of the matrix, is the most bottom right element.
2D - by the row and column index, starting from 1 for each.
Negative indices indicate counting from the end of the matrix. For example,
-1
is the last element,
-2
is the second to last element, and so on.
Examples:
Examples:
Examples:
x
:
<
f32
>
|
y
:
<
u8
>
|
---|---|
1.2 | 9 |
1.3 | 8 |
Examples:
Operators: