(* Leia user-facing grammar. This file is the syntax appendix for docs/spec/index.md. It describes stable source syntax, not parser helper productions or internal AST shapes. Dialect tags such as sh, json, re, prompt, AI workflow tags, and user-defined names are ordinary identifiers until they appear directly before a tagged string or tagged block. *) program = { separator | statement } EOF ; separator = ";" ; block = "{" { separator | statement } "}" ; statement = func_decl | import_decl | if_stmt | for_stmt | select_stmt | return_stmt | break_stmt | continue_stmt | goto_stmt | label_stmt | go_stmt | defer_stmt | const_decl | simple_stmt ; func_decl = "func" identifier param_list block ; import_decl = "import" ( import_spec | "(" { import_spec } ")" ) ; import_spec = [ identifier ] string_lit | string_lit "as" identifier ; param_list = "(" [ param { "," param } [ "," vararg_param ] | vararg_param ] ")" ; param = identifier ; vararg_param = "..." | identifier "..." ; if_stmt = "if" expr block { "elseif" expr block } [ "else" block ] ; for_stmt = "for" block | "for" expr block | "for" simple_stmt ";" expr ";" simple_stmt block | "for" identifier [ "," identifier ] ":=" "range" expr block ; select_stmt = "select" "{" { select_case } "}" ; select_case = ( "case" ( recv_clause | send_clause ) | "default" ) ":" { separator | statement } ; recv_clause = "<-" expr | identifier ":=" "<-" expr | identifier "," identifier ":=" "<-" expr ; send_clause = expr "<-" expr ; return_stmt = "return" [ expr_list ] ; break_stmt = "break" ; continue_stmt = "continue" ; goto_stmt = "goto" identifier ; label_stmt = identifier ":" ; go_stmt = "go" call_expr ; defer_stmt = "defer" call_expr ; const_decl = "const" identifier ( "=" | ":=" ) expr ; simple_stmt = assignment | compound_assignment | inc_dec_stmt | send_clause | call_expr | expr ; assignment = expr_list ( "=" | ":=" ) expr_list ; compound_assignment = expr ( "+=" | "-=" | "*=" | "/=" ) expr ; inc_dec_stmt = expr ( "++" | "--" ) ; expr_list = expr { "," expr } ; expr = logical_or ; logical_or = logical_and { "||" logical_and } ; logical_and = comparison { "&&" comparison } ; comparison = concat { ( "==" | "!=" | "<" | "<=" | ">" | ">=" ) concat } ; concat = additive [ ".." concat ] ; additive = multiplicative { ( "+" | "-" | "|" | "^" ) multiplicative } ; multiplicative = unary { ( "*" | "/" | "%" | "<<" | ">>" | "&" | "&^" ) unary } ; unary = ( "!" | "-" | "#" | "<-" | "^" ) unary | power ; power = postfix { "**" unary } ; postfix = primary { call_suffix | method_suffix | index_suffix | member_suffix } ; call_expr = postfix ( call_suffix | method_suffix ) ; call_suffix = "(" [ expr_list ] ")" ; method_suffix = ":" identifier "(" [ expr_list ] ")" ; index_suffix = "[" expr "]" ; member_suffix = "." identifier ; primary = identifier | number_lit | string_lit | "true" | "false" | "nil" | "..." | "(" expr ")" | func_lit | tagged_string | tagged_block | table_lit | list_lit | dense_lit ; func_lit = "func" param_list block ; tagged_string = ( identifier | "$" ) [ "!" ] tagged_raw_string_lit ; tagged_block = identifier [ "!" ] config_block ; config_block = "{" [ config_field { field_sep config_field } [ field_sep ] ] "}" ; config_field = identifier ":" expr | string_lit ":" expr | "[" expr "]" ":" expr ; table_lit = "{" [ table_field { field_sep table_field } [ field_sep ] ] "}" ; table_field = identifier ":" expr | "[" expr "]" ":" expr | expr ; list_lit = "[" [ expr { field_sep expr } [ field_sep ] ] "]" ; dense_lit = "[" [ integer_lit ] "]" dense_type "{" [ expr { field_sep expr } [ field_sep ] ] "}" ; dense_type = "i32" | "i64" | "f32" | "f64" | "bool" ; field_sep = "," | ";" ; identifier = ( "A".."Z" | "a".."z" | "_" ) { "A".."Z" | "a".."z" | "0".."9" | "_" } ; number_lit = integer_lit | float_lit ; integer_lit = decimal_lit | hex_lit | binary_lit | octal_lit ; decimal_lit = digit { digit | "_" } ; hex_lit = "0" ( "x" | "X" ) hex_digit { hex_digit | "_" } ; binary_lit = "0" ( "b" | "B" ) ( "0" | "1" ) { "0" | "1" | "_" } ; octal_lit = "0" ( "o" | "O" ) ( "0".."7" ) { "0".."7" | "_" } ; float_lit = decimal_lit "." decimal_lit [ exponent ] | decimal_lit exponent ; exponent = ( "e" | "E" ) [ "+" | "-" ] decimal_lit ; digit = "0".."9" ; hex_digit = digit | "A".."F" | "a".."f" ; string_lit = double_quoted_string | single_quoted_string | raw_string_lit ; double_quoted_string = '"' { escaped_char | interpolation | any_char_except_double_quote_or_newline } '"' ; single_quoted_string = "'" { escaped_char | any_char_except_single_quote_or_newline } "'" ; raw_string_lit = short_raw_string | fenced_raw_string ; short_raw_string = "`" { any_char_except_backtick } "`" ; fenced_raw_string = "```" { any_char_except_three_backticks } "```" ; tagged_raw_string_lit = tagged_short_raw_string | tagged_fenced_raw_string ; tagged_short_raw_string = "`" { tagged_raw_char | interpolation } "`" ; tagged_fenced_raw_string = "```" { tagged_fenced_raw_char | interpolation } "```" ; interpolation = "${" expr "}" ; escaped_char = "\\" ( "\\" | '"' | "'" | "a" | "b" | "f" | "n" | "r" | "t" | "v" | "x" hex_digit hex_digit | "u" hex_digit hex_digit hex_digit hex_digit | "U" hex_digit hex_digit hex_digit hex_digit hex_digit hex_digit hex_digit hex_digit | decimal_escape ) ; decimal_escape = digit [ digit [ digit ] ] ; any_char_except_double_quote_or_newline = ? any Unicode scalar value except '"' and newline ? ; any_char_except_single_quote_or_newline = ? any Unicode scalar value except "'" and newline ? ; any_char_except_backtick = ? any Unicode scalar value except "`" ? ; any_char_except_three_backticks = ? any Unicode scalar sequence not containing "```" ? ; tagged_raw_char = ? any Unicode scalar value except "`" and the start of "${" ? ; tagged_fenced_raw_char = ? any Unicode scalar sequence not containing "```" or the start of "${" ? ;