Mech Platform Specification

Introduction

Source Code Representation

File Format

Literate Programming and Mechdown

Whitespace

Lexical Elements

Tokens

Character Classes

Alphanumeric Sequences

Whitespace and Separators

Operators and Text

Operators

Punctutation

Examples

Symbols

Examples

Grouping Symbols

Examples

Text

Comments

Examples

Keywords

Identifiers

Examples

Literals

Kinds

Kind

Examples

Numbers

Integer Numbers

Kind
Examples

Fractional Numbers

Kind
Examples

Complex Numbers

Kind
Examples

Strings

Kind

Examples

Boolean

Kind

Examples

Atoms

Kind

Examples

Empty

Kind

Examples

Data Structures

Matrix

Kind

Examples

Semantics

Indexing

Operations

Set

Kind

Examples

Semantics

Operations

Map

Kind

Examples

Semantics

Operations

Tuple

Kind

Examples

Semantics

Operations

Table

Kind

Examples

Semantics

Record

Kind

Examples

Semantics

Expressions

Formula

Operator Precedence

Evaluation Order and Associativity

Arithmetic

Matrix

Comparison

Logical

Set

Range

Indexing

Slicing

Examples

Dot Index

Examples

Swizzle

Examples

Statements

Variable Define

Examples

Variable Assign

Op-Assign

Examples

Enum Define

Examples

Kind Define

Examples

Mech Programs

Mechdown

Document Structure

Titles

Paragraphs

Paragraph Elements

References

Examples

Lists

Thematic Breaks

Code Blocks

Examples

Equations

Callout Blocks

Tables

Example

Images

Example

Mech Extensions

Mech Code Blocks

Examples

Inline Mech Code

Examples

Notation

Works Cited

Mech Platform Specification

Introduction

This document defines the default syntax and semantics of the Mech programming platform, which is designed for building reactive systems such as robots, games, and user interfaces. As a platform, Mech can support multiple syntaxes and interfaces; the syntax presented here is just one possible option. However, the semantics of data types, data structures, and other core programming constructs described in this document are fundamental to Mech and must be supported by any system targeting the platform.

This document is for:

  • Language designers who want to target Mech as a backend.

  • Developers creating tools to interact with Mech code.

  • Anyone who wants to understand the syntax and structure of Mech programs.

Source Code Representation

File Format

Mech source code must be stored in files with a .mec extension.

Source code is ecoded with UTF-8, which allows for Unicode support in identifiers, strings, and comments.

Literate Programming and Mechdown

Mech supports literate programming as a first-class language feature. Literate programming is when code and documentation are interwoven in a single source file, allowing developers to write code that is both executable and well-documented.

Mech supports this concept through a format called Mechdown, a Markdown dialect with extensions to support embedded Mech programs. This document is formatted with Mechdown to demonstrate its features.

For more information, see the Mechdown Section.

Whitespace

Whitespace includes spaces (), tabs (\t), carriage returns (\r) and newlines (\n). Although it is generally ignored, whitespace is be significant in several contexts:

  • In lists, whitespace can be used to separate items.

  • In matrix and table definitions, whitespace can deliniate 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 Syntax Design Document.

Lexical Elements

Tokens

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 valid identifiers.

Character Classes

alpha :="a".."z" | "A".."Z" ;
digit :="0".."9" ;
emoji :=+emoji-grapheme ;
bin-digit :="0" | "1" ;
hex-digit :=digit | "a".."f" | "A".."F" ;
oct-digit :="0".."7" ;

Alphanumeric Sequences

word :=+alpha ;
digit0 :=*digit ;
digit1 :=+digit ;
number :=digit1 ;
alphanumeric :=alpha | digit ;
digit-sequence :=digit, *((underscore, digit) | digit) ;

Whitespace and Separators

whitespace :=space | new-line | tab ;
ws0 :=*whitespace ;
ws1 :=+whitespace ;
stb :=space | tab ;
list-separator :=ws0, ",", ws0 ;
enum-separator :=ws0, "|", ws0 ;

Operators and Text

Operators

Category

Operators

Assign

:= = += -= *= /= ^=

Arithmetic

+ - * / ÷ ^ %

Condition

!= ¬= == > < >=

Matrix

** · \ '

Logic

|| && ^^ ¬ !

Set

Table

Range

.. ..=

Transition

=> -> ~>

Guard

|

Punctutation

Examples
. ! ? , : ; " ' 

Symbols

Examples
& $ | % @ / # = \ ~ + - * ^ _

Grouping Symbols

Examples
( ) < > { } [ ]

Text

Comments

comment-sigil :="--" | "//" ;

There are two options for single line comments in Mech:

  • -- for those familiar with languages like Lua, Haskell, and SQL.

  • // for those familiar with languages like C, C++, Java, and JavaScript.

There is no difference between the two, and they can be used interchangeably.

Because Mech has a focus on literate programming, comments have less of an emphasis compared to other programming languages. For example, there is no support for block comments in Mech; instead, programmers are encouraged to use Mechdown to express their comments in a more structured way.

Therefore, comments are primarily used for writing notes inline with code that cannot be broken out into a paragraph.

Examples

Here are some ways to write a comment in Mech:

  -- Comment prefix with --
  // Comment prefixed with // (renders with --)
  -- Supports formatting like **bold**, __underline__, `inline code`, and [links](https://example.com).
  x := 1 -- Comment after an expression

When parsed and rendered, these become:

--

Comment prefix with --

--

Comment prefixed with // (renders with --)

--

Supports formatting like bold, underline, inline code, and links.

x:=1--

Comment after an expression

One special ability comments have is they can be used to print out the evaluation of a Mech code statement.

qq:=10*20--

The value of qq is qq

Keywords

There are only two keywords in Mech: true and false. Because Mech is designed to be used by non-English speakers, the syntax allows for an alternative representation, which can be used in place of the English keywords.

Keyword

Alternative

true

false

This allows users to write code in their native language without the need to learn English keywords.

Identifiers

identifier :=(alpha | emoji), *(alpha) ;

Identifiers start with letters or most UTF-8 encoded emoji characters, and can contain alphanumeric, most emojis, /, *, +, -, and ^ characters.

Examples

Hello-Worldio/printΔx^2🤖A*

Note: Underscores _ are not allowed in identifiers, as kebab-case is the preferred style in Mech. Underscores are reported as syntax errors.

Literals

Mech supports several types of literals, which are used to represent values in the code. Each literal type has its own syntax and semantics. Each literal has an associated "kind", which describes the data type of the literal. Mech supports the following literal types:

  • Number - Represents numeric values, including integers, floating-point numbers, and complex numbers.

    • Real - Real numbers, including integers and floats.

      • Integer - Whole numbers, which can be positive, negative, or zero.

        • Signed - Can represent both negative and positive values.

          • i8 - 8-bit signed integer

          • i16 - 16-bit signed integer

          • i32 - 32-bit signed integer

          • i64 - 64-bit signed integer

          • i128 - 128-bit signed integer

        • Unsigned - Can only represent zero and positive values.

          • u8 - 8-bit unsigned integer

          • u16 - 16-bit unsigned integer

          • u32 - 32-bit unsigned integer

          • u64 - 64-bit unsigned integer

          • u128 - 128-bit unsigned integer

        • Floating-point - Decimal numbers, which can represent fractions.

          • f32 - 32-bit floating-point number, can represent integers up to 2^24.

          • f64 - 64-bit floating-point number, can represent integers up to 2^53.

      • Fractional - Decimal numbers with fractional components.

        • f32 - 32-bit floating-point number

        • f64 - 64-bit floating-point number

        • r64 - 64-bit rational number, which can be represented as a fraction of two i64 integers.

    • Complex - Represent imaginary components of complex numbers.

      • c64 - 64-bit complex number, which can be represented as a pair of f64 values corresponding to the real and imaginary parts.

  • String

    • string - A sequence of UTF-8 characters representing text.

  • Boolean

    • bool - Represents logical truth values.

  • Atom - A symbolic constant, often used for tags or enums.

  • Empty

    • _ - Represents an empty value, placeholder, or the absence of a value.

Kinds

kind-annotation :="<", kind, ">" ;
kind-empty :=+"_" ;
kind-atom :="`", identifier ;
kind-map :="{"
, ":"
, "}"
;
kind-fxn :="("
, ?[",",kind]
, ")"
, "="
, "("
, ?[",",kind]
, ")"
;
kind-brace :="{"
, [",",kind]
, "}"
, ?":"
, ?[",",literal]
;
kind-bracket :="["
, [",",kind]
, "]"
, ?":"
, ?[",",literal]
;
kind-tuple :="(", [",",kind], ")" ;
kind-scalar :=identifier ;

Kinds are used to specify the type of a literal or expression in Mech. Kinds are specified with a syntax structure called a "kirby" e.g. <string>, which indicates a String data type; or <[u64]:3,1>, which indicates a 3x1 matrix of 32-bit unsigned integeres.

Kind

The kind of a kind is itself. For example, the kind <[u8]:2,3> has the kind <[u8]:2,3>.

Examples

<_>--

Empty

<`A>--

Atom

<{A:B}>--

Map

<{A}>--

Set

<[A]>--

Matrix

<(A,B,C)>--

Tuple

<|x<A>,y<B>|>--

Table

<{x<A>,y<B>}>--

Record

Numbers

Integer Numbers

integer-literal :=+digit ;
decimal-literal :="0d", +digit ;
hexadecimal-literal :="0x", +hex-digit ;
octal-literal :="0o", +oct-digit ;
binary-literal :="0b", +bin-digit ;

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).

  • Hexadecimal: Prefixed with 0x, containing digits 0-9 and a-f or A-F (e.g., 0x1A3F).

  • Octal: Prefixed with 0o, containing digits 0-7 (e.g., 0o755).

  • Binary: Prefixed with 0b, containing only 0 and 1 (e.g., 0b1010).

Kind

By default, Mech can represent integers in the following data types:

  • Signed: i8, i16, i32, i64, i128

  • Unsigned: u8, u16, u32, u64, u128

  • Float: f32, f64

Unless specified or inferred, the default data type for integer literals is f64. You can change the datatype of an integer literal by annotating it with a kind, such as or .

Examples
42--

decimal

42--

decimal

0x1234567890ABCDEF--

hexadecimal

0x1234567890abcdef0o12345670--

octal

0b100110101--

binary

Numerical literals annotated with a kind to specify their type:

1234--

1234 as a 64-bit float-point number

1234<i32>--

1234 as a signed 32-bit integer

1234<u8>--

Convert 1234 to an unsigned 8-bit integer (will saturate to 255)

Fractional Numbers

scientific-literal :=(float-literal | integer-literal)
, ("e" | "E")
, ?plus
, ?dash
;
rational-literal :=integer-literal, slash, integer-literal ;
float-literal :=float-decimal-start | float-full ;
float-full :=digit-sequence, ".", digit-sequnce ;
float-decimal-start :=".", digit-sequence ;

A floating-point literal represents a real number, potentially with a fractional component. Mech supports several forms of floating-point literals:

  • Decimal floats: Numbers with a decimal point (e.g., 3.14, .123, 0.0)

  • Scientific notation: A number followed by e or E, then an optional sign and exponent (e.g., 2.5e10, 1e-3)

  • Rational literals: A fraction of two integers separated by / (e.g., 3/4, 22/7) — these may be evaluated as exact values or approximated depending on context.

Kind

Fractional numbers can be represented using various kinds, including:

<f32>--

32-bit floating-point number

<f64>--

64-bit floating-point number

<r64>--

64-bit rational number, which can be represented as a fraction of two i64 integers.

Examples
3.14--

decimal float

0.001--

decimal float

2.5e+10.--

scientific notation

-2.5--

negative float

.123--

leading-dot float

3/4--

rational

By default, floating-point literals are inferred to be of type f64, unless explicitly annotated or inferred from context.

Complex Numbers

complex-number :=real-number, ?("i" | "j") | (("+" | "-"), real-number, ("i" | "j")) ;

A complex number literal represents a number with both real and imaginary parts. To support a wide range of mathematical expressions, Mech allows complex numbers to be expressed with i or j. The real and imaginary parts can be any real number.

Kind
<c64>--

64-bit complex number, which can be represented as a pair of f64 values (real and imaginary parts).

Complex numbers can be represented using the c64 kind, which indicates a 64-bit complex number. This kind is typically represented as a pair of f64 values (real and imaginary parts).

Examples
5i--

purely imaginary number

3+4i--

complex number with real and imaginary parts

2+-3i--

complex number with negative imaginary part

-2+0i--

complex number with negative real part

Strings

string :=quote, *(¬quote, (text | new-line)), quote ;

Strings are enclosed in double quotes " and can contain any character, including whitespace, except for the quote character itself. To include a quote character in a string, it must be escaped with a backslash \.

Strings heap-allocate their contents, so they can be of any length. They are encoded in UTF-8, allowing for Unicode characters.

Kind

<string>--

Represents a sequence of UTF-8 characters.

Examples

"Hello, World!""characters like " and \ are escaped with, \ e.g. \"""This string contains emojis: 🤖, 🐦, and 🐍""Multiline strings are supported"

Boolean

true-symbol :="✓" ;
false-symbol :="✗" ;
english-true-literal :="true" ;
english-false-literal :="false" ;

A boolean literal represents a logical truth value, and can be expressed in either textual or symbolic form. Thre reason Mech supports both is tho allow for code that doesn't contain any English keywords, which is useful for non-English speakers.

Kind

<bool>--

Represents a boolean value, which can be either true or false.

Examples

truefalse

Atoms

atom :="`", identifier ;

An atom is a symbolic constant used to represent a fixed, named value. Atoms are prefixed with a backtick and followed by an identifier. They are used to represent tags, enums, or other symbolic values in the code.

Kind

The kind of an atom is itself. For example, the atom `A has the kind <`A>.

<`A>--

Represents an atom with the name A.

Examples

`A`MyAtom`🐦`Δx^2

Empty

empty :=+underscore ;

Empty literals are used to represent the absence of a value or a placeholder. They are represented by one or more underscores _. Empty literals can be used in various contexts, such as in tables, to indicate missing values.

Kind

<_>--

Represents an empty value.

Examples

____

Data Structures

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.

Matrix

A Matrix is a structured, numbered sequence of elements of a single kind, arranged in rows and columns, enclosed bt square brackets, []. The number of elements in the matrix is called its length, and the shape of a matrix is defined as a pair of non-negative integers representing the number of rows and columns.

Kind

The kind of a matrix includes the type of its elements and its shape. For example, a matrix of unsigned 8-bit integers with 2 rows and 3 columns has the kind <[u8]:2,3>.

Description

Kind

Dynamic matrix

<[u8]>

Col Vector

<[u8]:2>

Row Vector

<[u8]:1,2>

2D Matrix

<[u8]:2,3>

3D Matrix

<[u8]:2,3,4>

Dynamic cols

<[u8]:2,_>

Dynamic rows

<[u8]:_,3>

Examples

--

Empty Matrix

[]--

1x1 Matrix

[
1
]
--

3x3 Matrix

[
1 4 7
2 5 8
3 6 9
]
--

3x2 Matrix

[
1 3 5
2 4 6
]
--

1x3 Row Vector

[
1
2
3
]
--

3x1 Column Vector

[
1 2 3
]
--

4x1 Column Vector

[
1 2 3 4
]

Semantics

  • Homogeneous Elements: All elements in a matrix must be of the same kind.

  • Fixed Shape: A static matrix's shape (rows, columns) is part of its kind and is always a tuple of non-negative integers.

  • One-Based Access: Elements are accessed using 1-based indexing for both rows and columns.

  • Column-Major Order: Matrix elements are stored and accessed in column-major order.

Matrix kinds are always two-dimensional, so row vectors and column vectors are also represented as matrices with a single row or column, respectively.

Indexing

Matrix elements can be accessed using either 1D or 2D indexing:

  • 1D Indexing (Column-Major Order): Elements are stored in column-major order, meaning the first element is the top-left element, proceeding down the first column before moving to the next.

  • 2D Indexing: Elements can be referenced using [row, column] notation, starting from 1 for both indices.

  • Negative Indices: Negative indices count from the end of the matrix, with -1 being the last element.

See the indexing section for more details on syntax and semantics of matrix indexing.

Operations

By default, basic operations on matrices are broadcast, meaning they are applied element-wise across the matrix. For example:

[
1
2
3
]
+[
4
5
6
]
--

Results in [5 7 9]

This works as long as both matrices have the same shape. If not, the operation will fail with a type error at compile time.

The exception is if either of the operands are scalar, then the scalar is broadcast across the matrix. For example:

[
1
2
3
]
+10
--

Results in [11 12 13]

10+[
1
2
3
]
--

Results in [11 12 13]

Set

set :="{"
, ws0
, ws0
, "}"
;
empty-set :=table-start
, ws0
, ws0
;

A Set is defined using curly braces {} and contains a comma-separated list of expressions. Sets do not maintain order and contain only unique elements.

Kind

The kind of a set consists of:

  • The kind of the elements

  • The number of elements, which can be dynamic or fixed

<{u8}>--

Generic set of unsigned 8-bit integers

<{u8}:3>--

Set of 3 unsigned 8-bit integers

<{{i8}}>--

Set of sets of signed 8-bit integers

Examples

{}--

Empty set

{1}--

Singleton set with one element

{1.2, 3.4, 5.6}--

Set of floats

{"a", "b", "c"}--

Set of strings

{{1, 2}, {3, 4}}--

Nested set of sets

Edge Cases

  • {} represents an empty set.

  • {1, 1, 2} results in {1, 2} due to uniqueness constraints.

  • {1, "hello"} results in a type error due to homogeneity constraints.

Semantics

  • Homogeneity: All elements in a set must be of the same type.

  • Unordered: The order of elements within a set is not preserved.

  • Uniqueness: Duplicate elements are not allowed in a set.

Operations

  • Insertion: Adding an element to a set does not affect its order and only - succeeds if the element is not already present.

  • Deletion: Removing an element, if present, maintains the set property.

  • Union: Combines two sets, keeping only unique elements.

  • Intersection: Produces a set containing elements common to both sets.

  • Difference: Returns a set containing elements in the first set but not in the second.

Map

map :="{"
, ws0
, ws0
, "}"
;
mapping :=ws0
, ws0
, ":"
, ws0
, ws0
;

A Map is defined using curly braces {} and contains a set of key-value mappings. Each key is unique and associated with a corresponding value.

Kind

The kind of a map consists of:

  • The kind of the keys

  • The kind of the values

  • The number of key-value pairs, which can be dynamic or fixed

<{string:u8}>--

A map of strings to unsigned 8-bit integers

<{string:{string:u8}}>--

A map of strings to a map of strings to unsigned 8-bit integers

Examples

{_:_}--

Empty map

{"a":1}--

Map with a single key-value pair

{1:0xA, 2:0xB, 3:0xC}--

Map with multiple key-value pairs

{"a":{"b":10}}--

Nested map

{"a":10, "b":20, "c":30}--

Multiline map

Edge Cases

  • {_:_} represents an empty map.

  • If the map is mutable, inserting a duplicate key overwrites the previous value

  • {1: "hello", 2: "world"} is valid, but {1: "hello", "one": "world"} results in an error, as the keys are not homogenous.

Semantics

  • Key Uniqueness: Each key in a map must be unique.

  • Unordered: The order of key-value pairs within a map is not preserved.

  • Key-Value Association: Each key is mapped to exactly one value.

Operations

  • Insertion: Adding a key-value pair updates the map. If the key already exists, its value is updated.

  • Deletion: Removing a key-value pair removes the key and its associated value.

  • Lookup: Retrieving the value associated with a key.

  • Merge: Combining two maps, where duplicate keys take precedence from the second map.

Tuple

tuple :="(", ?[expression,","], ")" ;
tuple-struct :=atom
, "("
, ")"
;

A Tuple is defined using parentheses () and contains an ordered collection of elements, which can be of different types.

Kind

<(u8,string)>--

Two-tuple of u8 and string

<(u8,u8,u8)>--

Three-tuple of u8s

Examples

()(1)(1,1,3)(1,(2,3))(1,true,"Hello")([
1
2
3
4
]
,7,false)

Edge Cases:

  • () represents an empty tuple.

  • (1) is a single-element tuple, not a parenthetical expression that evaluates to 1.

  • Tuples maintain the type of each element, so (1, "hello") has the kind <(f64,string)>,, unlike sets which require homogeneity.

Semantics

  • Ordered: The order of elements within a tuple is preserved.

  • Heterogeneous: A tuple can contain elements of different types.

  • Immutable: Once created, the elements in a tuple cannot be changed.

Operations

  • Access: Elements can be accessed by their position (zero-based index).

  • Concatenation: Tuples can be combined to form a larger tuple.

  • Decomposition: Tuples can be unpacked into individual variables.

Table

A Table represents a structured collection of records, where each record consists of multiple fields (columns). Tables allow organizing data in a flexible, expressive manner.

Kind

A table's kind includes the column types and table dimensions. For example:

<|x<u8>,y<string>,z<[u8]:1,3>|:4>

This denotes:

  • Columns: |x, y, z<[u8]:3>|

    • x: An unsigned 8-bit integer column.

    • y: A string column.

    • z<[u8]:1,3>: A column containing row vectors of u8 with a fixed length of 3 elements.

  • Shape: The 4 indicates there are 4 rows in the table.

    • An underscore _ can be used to indicate that the number of rows is dynamic,

    • Rows can be omitted if the number of rows is to be inferred from an expression.

The kind of a table row is equivalent to a record with the same column kinds. Each row of the table has kind:

<{x<u8>,y<string>,z<[u8]:1,3>}>--

A table row is a record.

The kind of a table column is equivalent to a vector of the table column kind. For example the kind of the first column in the above table is:

<[u8]:1,3>--

A table column is a vector.

Examples

Tables are enclosed in {} and contain a header row specifying column names and kinds. The pipe | separates the header from the data rows.

x<f32>
y<u8>
1.2 9
1.3 8

This defines a table with two columns:

  • x: A floating-point column.

  • y: An unsigned 8-bit integer column.

The same table can be written in a compact, inline format using semicolons | to separate rows.

| x y | 1.2 9 | 1.3 8 |

Where the first cell is the header row, and the subsequent cells are the data rows, with each column separated by a space or comma.

Semantics

  • Structured: Each record consists of ordered fields (columns).

  • Heterogeneous: Fields can have different kinds (types).

  • Homogeneous: Each row has a similar structure, with the same fields.

  • Sparse: Tables allow missing values (denoted by _).

Any Fields

The * is the "any" kind and allows columns to contain data from mixed kinds.

x<*>
y<*>
1.2 true
"Hi" 8<u8>

Here, x holds both floats and strings, and y holds both integers and booleans. This can be useful for dealing with data whose type is not known at compiletime.

Incomplete Tables

When used as a value in a table, _ indicates that a cell is missing and will be filled in later.

x<u8>
y<string>
z<[u8]:1,3>
_ "a" [
1
2
3
]
4 "b" _
7 _ [
7
8
]

Fancy Representation

The Mech REPL prints tables using a fancy represntation, which is valid as input to a Mech program as well. The above table is equavlent to the following fancy table:

╭───────────────────────────────────╮
│ x   y  z<[u8]:1,4?> │
├────────┬───────────┬──────────────┤
│   _    │    "a"    │   [1 2 3]    │
├────────┼───────────┼──────────────┤
│   4    │    "b"    │      _       │
├────────┼───────────┼──────────────┤
│   7    │     _     │   [7 8 9]    │
╰────────┴───────────┴──────────────╯

Performance Considerations:

Tables are more expressive and flexible than matrices, because they can support missing values and mixed types. However, they may be slower due to additional metadata and dynamic typing associated with each cell, and the unwrapping involved in accessing data.

Table columns are stored in a column matrix with unboxed value element, so operating column-wise on table values can be fast.

However, "any" kinded columns resolve to a column matrix of fully wrapped values, so they will not work with matrix operations that expect unboxed values.

Record

A Record is a collection of named fields, where each field consists of a key-value pair. Records provide a structured way to group related data while allowing heterogeneous types.

Kind

A record's kind describes the types of its fields:

<{x<u8>,y<string>,z<[u8]:1,3>}>

This denotes a record with three fields:

  • x: u8

  • y: string

  • z: [u8]:1,3 (a 1×3 array of u8 values)

Examples

Examples 1: Implicitly Typed Records

{x:1, y:"a", z:[
1
2
3
]
}

This defines a record with three fields:

  • x (implicitly an float).

  • y (implicitly a string).

  • z (implicitly a column matrix of floats).

Example 2: Explicitly Typed Record

{x:1, y:"a", z:[
1
2
3
]
}

Here, each field has an explicit kind:

  • x: A u8 integer.

  • y: A string.

  • z<[u8]:3,1>: A fixed-size 3×1 matrix of u8 integers.

Example 3: Nested Records

{a:{b:1, c:"hi"}, b:[
1 2 3
]
}

This record contains:

  • a: A nested record {b: 1, c: "hi"}.

  • b: A columm matrix [1;2;3].

Semantics

  • Named Fields: Each field is identified by a unique name.

  • Heterogeneous: Fields can have different types.

  • Nested: Records can contain other records.

Defining Records:

Records are enclosed in {} and contain bindings of the form key: value. The type of each field can be inferred or explicitly specified.

Comparison to Tables

  • Records group related attributes of a single entity.

  • Access a field on a record yields a scalar of that type, rather than a column matrix.

  • A table with one row is not the same as a record, as they have to be stored differently internally.

  • A table can be thought of as a vector of records.

Tables represent multiple records (rows) sharing a common structure.

Expressions

expression :=range-expression | formula ;

Expressions define computations in Mech. Most expressions operate elementwise over collections according to the rules of broadcasting.

Broadcasting Rules:

  • Scalars expand to match the shape of collections.

  • Operations between collections are elementwise when shapes are compatible.

  • Higher-dimensional collections expand along singleton dimensions when necessary.

  • Tables support column-wise elementwise operations but use set-based operations (e.g., unions, joins) for whole-table manipulation.

Expression Categories:

  • Arithmetic: Addition, subtraction, multiplication, and division over scalars, vectors, and matrices.

  • Matrix Operations: Matrix multiplication, transposition, and other matrix-specific operations.

  • Comparison: Elementwise relational comparisons (<, >, ==, etc.).

  • Logical Operations: Boolean elementwise operations (and, or, not).

  • Set Operations: Union, intersection, and other set-specific operations.

  • Range Expressions: Constructing sequences of values.

  • Indexing: Accessing elements within collections using direct and computed indices.

Formula

parenthetical-term :=left-parenthesis, formula, right-parenthesis ;
negate-factor :="-", factor ;
formula :=l1, *(range-operator, l1) ;
add-sub-operator :=add | subtract ;
l1 :=l2, *(add-sub-operator, l2) ;
mul-div-operator :=multiply | divide ;
exponent-operator :=exponent ;
l3 :=l4, *(exponent-operator, l4) ;
logic-operator :=and | or | xor ;
l4 :=l5, *(logic-operator, l5) ;

A formula is an expression that follows operator precedence rules and consists of arithmetic, logical, comparison, matrix, and range expressions. Expressions in formulas are evaluated according to their precedence, with higher-precedence operations being evaluated first.

Operator Precedence

Operators in formulas are applied according to the following precedence, from highest to lowest:

  1. Parentheses - Explicit grouping of expressions.

  2. Negation and Logical NOT - Unary operations.

  3. Exponentiation - Raising to a power.

  4. Multiplication, Division, and Matrix Operations - Elementwise and matrix operations.

  5. Addition and Subtraction - Binary arithmetic operations.

  6. Comparison Operators - Elementwise comparisons.

  7. Logical Operators - and, or, xor.

  8. Range Operators - Used in range expressions.

Evaluation Order and Associativity

  • Left-to-right associativity applies to all operators, including exponentiation.

  • Parentheses explicitly override precedence rules.

Arithmetic

add :="+" ;
subtract :="-" ;
multiply :="*" ;
divide :="/" ;
exponent :="^" ;
remainder :="%" ;

Matrix

solve :="\\" ;
dot-product :="·" ;
cross-product :="⨯" ;
matrix-multiply :="**" ;
transpose :="'" ;

Comparison

not-equal :="!=" | "¬=" | "≠" ;
equal :="==" ;
greater :=">" ;
less :="<" ;
greater-or-equal :=">=" | "≥" ;
less-or-equal :="<=" | "≤" ;

Logical

or :="|" ;
and :="&" ;
not :="!" | "¬" ;
exclusive-or :="xor" | "⊕" | "⊻" ;

Set

union :="∪" ;
intersection :="∩" ;
difference :="∖" ;
complement :="∁" | "'" ;
subset :="⊆" ;
superset :="⊇" ;
proper-subset :="⊊" ;
proper-superset :="⊋" ;
element-of :="∈" ;
not-element-of :="∉" ;

Range

range-inclusive :="..=" ;
range-exclusive :=".." ;

Indexing

Slicing

bracket-subscript :="[", [(select-all | range-subscript | formula-subscript),","], "]" ;
brace-subscript :="{", [(select-all | formula-subscript),","], "}" ;
formula-subscript :=formula ;
range-subscript :=range-expression ;
select-all :=":" ;

Examples

    array := [10, 20, 30, 40, 50]
    slice_1 := array[1:]                -- Select all from index 1 to the end (select-all)
    slice_2 := array[1, 3]              -- Range subscript (from index 1 to 3)
    slice_3 := array[2, 4]              -- Another range from index 2 to 4
    slice_4 := array[:4]                -- Select all up to index 4
    slice_formula := array[(x + y), 3]  -- Formula-based subscript, with a calculated index

    matrix := { {1, 2}, {3, 4}, {5, 6} }
    brace_index := matrix{(x * y)}      -- Formula-based indexing within braces

Dot Index

dot-subscript :=".", identifier ;
dot-subscript-int :=".", integer-literal ;

Examples

dot_result_1 := object.field        -- Dot subscript with identifier
dot_result_2 := object.42           -- Dot subscript with integer literal

Swizzle

swizzle-subscript :="."
, ","
, [identifier,","]
;

Examples

    vector := {x: 1, y: 2, z: 3}
    swizzle_result := vector.x, y      -- Swizzling: selecting x and y
    swizzle_combined := vector.x, y, z -- Swizzling: selecting x, y, z

Statements

Variable Define

define-operator :=":=" ;

Examples

    intVar := 10                                -- Variable definition with initialization
    optionalVar := ~stringVar                   -- Variable definition with optional tilde
    varWithExpression := ~calculatedValue * 5   -- Variable definition with expression

Variable Assign

assign-operator :="=" ;

Examples

numbers:=[
1
2
3
4
5
]
numbers[2] = 10 --

Assign value 10 to index 2 of the array

Op-Assign

add-assign-operator :="+=" ;
sub-assign-operator :="-=" ;
mul-assign-operator :="*=" ;
div-assign-operator :="/=" ;
exp-assign-operator :="^=" ;

Examples

counter:=0counter+=5--

Add 5 to counter (addition assignment)

counter-=3--

Subtract 3 from counter (subtraction assignment)

counter*=2--

Multiply counter by 2 (multiplication assignment)

counter/=4--

Divide counter by 4 (division assignment)

counter^=2--

Exponentiate counter by 2 (exponentiation assignment)

Enum Define

enum-variant :=?grave, identifier, ?enum-variant-kind ;
enum-variant-kind :="(", kind-annotation, ")" ;

Examples

    status < Active | Inactive | Pending  -- Enum definition with variants
    priority < High | Medium | Low        -- Enum definition for priority levels

Kind Define

kind-define :="<"
, ">"
;

Examples

    userKind < Person > :< string | int -- Kind definition with annotation

Mech Programs

Mechdown

Mechdown is a markup language for writing Mech programs. It is designed to maintain vague compatibility with Markdown, it is not a superset of Markdown. Rather, Mechdown is a distinct markup language with its own syntax and semantics. For instance, hashtag notation is not supported for titles, which is a departure from Markdown.

Moreover, Mechdown supports tables and other features that are not present in Markdown, but can be found in extension to Markdown like Github Flavored Markdown (GFM), and Mech-specific features like that ability to query Mech values and print them inline using {} syntax.

Mech programs and scripts can be written entirely without Mechdown, but literate programming with Mechdown is idomatic.

Document Structure

A Mechdown document consists of an optional title followed by a body containing sections. Each section can contain various elements such as paragraphs, subtitles, code blocks, lists, footnotes, citations, images, equations, tables, and thematic breaks.

Titles

title :=+text
, +"="
, *(space | tab)
, ws0
;
paragraph-element :=+(¬define-operator, text) ;
subtitle :=+digit-token
, "."
, +text
, +"-"
, *(space | tab)
, *(space | tab)
, ws0
;
number-subtitle :=*(space | tab)
, "("
, ")"
, +(space | tab)
, +text
, *(space | tab)
, ws0
;
alpha-subtitle :=*(space | tab)
, "("
, ")"
, +(space | tab)
, +text
, *(space | tab)
, ws0
;

There are 6 levels of titles: the document title, section titles, and two levels of sub section titles.

Example:

Title
========

1. Section Title
----------------

(1.1) Sub Section Title

(1.1.1) Sub Sub Section Title

Section titles and the first level of sub-section titles comprise the table of contents, which is generated automatically.

Paragraphs

At their base, paragraphs are blocks or raw text that start with a valid paragraph starter and end with a newline character.

Paragraph Elements

strikethrough :=tilde, +paragraph-element, tilde ;
highlight :="!!", +paragraph-element, "!!" ;
inline-code :=grave, +text, grave ;
inline-equation :=equation-sigil, +text, equation-sigil ;
hyperlink :="["
, +text
, "]"
, "("
, +text
, ")"
;
raw-hyperlink :=http-prefix, +text ;
eval-inline-mech-cdoe :="{", expression, "}" ;
inline-mech-cdoe :="{{", expression, "}}" ;

Beyond raw text, paragraphs also can contain various markup which indicates inline elements. Mechdown supports the following inline markup:

- Text Markup
  - **Bold Text**
  - *Italic Text*
  - __Underline Text__
  - ~~Strikethough Text~~
  - !!Highlighted Text!!
- Inline Elements
  - `Inline code blocks`
  - {{inline-mech := syntax + "highlighting"}}
  - $$\pm\sqrt{inline^2 + equation^2}$$
- Link Elements
  - [Hyperlinks](#)
  - Autonumbered inline references [MECH]
  - Autonumbered footnote references[^1]
  - Section references §10.3

This renders as

  • Text Markup

    • Bold Text

    • Italic Text

    • Underline Text

    • Strikethough Text

    • Highlighted Text

  • Inline Elements

    • Inline code blocks

    • inline-mech:=syntax+"highlighting"

  • Link Elements

    • Hyperlinks

    • Autonumbered inline references [1]

    • Autonumbered footnote references1

    • Section references §10.3

References

footnote :="[^"
, +text
, "]"
, ":"
, ws0
;
footnote-reference :="[^", +text, "]" ;
citation-reference :="[", +alphanumeric, "]" ;
citation :="["
, "]"
, ":"
, ws0
, ws0
, ?("(", +text, ")")
;
section-reference :="§", +(alphanumeric | period) ;

Mechdown supports various references including footnotes, citations, and section references.

Footnotes are used to indicate additional information or references at the bottom of the document. They are referenced inline using a [^label] syntax. Footnotes are defined as section elements, and are rendered where they are defined. They are indicated with a [^label]: syntax, followed by the footnote text.

Citations are used to reference external sources or documents. They are indicated inline using a [label] syntax. Citations are defined as section elements, and are rendered at the bottom of the document, in an auto-generated "Works Cited" section. They are indicated with a [label]: syntax, followed by the citation text and optional additional information in parentheses. The label used in reference must match the label used in the citation definition.

Section references are inline references to section titles, and are indicated with a § followed by the section number, or a unique section label.

Examples
This is a paragraph with a footnote reference.[^1] Here is a citation reference.[MECH] Finally, we have a section reference to §10.4.

[^1]: This is the text of the footnote.
[MECH]: Mech Programming Language. (2024). Retrieved from https://mech-lang.org (Mech Official Website)

This renders as:

This is a paragraph with a footnote reference.1 Here is a citation reference.[2] Finally, we have a section reference to §10.4.

1:

This is the text of the footnote.

Although the referenec is defined here in the document, it will be rendered at the bottom of the document in the "Works Cited" section. This is in contrast to footnotes, which are rendered where they are defined.

Lists

unordered-list :=+list-item, ?new-line, ws0 ;
ordered-list :=+ordered-list-item, ?new-line, ws0 ;
ordered-list-item :=integer-literal
, "."
;
list-item :=dash ;

There are two varities of lists, unordered, which are delinated with a - or a graphicl and ordered list, which are delinated with a numeral like 1., and are numbered in order automatically when formatted.

Example:

- Item 1
- Item 2
- Item 3

1. Item 1
2. Item 2
3. Item 3

When rendered, they look like this:

  • Item 1

  • Item 2

  • Item 3

List items are paragraphs, and can contain any inline elements.

Example:

- **First**: item 1
- **Second**: item 2
- **Third**: item 3

Here's a list of some of the features of lists:

  1. Bullet lists

    • One

    • Two

    • Three

  2. Custom lists

    • Four

    • Five

    • Six

  3. Numbered lists

    1. One

    2. Two

    3. Three

  4. Custom start number

    1. One

    2. Two

    3. Three

  5. Check lists

    • One

    • Two

    • Three

Thematic Breaks

thematic-break :=asterisks, asterisks, +asterisks ;

Thematic breaks are horizontal lines that can be used to separate sections of a document. They are created using three or more asterisks.

Example:

***
***********

When rendered, they look like this:


Code Blocks

grave-codeblock-sigil :=grave, grave, grave ;
tilde-codeblock-sigil :=tilde, tilde, tilde ;
code-identifier :=+((¬"{", text)) ;
code-content :=*(¬codeblock-sigil, any) ;

Mechdown supports code blocks, which are enclosed in triple backticks (graves) and can contain any text. Code blocks are useful for including Mech code snippets or other text that should be displayed verbatim.

Blocks are deliniated by a code fence, whether triple graves or triple tildes. Optionally, a code identifier can be provided after the opening code fence to indicate the programming language of the code block. This enables syntax highlighting when rendered.

When "mech" is specified as the code identifier, the code block is treated as Mech code and syntax highlighting is applied accordingly. See §10.10 for more details specific to Mech code blocks.

When "ebnf" is specified as the code identifier, the code block is treated as EBNF syntax and syntax highlighting is applied accordingly.

Start and end code fences must be of the same type (either graves or tildes). To embed a code fence in another code fence, use the alternate type for the inner fence.

Examples

```
This is a code block deliniated with graves.
```
~~~
This is a code block deliniated with tildes.
~~~

This one has a label:

```ebnf
X := A | B, C ;
```

The label can also have an options map:

```ebnf{width: "25px}
X := A | B, C ;
```

Equations

equation :=(dollar, dollar), +text, new-line ;

Equations are orefixed with $$ and can contain any text. They are used to display mathematical expressions or formulas expressed in LaTeX syntax.

For instance,

$$ c = \pm\sqrt{a^2 + b^2}

when rendered will look like this:

Mechdown also supports inline equations, which begin and conclude with a $$. They are expressed with LaTeX syntax, like so: $$c^2 = a^2 + b^2$$. This is rendered by a third-party library into .

Callout Blocks

block-quote :=">", ws0, +paragraph ;
block-important :="(!)>", ws0, +paragraph ;
block-question :="(?)>", ws0, +paragraph ;

Callouts are used to emphasize a paragraphs, and classifies them into one of three semantic categories:

  • Quotes: for quotations, indicated with a >.

  • Important: for information critical to the reader, indicated with a (!)>

  • Question: for anticipated and frequently asked questions, indicated with a (?)>

Multiple paragraphs can be included in the callout block as long as there are no newline characters between them (although a newline is of course required to end a paragraph).

Example:

> This is a quote block.

(!)> This is an important block.

(?)> This is a question block.

(?)> This is a question block with multiple paragraphs.
This is the second paragraph.

When rendered, they look like this:

This is a quote block.

This is an important block.

This is a question block.

This is a question block with multiple paragraphs.

This is the second paragraph.

Tables

column-header :=bar, paragraph ;
no-alignment :=+dash ;
left-alignment :=colon, +dash ;
right-alignment :=+dash, colon ;
center-alignment :=colon, +dash, colon ;
markdown-table-row :=whitespace0
, bar
;
column-cell :=bar, paragraph ;

Markdown tables consist of a header, and a body. The header is defined using a pipe | to separate columns, and a row of dashes - to indicate the alignment of each column. The body of the table contains rows of data, also separated by pipes.

Table Heading::

The header of a table is defined using a row of text followed by a row of dashes. The dashes indicate the alignment of each column.

Column Alignment:

Columns can be aligned in one of three ways:

  • Left-aligned: :-- or --

  • Right-aligned: --:

  • Center-aligned: :--:

Any number of dashes can be used to indicate the width of the column, and they can be of different lengths.

Table Body:

The body of a table is defined using rows of text separated by pipes. Each row can contain any number of columns, and the number of columns in each row must match the number of columns in the header.

Example

| Align Left  | Align Center | Align Right |
|:------------|:------------:|------------:|
| One         | Four         | {1 * 10}    |
| Two         | Five         | {2 * 20}    |
| Three       | Six          | {3 * 30}    |

Renders the following table:

Align Left

Align Center

Align Right

:------------

:------------:

0-----------:

One

Four

1*10

Two

Five

2*20

Three

Six

3*30

Images

img :="!["
, "]"
, "("
, +text
, ")"
;
option-map :="{"
, ws0
, ws0
, "}"
;
option-mapping :=ws0
, ws0
, ":"
, ws0
, ws0
;

Images are added to Mechdown documents using the ![alt-text](image-url) syntax. An optional options map can be provided within curly braces {} to specify additional attributes for the image, such as width, height, or alignment.

The alt-text is a rich paragraph that can contain any paragraph elements. It is configured to display below the image as a caption by default. The caption is accompanied by a figure number, which is automatically assigned based on the section of the document in which the image appears.

Images can be floated to the left or right by prefixing with << or >>, respectively. This allows text to wrap around the image and caption.

Example

![The Mech "M"](https://github.com/mech-lang/assets/blob/main/images/mech-m2.png?raw=true)
![A smaller Mech "M"](https://github.com/mech-lang/assets/blob/main/images/mech-m2.png?raw=true){width: "100px", height: "100px"}

This renders as:

Fig 10.1

The Mech "M"

Fig 10.2

A smaller Mech "M"

Mech Extensions

eval-inline-mech-cdoe :="{"
, ws0
, ws0
, "}"
;
inline-mech-cdoe :="{{"
, ws0
, ws0
, "}}"
;
mech-code :=mech-code-alt, ("\n" | ";" | comment) ;

Mechdown extends the base markup language to include Mech code block support. These blocks integrate directly with the Mech runtime and are parsed, executed, and rendered as live, reactive code segments.

Mech Code Blocks

Mech code ban be written directly into any Mechdown document, or within a fence. Each has different semantics.

Subsequent lines of unadorned Mech code are treated as part of the same Mech program, and are executed in sequence. The scope of these blocks is global, so any variable defined in a code block can be referenced from other blocks, or also inline code elements. However, no output is rendered for unadorned Mech code.

Fenced Mech code much be indicated with a triple fence (either ` or ~), followed by the language specifier mech. Code within these fences is executed in the same global scope as unadorned Mech code, but any output from the final expression in the block is rendered below the code fence. This allows for live code examples that show both the code and its output.

Mech code blocks can be configured by adding a : at the end followed by a string or an option map. This configuration can specify options such as whether to show output, hide code, or other rendering preferences. Current options include:

  • mech:interpreter-id - Scope block code to a specific interpreter instance. This is useful for separating examples and tests that should not change the global program state.

  • mech:hidden - This will hide the code block from being rendered by Mechdown. Code in this block will still execute in the global scope.

  • mech:disabled - This will disable execution of the code block. The code will be rendered as-is, but not executed.

Furthermore, an options map can be provided within curly braces {} to specify multiple options in a structured way, where the keys are identifiers and the values are strings. By default, these otions are applied to the style of the code block.

Examples

Example 1: Unadorned Mech Code

my-var := 123     -- This code isn't in a code fence, so there is no output attached.
my-var2 := my-var + 1

This renders as:

my-var:=123--

This code isn't in a code fence, so there is no output attached.

my-var2:=my-var+1

Example 2: Fenced Mech Code

```mech
result := my-var2 * 2   -- This code is in a code fence, so the output will be rendered below.
```

This renders as:

result:=my-var2*2--

This code is in a code fence, so the output will be rendered below.

Example 3: Fenced Mech Code targeting a sub interpreter

```mech:ex1
value := 10 * 5
```
```mech:ex1
result := value + 20
```

This renders as:

value:=10*5
result:=value+20

Inline Mech Code

Mechdown supports inline Mech code, which can be used to embed Mech expressions directly within paragraphs. Inline Mech code comes in two variants:

  • {{expression}}: This syntax is used for inline Mech code that should be syntax highlighted but not evaluated. It is useful for documentation purposes where you want to show Mech code without executing it.

  • {expression}: This syntax is used for inline Mech code that should be evaluated and its result displayed within the paragraph. It allows for dynamic content generation based on Mech expressions. If an interpreter is not available, the code will be displayed as-if it were a syntax-highlighted block.

Examples
The result of 6 times 7 is {6 * 7}.
The syntax for defining a variable in Mech is {{var-name := value}}.

This renders as:

The result of 6 times 7 is 6*7.

The syntax for defining a variable in Mech is var-name:=value.

Notation

The grammar is specified using extended Extended Backus-Naur Form (EBNF):

Symbol

Meaning

Semantics

p

rule

p is a rule in the grammar

p := q;

definition

p is defined as q

"abc"

terminal

string literal "abc"

p, q

sequence

p followed by q

p | q

choice

p or q

[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

increase precedence

The grammar grammar:

grammar :=+rule ;
identifier :=alpha-token, *(alpha-token | digit-token | dash) ;
rule :=identifier
, ":="
, ";"
;
expression :=term, *("|", term) ;
term :=factor, *(",", factor) ;
definition :=identifier ;
repeat0 :="*", factor ;
repeat1 :="+", factor ;
optional :="?", factor ;
peek :=">", factor ;
not :="¬", factor ;
list :="["
, "]"
;
group :="(", expression, ")" ;
terminal :=quote, +any-token, quote ;

Works Cited

[2]:

Mech Programming Language. (2024). Retrieved from https://mech-lang.org (Mech Official Website)