For the complete Mojo documentation index, see llms.txt. Markdown versions of all pages are available by appending .md to any URL (e.g. /docs/manual/basics.md).
Mojo lexical structure reference
Mojo divides source text into tokens: identifiers, keywords, literals, operators, and delimiters.
This page explores how tokens form lines and blocks, how statements continue across lines, and how comments and punctuation work.
Source text
Mojo reads source files as Unicode Standard UTF-8 encoded text.
Comments and string literals can contain Unicode grapheme clusters. Identifiers use ASCII letters, digits, and underscores only (see Identifiers).
# Größe und Maß: any text works in a comment
print("größe") # and in a string literal
Mojo doesn't accept a UTF-8 byte-order mark (BOM) at the start of a file. Save source files as UTF-8 without a BOM.
Lines
A line ends at a line feed (\n), a carriage return (\r), or a
carriage return followed by a line feed (\r\n). A form feed or vertical
tab also ends a line.
Mojo ignores blank lines and lines with only a comment, whatever the indentation:
if ready:
start()
# A comment at any indentation won't affect the block.
log("started")
Indentation
Indentation groups statements into blocks. A
compound statement header ends with
:, and its body is indented deeper than the header. The body ends at the
first line indented to the header's level or less.
Mojo measures indentation by counting the spaces and tabs at the start of a line. A tab counts as one column, the same as a space. Use spaces or tabs, not both.
Each line's leading whitespace must match the previous line's, character for character, over their shared length.
def main():
var width = 3
var height = 4 # Error: tab-indented after space-indented
var depth = 2 # Error: 2-spaces used after 4-spaces
Line continuation
A statement can continue onto another line in four ways.
Inside parentheses, indentation doesn't matter. A parenthesized expression can span as many lines as it needs:
var total = area(
width=5,
height=6,
)
var size = (
"small"
if total < 100
else "large"
)
A backslash at the end of a line joins the next line to it. Only spaces or tabs can follow the backslash on its line:
var total = width * height + \
margin
A backslash anywhere else is part of a string literal or an error.
A line indented deeper than the statement's first line continues that statement, with or without parentheses:
var total = width * height
+ margin # Continues the assignment
A line that ends with an operator continues onto the next line, because the operator still needs its right operand:
var total = width * height +
margin
if width <
height:
print("width is less than height")
else:
print("width is not less than height")
Prefer parentheses for long expressions. They make continuation explicit and let you control indentation.
Comments
A comment starts with # and runs to the end of the line:
# Comments can stand on their own line.
var retries = 3 # Or follow code.
Mojo doesn't have block comment syntax. Prefix each line of a multiline
comment with #. Many IDE/editors have support built-in.
A # inside a string literal is part of the string, not the start of a
comment:
print("Order #1042") # Prints: Order #1042
Mojo discards comments before parsing, so a comment can hold any
text. A #! line at the top of a file is a comment too, so a shebang
line works, just not in the way you might expect. It's just a text comment:
#!/usr/bin/env mojo
Docstrings
A docstring is a string literal at the start of a module, function, struct, or trait body. Unlike a comment, a docstring is part of the program: the compiler keeps it, and documentation tools read it. See the docstring reference for the format.
Semicolons
A semicolon groups simple statements on the same line. You don't need one at the end of a statement:
var width = 3; var height = 4
Think of semicolons as glue, not terminators.
A trailing semicolon is allowed. Two semicolons in a row (;;) are an
error.
A compound statement can put its body on the header line, after the :.
Semicolons separate the statements in that body:
if width < height: print("narrow"); print("tall")
for step in range(2): print(step)
Commas
A comma separates the items in a syntax list: arguments, parameters, conformances, collection elements, captures, import names, and tuple items. A trailing comma after the last item is allowed in every list:
from std.collections import (
Dict,
Set,
)
def area(width: Int, height: Int,) -> Int:
return width * height
var ports = [80, 443,]
var total = area(
width=5,
height=6,
)
In multiline lists, put each item on its own line with a trailing comma. Adding an item then changes only one line in a diff.
A one-element tuple needs a trailing comma. Without it, the parentheses only group the value:
var single = (8080,) # Tuple with one element
var grouped = (8080) # The number 8080 in parentheses
An empty item is an error, so print(1,,2) and (,) don't compile.
Write an empty tuple as ().
Delimiters
Delimiters group, separate, and mark parts of a statement. Several characters also serve as operators; see the operator reference for those uses.
| Delimiter | Use | Reference |
|---|---|---|
( ) | Grouping, calls, argument lists, tuples | Expressions |
[ ] | Parameter lists, subscripts, array and list literals | Collections, subscripts |
{ } | Set and dict literals, initializer lists, capture lists | Collections, closures |
, | Separates items in a list | Commas |
; | Separates simple statements | Semicolons |
: | Ends a header; type annotations, dict entries, slices | Compound statements |
. | Member access, implicit member references | Expressions |
-> | Return type | Function declarations |
@ | Decorator | Decorators |
= | Assignment, default values, keyword arguments | Simple statements |
:= | Walrus assignment | Expressions |
/ * // | Positional-only, keyword-only, and infer-only markers in a signature | Function declarations |
^ | Transfer, after a name | Ownership |
_ | Discard pattern | Literals |
... | Ellipsis | Literals |
` | Escaped identifier | Identifiers |
# | Comment | Comments |
Mojo doesn't use ! on its own, ?, or $. Outside a string literal or
comment, each is an error.
Token separation
Whitespace separates tokens that would otherwise run together. Two words need
whitespace between them, as in def main or var count. Whitespace is optional
around operators and delimiters:
print(3+4) # 7
print(3 + 4) # 7
my_function(a=1, b = 2) # a custom call