Luce Base
LuceSourceLuciaOS

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.