Luce Base
LuceEngineeringLuciaOS

21. Grammar

Repetition is {...}, optional syntax is [...], quoted text is a token. 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. 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, { ",", 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 )
                | "export", function_decl
                | test_decl
                | asm_module_decl ;

constant_decl   = "let", IDENT, [ ":", type ], "=", expression, NEWLINE ;
global_decl     = [ "thread_local" ], "var", IDENT, ":", type, NEWLINE ;
type_alias      = "type", TYPE_IDENT, "=", type, NEWLINE ;

function_decl   = [ "inline" ], [ "mutating" ], "func", [ TYPE_IDENT, "." ], IDENT,
                  [ generic_params ], parameter_list, result_clause, ":", suite ;
function_sig    = [ "mutating" ], "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       = "self" | IDENT, ":", type, [ "=", constant_expression ] ;
result_clause   = [ "->", type ] ;

implements_clause
                = [ "implements", interface_type, { ",", interface_type } ] ;
struct_decl     = [ "packed" | "align", "(", INTEGER_LITERAL, ")" ],
                  "struct", TYPE_IDENT, [ generic_params ], implements_clause, ":",
                  NEWLINE, INDENT, type_member, { type_member }, DEDENT ;
type_member     = [ "pub" ], ( field_decl | function_decl ) ;
field_decl      = ( "let" | "var" ), IDENT, ":", type, [ "=", constant_expression ], NEWLINE ;

enum_decl       = "enum", TYPE_IDENT, [ generic_params ], [ "as", integer_type ],
                  implements_clause, ":", NEWLINE, INDENT,
                  enum_case, { enum_case }, { [ "pub" ], function_decl }, DEDENT ;
enum_case       = IDENT, [ payload_list | "=", INTEGER_LITERAL ], 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    = 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 ;
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   = "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 | asm_stmt ;
simple_stmt     = binding_stmt | assignment_stmt
                | "break", [ IDENT ], NEWLINE
                | "continue", [ IDENT ], NEWLINE
                | "return", [ expression ], NEWLINE
                | "defer", call_expression, NEWLINE
                | "errdefer", call_expression, NEWLINE
                | "recover", 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 ;
lvalue          = IDENT, { lvalue_part }
                | "*", unary_expr
                | "(", lvalue, ")", { lvalue_part } ;
lvalue_part     = ".", IDENT | "[", expression, "]" ;
ASSIGN_OP       = "=" | "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "+%=" | "-%=" | "*%="
                | "&=" | "|=" | "^=" | "<<=" | ">>=" ;

if_stmt         = "if", expression, ":", suite, { "elif", expression, ":", suite },
                  [ "else", ":", suite ]
                | "if", "let", IDENT, "=", expression, ":", suite, [ "else", ":", suite ] ;
while_stmt      = "while", expression, ":", suite
                | "while", "let", IDENT, "=", expression, ":", suite ;
for_stmt        = "for", IDENT, "in", expression, ":", suite ;
labeled_loop    = IDENT, ":", ( while_stmt | for_stmt ) ;

match_stmt      = "match", expression, ":", NEWLINE, INDENT, match_arm, { match_arm }, DEDENT ;
match_arm       = pattern, { ",", pattern }, ":", suite ;
pattern         = "_" | literal_pattern | case_pattern ;
literal_pattern = pattern_literal, [ ( "..<" | "..=" ), pattern_literal ] ;
pattern_literal = literal | "-", ( INTEGER_LITERAL | FLOAT_LITERAL ) ;
case_pattern    = ".", IDENT, [ "(", [ IDENT, { ",", IDENT } ], ")" ] ;

asm_stmt        = "asm", IDENT, [ "(", asm_operand, { ",", asm_operand }, ")" ],
                  ":", NEWLINE, INDENT, RAW_LINE, { RAW_LINE }, DEDENT ;
asm_operand     = ( "in" | "out" | "inout" ), ( "reg" | "mem" ), IDENT
                | "clobber", ( IDENT | "memory" ), { ",", ( IDENT | "memory" ) } ;

expression      = else_expr, [ "catch", IDENT, ":", suite ] ;
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 | ".", IDENT, [ argument_list ]
                | "(", expression, [ ",", expression, { ",", expression }, [ "," ] ], ")"
                | "(", ")"
                | "[", [ expression, { ",", expression }, [ "," ] ], "]"
                | lambda_expr | match_expr | span_constructor ;
lambda_expr     = "(", [ IDENT, [ ":", type ], { ",", IDENT, [ ":", type ] } ], ")", "=>", expression ;
match_expr      = "match", expression, ":", NEWLINE, INDENT,
                  pattern, { ",", pattern }, "=>", expression, NEWLINE,
                  { pattern, { ",", pattern }, "=>", expression, NEWLINE }, DEDENT ;
span_constructor
                = type, "[", "]", argument_list ;          (* u8[](pointer, count) *)

type            = [ "@" ], [ "const" ], [ "volatile" ], type_core,
                  { "*" | "[", INTEGER_LITERAL, "]" | "[", "]" }, [ "?" ], [ "!" ] ;
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" ;
literal         = INTEGER_LITERAL | FLOAT_LITERAL | CHAR_LITERAL | STRING_LITERAL
                | formatted_string | "true" | "false" | "none" ;
formatted_string
                = FORMAT_START, { FORMAT_TEXT | "{", expression, "}" }, 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 type_arguments bracket contains types; a bracket after a complete type containing only an integer literal or nothing is an array or span suffix. *% is recognised only between two operands, so it cannot be confused with a dereference. The new tokens @, ---, ..., +%, -%, *%, +%=, -%=, *%= 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.