This document specifies the default syntax and semantics of the Mech programming platform, 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.
Anyone who want to understand the syntax and structure of Mech programs.
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 presents programs as structured documents where explanations take precedence over code. Mech supports this concept through a format called Mechdown, a Markdown varient 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 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 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 valid identifiers.
Category | Operators |
---|---|
Assign | |
Arithmetic | |
Split / Merge | |
Matrix | |
Logic | |
Set | |
Range | |
Condition | |
Transition | |
Guard | |
Examples:
. ! ? , : ; " '
Examples:
& $ | % @ / # = \ ~ + - * ^ _
Examples:
( ) < > { } [ ]
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. However,
Because Mech has a focus on literate programming, comment 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 the code that cannot be broken out into a paragraph. For example, to make a note within a state machine definition.
Examples:
Here are some ways to write a comment in Mech:
-- Single line comment. // Also a single line comment. x := 1 -- Comment after an expression
When parsed and rendered, these become:
Comment prefix with --
--Comment prefixed with //
x:=1--Comment after an expression
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 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 will be reported as syntax errors.
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.
Integers - 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
Fractional - Decimal numbers with fractional components.
f32
- 32-bit floating-point number
f64
- 64-bit floating-point number
Imaginary - Represent imaginary components of complex numbers.
String - A sequence of UTF-8 characters representing text.
string
- A sequence of characters enclosed in double quotes.
Boolean - 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.
Kind - A meta-type that categorizes types
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.
, which indicates a String data type; or <[u64]:3,1>
, which indicates a 3x1 matrix of 32-bit unsigned integeres.
Examples:
<_> -- Empty <`A> -- Atom <{A:B}> -- Map <(A,B)=(C,D)> -- Function <{A}> -- Set <[A]> -- Matrix <(A,B,C)> -- Tuple
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--decimal
42--decimal
0x1234567890ABCDEF--hexadecimal
0x1234567890abcdef0o12345670--octal
0b100110101--binary
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
. This is different from many systems languages but consist with other languages like Python, JavaScript, and Ruby.
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.
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.
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.
Examples:
"Hello, World!""characters like " and \ are escaped with, \ e.g. \"""This string contains emojis: 🤖, 🐦, and 🐍"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.
Examples:
truefalse✓✗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.
Examples:
`A`MyAtom`🐦`Δx^2Empty 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.
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 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.
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.
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.
Empty Matrix
[]--1x1 Matrix
[3x3 Matrix
[3x2 Matrix
[1x3 Row Vector
[3x1 Column Vector
[4x1 Column Vector
[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.
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 | |
Col Vector | |
Row Vector | |
2D Matrix | |
3D Matrix | |
Dynamic cols | |
Dynamic rows | |
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.
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.
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.
Description | Example |
---|---|
Empty | |
Singleton | |
Basic | |
Strings | |
Nested | |
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.
<{u8}:3>
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.
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.
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.
A map of strings to u8s: <{string:u8}>
A map of strings to a map of strings to u8: <{string:{string:u8}}>
A Tuple is defined using parentheses ()
and contains an ordered collection of elements, which can be of different types.
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.
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.
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.
-- Two-tuple of u8 and string <(u8,string)> -- Three-tuple of u8s <(u8,u8,u8)>
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.
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 _
).
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.
{ xy | 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.
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]: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:
╭──────────────────────────────╮ │ xy z<[u8]:3> │ ├───────┬──────────┬───────────┤ │ _ │ "a" │ [1;2;3] │ ├───────┼──────────┼───────────┤ │ 4 │ "b" │ _ │ ├───────┼──────────┼───────────┤ │ 7 │ _ │ [7;8;9] │ ╰───────┴──────────┴───────────╯
A table's kind includes the column types and table dimensions. For example, the pretty print table's kind is: <{u8, string, [u8]:3}:3,3>
.
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).
The kind of a table row is equivalent to a record with the same column kinds.
<{u8, string, [u8]:3}>
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]:3,1>
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 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.
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.
Examples 1: Implicitly Typed Records
{x:1, y:"a", z:[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:[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:[This record contains:
a: A nested record {b: 1, c: "hi"}
.
b: A columm matrix [1;2;3]
.
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)
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.
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.
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.
Left-to-right associativity applies to all operators, including exponentiation.
Parentheses explicitly override precedence rules.
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 subscript with identifier
dot_result_2:=object.42--Dot subscript with integer literal
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
Examples
intVar := 10 -- Variable definition with initialization optionalVar := ~stringVar -- Variable definition with optional tilde varWithExpression := ~calculatedValue * 5 -- Variable definition with expression
Examples
numbers:=[Assign value 10 to index 2 of the array
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 definition with variants
priority<High|Medium|Low--Enum definition for priority levels
userKind < Person > :< string | int -- Kind definition with annotation
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
Examples
--Call function with simple arguments
sumResult = addNumbers(5, 10) --Call addNumbers with two integer arguments
--Call function with binding (using colon syntax to bind a specific argument)
rectangleDetails = createRectangle(10, 20) --Call with two integers
area = rectangleDetails.area --Accessing the area
perimeter = rectangleDetails.perimeter --Accessing the perimeter
--Call function with complex arguments and output
stats = calculateStats(10, 20, 30) --Call calculateStats
average = stats.average --Extract average
maxValue = stats.max --Extract max value
--Call function with optional argument
greetUser("Alice")--Function call with a single string argument
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") .
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.
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 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}
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:
Bullet lists
One
Two
Three
Custom lists
Four
Five
Six
Numbered lists
One
Two
Three
Custom start number
One
Two
Three
Check lists
One
Two
Three
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:
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.
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 .
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.
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 |
The grammar is specified using extended Extended Backus-Naur Form (EBNF):
Symbol | Meaning | Semantics |
---|---|---|
| terminal | string literal "abc" |
| sequence | |
| choice | |
| list | list of |
| repeat 0 | |
| repeat 1 | |
| optional | |
| peek | |
| not | does not match |
| group | incrase precedence |
The grammar grammar: