Mech Language Specification

Introduction

Source Code Representation

File Format

Literate Programming and Mechdown

Whitespace

Lexical Elements

Tokens

Identifiers

Keywords

Operators and Punctuation

Comments

Literals

Integers

Floats

Strings

Boolean

Atoms

Empty

Kinds

Data Structures

Matrix

Semantics

Indexing

Set

Map

Tuple

Table

Record

Expressions

Formula

Arithmetic

Matrix

Comparison

Logical

Set

Range

Indexing

Slicing

Dot Index

Swizzle

Statements

Variable Define

Variable Assign

Op-Assign

Enum Define

Kind Define

Functions

Function Define

Function Call

State Machines

Operators

Specification

Implementation

Mech Programs

Mechdown

Body

Sections and Section Elements

Titles

Paragraphs and Paragraph Elements

Lists

Thematic Breaks

Code Blocks

Block Quotes

Tables

Mech Extensions

Notation

Mech Language Specification

Introduction

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.

Source Code Representation

File Format

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 and Mechdown

Literate programming 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

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 .

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

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

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-Word
io/stdout
Δx^2
🤖
A*

Keywords

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.

Operators and Punctuation

Punctutation:

. ! ? , : ; ' "

Symbols:

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

Grouping Symbols:

( ) < > { } [ ]

Operators:

Category

Operators

Assign

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

Arithmetic

+ - * / ^ %

Split / Merge

>- -<

Matrix

** · ⨯ \ '

Logic

| & xor ⊕ ⊻ ! ¬

Set

∪ ∩ ∖ ∁ ⊆ ⊇ ⊊ ⊋ ∈ ∉

Range

.. ..=

Condition

!= ¬= ≠ == > < >= ≤ ≥

Transition

=> -> ~>

Guard

| │ ├ └

Comments

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

Examples:

-- Single line comment.
-- Also a single line comment.

Literals

Integers

number := real-number , ? "i" | ? ( "+" , real-number , "i" ) ;
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).

Examples:

42
0x1234567890ABCDEF
0x1234567890abcdef
0o12345670
0b100110101

Floats

scientific-literal := ( float-literal | integer-literal )
, ( "e" | "E" )
, ? plus
, ? dash
;
float-literal := ? "."
, ? "."
;

Examples:

1234
3.14
0.001
2.5e+10.
1/3
1 / 3

Strings

string := quote , * ( ¬ quote , text ) , quote ;

Examples:

"Hello, World!"
"characters like " and \ are escaped with, \ e.g. \""

Boolean

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

Examples:

true
false

Atoms

atom := "`" , identifier ;

Examples:

` A
` MyAtom
` MyAtom123
` 🐦

Empty

empty := + underscore ;

Examples:

_

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 ;

Examples:

