21. Grammar
Repetition is {...}, optional syntax is [...], quoted text is a token. A contextual word (§3.6) is quoted where it is one and is an IDENT everywhere else. NEWLINE, INDENT, and DEDENT come from the layout lexer; RAW_LINE is a physical line captured without tokenisation after removal of the suite's indentation baseline. IDENT is an identifier that is not a reserved word; TYPE_IDENT is a PascalCase identifier; TYPE_PATH is a TYPE_IDENT, or an alias's IDENT, optionally qualified by a module path; CORE_TYPE is one of the scalar type names, str, fmt, unit, never; COMPARE_OP is ==, !=, <, <=, >, >=; FORMAT_START, FORMAT_TEXT, FORMAT_END are the lexer's pieces of one f"..." literal, and FORMAT_SPEC the text after a field's colon up to its } (§5.5); constant_expression is an expression meeting §6.4. Semantic restrictions in the earlier chapters remain normative over this shape.
module = { import_decl | top_decl }, EOF ;
import_decl = "import", module_path, [ "as", IDENT ], NEWLINE
| "from", module_path, "import", IDENT, [ "as", IDENT ],
{ ",", IDENT, [ "as", IDENT ] }, NEWLINE ;
module_path = IDENT, { ".", IDENT } ;
top_decl = [ "pub" ], ( constant_decl | global_decl | type_alias
| function_decl | struct_decl | enum_decl
| union_decl | interface_decl | extern_decl
| handle_decl )
| "export", function_decl
| test_decl
| "assert", argument_list, NEWLINE
| asm_module_decl
| extension_decl ;
constant_decl = "let", IDENT, [ ":", type ], "=", constant_expression, NEWLINE ;
global_decl = [ "local" ], { attribute }, "var", IDENT, ":", type,
[ "=", constant_expression ], NEWLINE ;
type_alias = "type", TYPE_IDENT, "=", type, NEWLINE ;
attribute = "inline" | "noinline" | "cold" | "naked" | "weak" | "used" | "linked"
| "section", "(", STRING_LITERAL, ")" ;
function_decl = { attribute }, [ "static" ], "func", IDENT,
[ generic_params ], parameter_list, result_clause, ":", suite
| { attribute }, "linked", { attribute }, [ "static" ], "func", IDENT,
( parameter_list | receiver_list ), result_clause, NEWLINE ;
receiver_list = "(", "self", ":", [ "const" ], TYPE_IDENT, "*",
{ ",", parameter }, [ "," ], ")" ; (* a linked method, §9.8 *)
function_sig = "func", IDENT, [ generic_params ],
parameter_list, result_clause, NEWLINE ;
generic_params = "[", generic_param, { ",", generic_param }, [ "," ], "]" ;
generic_param = TYPE_IDENT, [ ":", interface_type, { "&", interface_type } ] ;
parameter_list = "(", [ parameter, { ",", parameter }, [ "," ] ], ")" ;
parameter = IDENT, ":", [ "noalias" ], type, [ "=", constant_expression ] ;
result_clause = [ "->", ( type | "!" ) ] ;
conformance = [ ":", interface_type, { ",", interface_type } ] ;
struct_decl = [ "packed" | "align", "(", constant_expression, ")" ],
"struct", TYPE_IDENT, [ generic_params ], conformance, ":",
NEWLINE, INDENT, type_member, { type_member }, DEDENT ;
type_member = [ "pub" ], ( field_decl | [ "export" ], function_decl ) ;
field_decl = [ "align", "(", constant_expression, ")" ], ( "let" | "var" ), IDENT, ":", type,
[ "=", constant_expression ], NEWLINE ;
extension_decl = "extend", TYPE_IDENT, ":", NEWLINE, INDENT,
[ "pub" ], [ "export" ], function_decl,
{ [ "pub" ], [ "export" ], function_decl }, DEDENT ;
enum_decl = "enum", TYPE_IDENT, [ generic_params ], [ "as", integer_type ],
conformance, ":", NEWLINE, INDENT,
enum_case, { enum_case }, { [ "pub" ], function_decl }, DEDENT ;
enum_case = IDENT, [ payload_list | "=", constant_expression ], NEWLINE ;
payload_list = "(", payload, { ",", payload }, [ "," ], ")" ;
payload = IDENT, ":", type ;
union_decl = "union", TYPE_IDENT, ":", NEWLINE, INDENT,
union_member, { union_member }, { [ "pub" ], function_decl }, DEDENT ;
union_member = [ "pub" ], IDENT, ":", type, NEWLINE ;
interface_decl = "interface", TYPE_IDENT, [ generic_params ], ":", NEWLINE,
INDENT, function_sig, { function_sig }, DEDENT ;
test_decl = "test", STRING_LITERAL, ":", suite ;
asm_module_decl = "asm", IDENT, ":", NEWLINE, INDENT, RAW_LINE, { RAW_LINE }, DEDENT ;
extern_decl = "extern", ( extern_type | extern_func | extern_var
| extern_struct | extern_union ) ;
extern_type = "type", TYPE_IDENT, [ "=", ( "u32" | "i32" | "u64" | "i64" ) ], NEWLINE ;
handle_decl = "handle", TYPE_IDENT, ":", NEWLINE, INDENT, "destroy", IDENT, NEWLINE, DEDENT ;
extern_func = [ "blocking" ], "func", IDENT, [ "as", STRING_LITERAL ],
"(", [ extern_parameter, { ",", extern_parameter } ], [ ",", "..." ], ")",
result_clause, NEWLINE ;
extern_parameter
= [ "out" ], IDENT, ":", type ;
extern_var = "var", IDENT, ":", type, NEWLINE ;
extern_struct = [ "packed" | "align", "(", constant_expression, ")" ], "struct", TYPE_IDENT, ":",
NEWLINE, INDENT, union_member, { union_member }, DEDENT ;
extern_union = "union", TYPE_IDENT, ":", NEWLINE, INDENT, union_member, { union_member }, DEDENT ;
suite = simple_stmt
| NEWLINE, INDENT, statement, { statement }, DEDENT ;
statement = simple_stmt | if_stmt | while_stmt | for_stmt | match_stmt
| labeled_loop | with_stmt | asm_stmt ;
simple_stmt = binding_stmt | assignment_stmt | drop_stmt
| "break", [ IDENT ], NEWLINE
| "continue", [ IDENT ], NEWLINE
| "return", [ expression ], NEWLINE
| ( "defer" | "errdefer" ), ( simple_stmt | ":", suite )
| "recover", expression, NEWLINE
| "free", "(", expression, ")", [ "in", expression ], NEWLINE
| expression, NEWLINE ;
binding_stmt = "let", binding_pattern, [ ":", type ], "=", expression, NEWLINE
| "var", binding_pattern, ":", type, [ "=", ( expression | "---" ) ], NEWLINE
| "var", binding_pattern, "=", expression, NEWLINE ;
binding_pattern = IDENT | "(", IDENT, ",", IDENT, { ",", IDENT }, [ "," ], ")" ;
assignment_stmt = lvalue, ASSIGN_OP, expression, NEWLINE ;
drop_stmt = "_", "=", expression, NEWLINE ;
lvalue = ( IDENT | "self" ), { lvalue_part }
| "*", unary_expr
| "(", lvalue, ")", { lvalue_part } ;
lvalue_part = ".", IDENT | "[", expression, "]" ;
ASSIGN_OP = "=" | "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "+%=" | "-%=" | "*%="
| "+|=" | "-|=" | "*|=" | "&=" | "|=" | "^=" | "<<=" | ">>=" ;
if_stmt = "if", condition, ":", suite, { "elif", condition, ":", suite },
[ "else", ":", suite ] ;
condition = expression | "let", IDENT, "=", expression ;
while_stmt = "while", condition, ":", suite ;
for_stmt = "for", ( IDENT, [ ":", type ] | "(", IDENT, ",", IDENT, ")" ), "in",
[ "&" ], expression, ":", suite ;
labeled_loop = IDENT, ":", ( while_stmt | for_stmt ) ;
with_stmt = "with", expression, ":", suite ;
match_stmt = "match", expression, ":", NEWLINE, INDENT, match_arm, { match_arm }, DEDENT ;
match_arm = pattern, { ",", pattern }, [ "if", expression ], ":", suite ;
pattern = "_" | literal_pattern | case_pattern ;
literal_pattern = pattern_literal, [ ( "..<" | "..=" ), pattern_literal ] ;
pattern_literal = literal | "-", ( INTEGER_LITERAL | FLOAT_LITERAL ) ;
case_pattern = ".", ( IDENT | "none" | "some" ), [ "(", [ ( IDENT | "_" ), { ",", ( IDENT | "_" ) } ], ")" ] ;
asm_stmt = "asm", IDENT, [ "(", asm_operand, { ",", asm_operand }, ")" ],
":", NEWLINE, INDENT, RAW_LINE, { RAW_LINE }, DEDENT ;
asm_operand = "in", "(", asm_place, ")", expression
| ( "out" | "inout" ), "(", asm_place, ")", ( lvalue | "_" )
| "options", "(", IDENT, { ",", IDENT }, ")" ;
asm_place = STRING_LITERAL | "reg" ;
expression = else_expr, [ "catch", IDENT, ":", suite ] ;
else_expr = "try", else_expr | conditional_expr, [ "else", else_expr ] ;
conditional_expr
= or_expr, [ "if", or_expr, "else", conditional_expr ] ;
or_expr = and_expr, { "or", and_expr } ;
and_expr = comparison_expr, { "and", comparison_expr } ;
comparison_expr = range_expr, [ COMPARE_OP, range_expr ] ;
range_expr = bit_or_expr, [ ( "..<" | "..=" ), bit_or_expr ] ;
bit_or_expr = bit_xor_expr, { "|", bit_xor_expr } ;
bit_xor_expr = bit_and_expr, { "^", bit_and_expr } ;
bit_and_expr = shift_expr, { "&", shift_expr } ;
shift_expr = additive_expr, { ( "<<" | ">>" ), additive_expr } ;
additive_expr = multiply_expr, { ( "+" | "-" | "+%" | "-%" | "+|" | "-|" | "+?" | "-?" ), multiply_expr } ;
multiply_expr = unary_expr, { ( "*" | "/" | "//" | "%" | "*%" | "*|" | "*?" ), unary_expr } ;
unary_expr = { "try" | "not" | "+" | "-" | "-%" | "~" | "*" | "&" | cast_prefix }, postfix_expr ;
cast_prefix = "(", type, ")" ; (* only when the parenthesised text is cast-shaped, §7.5 *)
postfix_expr = primary_expr, { ".", IDENT | argument_list | type_arguments, argument_list
| "[", index_or_slice, "]" } ;
call_expression = postfix_expr ;
argument_list = "(", [ argument, { ",", argument }, [ "," ] ], ")" ;
argument = [ IDENT, "=" ], expression ;
index_or_slice = expression | expression, "..<", expression | "..<", expression | expression, ".." ;
primary_expr = literal | IDENT | "self" | ".", IDENT, [ argument_list ]
| "(", expression, [ ",", expression, { ",", expression }, [ "," ] ], ")"
| "(", ")"
| "[", [ expression, { ",", expression }, [ "," ] ], "]"
| lambda_expr | match_expr | span_constructor | new_expr ;
lambda_expr = "(", [ IDENT, [ ":", type ], { ",", IDENT, [ ":", type ] } ], ")", "=>", expression ;
match_expr = "match", expression, ":", NEWLINE, INDENT,
match_value_arm, { match_value_arm }, DEDENT ;
match_value_arm = pattern, { ",", pattern }, [ "if", expression ], "=>", expression, NEWLINE ;
span_constructor
= type, "[", "]", argument_list ; (* u8[](pointer, count) *)
new_expr = "new", new_target, [ "in", expression ] ;
new_target = type_core, { "*" | "?" }, ( "[", expression, "]", [ "---" ] | argument_list | ".", IDENT, argument_list | ) ;
type = [ "@" ], [ "const" ], [ "volatile" ], type_core,
{ "*", [ "?" ] | "[", constant_expression, "]" | "[", "]" }, [ "?" ], [ "!" ] ;
type_core = type_name, [ type_arguments ]
| "func", "(", [ type, { ",", type } ], ")", "->", type
| "void"
| "(", type, ")"
| "(", type, ",", type, { ",", type }, [ "," ], ")" ;
type_name = TYPE_PATH | CORE_TYPE ;
type_arguments = "[", type, { ",", type }, [ "," ], "]" ;
interface_type = type_name, [ type_arguments ] ;
integer_type = "u8" | "u16" | "u32" | "u64" | "i8" | "i16" | "i32" | "i64" | "usize" | "isize" ;
literal = INTEGER_LITERAL | FLOAT_LITERAL | CHAR_LITERAL | STRING_LITERAL | BYTES_LITERAL
| formatted_string | "true" | "false" | "none" ;
formatted_string
= FORMAT_START, { FORMAT_TEXT | "{", expression, [ ":", FORMAT_SPEC ], "}" }, FORMAT_END ;Notes on the shape. Qualifiers bind to the innermost type_core, so const (T*)* is C's T *const * and void must be followed by at least one *. A ? may follow any * and the final suffix; ?? is rejected semantically. A type_arguments bracket contains types; a bracket after a complete type containing a constant expression or nothing is an array or span suffix. *% and the other operator forms are recognised only between two operands, so they cannot be confused with a dereference. The tokens @, ---, ..., and the wrapping, saturating, and checked operators are matched longest-first and admitted by the parser in Base modules only, so the formatter stays single. A statement beginning IDENT ":" is a labeled loop and nothing else, because no other statement begins with a bare identifier and a colon. new T[n] is a span allocation, new T[n] --- one left unwritten; new (T[4]) is a pointer to an array.