<_>
<`A>
<{A:B}>
<(A,B)=(C,D)>
<{A,B,C}>
<[A,B,C]>
<(A,B,C)>

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.

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 and examples.

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
]

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.

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>

4D Matrix

<[u8]:2,3,4>

Dynamic cols

<[u8]:2,_>

Dynamic rws

<[u8]:_,3>

Set

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.

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.

Examples:

Description

Example

Empty

{} or {_}

Singleton

{1}

Basic

{1,2,3}

Strings

{"apple", "banana", "cherry"}

Nested

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

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.

Kind:

<{u8}:3>

Map

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.

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.

- Empty:             {_:_}
- Single element:    {"a":1}
- Multiple elements: {"a":10, "b":20, "c": 30}
- Nested:            {"a":{"a":10}}
- Multiline:
    { "a" : 10 
      "b" : 20
      "c" : 30 }

Edge Cases

  • {_:_} represents an empty map.

  • Duplicate keys result in an overwrite of the previous value, as long as the map is mutable.

  • {1: "hello", 2: "world"} is valid, but {1: "hello", "one": "world"} results in a type error if homogeneity is enforced.

Kind:

  • A map of strings to u8s: <{string:u8}>

  • A map of strings to a map of strings to u8: <{string:{string:u8}}>

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.

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.

Examples:

( )
( 1 )
( 1 , 1 , 3 )
( 1 , ( 2 , 3 ) )
( 1 , true , "Hello" )
( [
1 3
2 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.

Kind

-- Two-tuple of u8 and string    <(u8,string)>
-- Three-tuple of u8s            <(u8,u8,u8)>

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.

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

Defining Tables:

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 | denotes the end of the header, and each row is separated by a semicolon ; .

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.

Sparse 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 ]: 3 >
_ "a" [
1 2 3
]
4 "b" _
7 _ [
7 8 9
]

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]:3> │
├───────┬──────────┬───────────┤
│   _   │   "a"    │  [1;2;3]  │
├───────┼──────────┼───────────┤
│   4   │   "b"    │     _     │
├───────┼──────────┼───────────┤
│   7   │    _     │  [7;8;9]  │
╰───────┴──────────┴───────────╯

Kind:

A table's kind includes the column types and table dimensions. For example, the pretty print table's kind is:

This denotes:

  • Columns: { u8, string, [u8]:3 } (a mix of an -integer, a string, and a fixed-size array).

  • Shape: 3,3 (3 rows, 3 columns).

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.

A table row is equivalent to a record.

<{u8, string, [u8]:3}:3,3>

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.

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.

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

Kind Representation:

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

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

This denotes a record with:

  • x: u8

  • y: string

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

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

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

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:

  • Parentheses - Explicit grouping of expressions.

  • Negation and Logical NOT - Unary operations.

  • Exponentiation - Raising to a power.

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

  • Addition and Subtraction - Binary arithmetic operations.

  • Comparison Operators - Elementwise comparisons.

  • Logical Operators - and, or, xor.

  • 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_result_2 := object . 42

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

Op-Assign

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

Examples

counter := 0
counter += 5
counter -= 3
counter *= 2
counter /= 4
counter ^= 2

Enum Define

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

Examples

status < Active | Inactive | Pending
priority < High | Medium | Low

Kind Define

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

Examples

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

Functions

Function Define

function-out-args := "(" , [ function-arg , list-separator ] , ")" ;
function-out-arg := function-arg ;
argument-list := "(" , ? [ ( call-arg-with-biding | call-arg ) , "," ] , ")" ;

Examples

    -- Simple function definition with no return value
    addNumbers(x: int, y: int) = (result: int) := 
        result = x + y
        .  -- Return result (implicitly)

    -- Function with multiple output arguments
    createRectangle(length: int, width: int) = (area: int, perimeter: int) := 
        area = length * width
        perimeter = 2 * (length + width)
        .  -- Return both area and perimeter

    -- Function with an optional argument (no output)
    greetUser(name: string) = := 
        print("Hello, " + name)
        .  -- No output, just side-effect

    -- Function with complex arguments and output
    calculateStats(x: int, y: int, z: int) = (average: float, max: int) := 
        average = (x + y + z) / 3.0
        max = max(x, max(y, z))  -- Function calls inside function body
        .  -- Return both average and max

Function Call

function-call := identifier , argument-list ;
call-arg-with-binding := identifier , colon , expression ;
call-arg := expression ;

Examples

-- Call function with simple arguments
sumResult = addNumbers ( 5 , 10 )
-- Call function with binding (using colon syntax to bind a specific argument)
rectangleDetails = createRectangle ( 10 , 20 )
area = rectangleDetails . area
perimeter = rectangleDetails . perimeter
-- Call function with complex arguments and output
stats = calculateStats ( 10 , 20 , 30 )
average = stats . average
maxValue = stats . max
-- Call function with optional argument
greetUser ( "Alice" )

State Machines

Operators

output-operator := "=>" ;
transition-operator := "->" ;
async-transition-operator := "~>" ;
guard-operator := "|"
| "│"
| "├"
| "└"
;

Specification

fsm-specification := "#"
, "("
, ? [ var , "," ]
, ")"
, "."
;
fsm-tuple-struct := grave
, "("
, [ fsm-pattern , "," ]
, ")"
;
fsm-state-definition-variables := "(" , ? [ var , list-separator ] , ")" ;
fsm-instance := "#" , identifier , ? fsm-args ;
fsm-args := "(" , ? [ ( call-arg-with-binding | call-arg ) , list-separator ] , ")" ;

Implementation

Examples

    -- Simple FSM Declaration
    fsm SimpleFSM
        (var1, var2)         -- Variables for FSM
        =>                   -- Output operator
        ;                    -- End of the state machine definition

    -- FSM with states and transitions
    fsm StateMachine1
        (state1, state2)
        => "StateMachineOutput"   -- Output operator for the FSM
        kind "simple"
        define
        #state1
            -> state2    -- Transition operator
            | guard1     -- Guard operator for conditional transitions
        .

    fsm-instance MyFSM
        (stateA, stateB)
        -> stateB         -- Simple state transition
        ~> stateA         -- Asynchronous transition operator


    -- FSM with variables and multiple states
    fsm ComplexFSM
        (state1, state2, state3)
        => "Processing"
        define
        #state1
            -> state2    -- Transition from state1 to state2
        | state2
            -> state3    -- Transition from state2 to state3
            ~> state1    -- Asynchronous transition back to state1
        .

    fsm-instance ComplexFSMInstance
        (stateX, stateY, stateZ)
        -> stateX       -- Transition to stateX
        ~> stateY       -- Async transition to stateY
        => outputX      -- FSM Output
        .


    -- FSM with guards and output operators
    fsm-implementation MyFSMImpl
        #FSMTransition1
        (state1, state2)
        -> state3         -- Transition from state1 to state3
        => stateOutput    -- Output from this FSM transition
        .

    fsm-guard-arm MyFSMGuard
        #FSMGuardState
        (stateGuard)
        | guard-condition  -- Guard operator for conditional checking
        .

    fsm-guard MyFSMGuardExample
        | FSMGuardPattern
        -> FSMGuardTransition
        ~> FSMAsyncGuard
        .

    fsm-block-transition MyFSMBlockTransition
        -> {
            // Complex code block executed during state transition
            set stateA = true
            set stateB = false
        }
        .


    -- FSM pattern with tuple struct
    fsm-pattern MyFSMPattern
        grave TupleState
        (varA, varB)
        .


    -- FSM instance with arguments
    fsm-instance ComplexArgsFSM
        (stateStart, stateEnd)
        (inputData1, inputData2) -- Call arguments with bindings
        -> stateStart
        .


    -- FSM State definition with guard and pattern matching
    fsm-state-definition MyStateDefinition
        | stateGuard
        grave stateDefinition
        (variableX, variableY)
        .


    -- FSM with wildcards and formulas in patterns
    fsm-pattern MyWildcardPattern
        *
        .

    fsm-pattern MyFormulaPattern
        formula("x + y = 10")
        .

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.

Body

program := ? title , body ;
body := + section ;

Sections and Section Elements

Titles

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

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

Example:

Title
========

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

(2) Sub Section Title

(a) Sub Sub Section Title

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

Paragraphs and Paragraph Elements

Paragraphs are a block element that can contain a number of inline elements including:

  • Strong text: **text**

  • Emphasis text: *text*

  • Strikethrough text: ~text~

  • Underlined text: _text_

  • Inline code: code

  • Hyperlinks: [text](url) also raw links http://example.com

  • Inline Mech: {expression}

Lists

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

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

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.

Block Quotes

block-quote := ">" , * whitespace , + paragraph ;

Block quotes are used to indicate quoted text. They are created using the > character followed by a space, and can contain any text until a newline.

Example:

> This is a block quote.

When rendered, they look like this:

This is a block quote.

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 ;
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:

| Left  | Center | Right |
|:------|-------:|:-----:|
| One   | Four   | 10    |
| Two   | Five   | 100   |
| Three | Six    | 1000  |

Renders the following table:

Left

Center

Right

One

Four

10

Two

Five

100

Three

Six

1000

Mech Extensions

Notation

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:

grammar := + rule ;
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 ;