Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

形式化语法

以下文法描述当前普通解析器接受的主要语法,使用扩展 BNF 记法。属性宏和派生宏会在普通解析前展开;宏参数因此以平衡 token tree 表示,而不在这里展开其内部语法。

program = statement*;

attribute = "#" "[" attribute_body "]";
attribute_body = balanced tokens until matching "]";

statement =
    attribute* (
    use_decl
  | mod_decl
  | extern_block
  | extern_fn_decl
  | enum_decl
  | trait_decl
  | impl_decl
  | const_decl
  | type_alias_decl
  | var_decl
  | func_decl
  | struct_decl
  | break_stmt
  | continue_stmt
  | return_stmt
  | expr_stmt
  );

// == FFI ==

extern_block = "pub"? "unsafe" "extern" string_lit "{" (attribute* extern_func_sig)* "}";

extern_func_sig = ("safe" | "unsafe")? "fun" ident "(" (param ("," param)*)? ")" ("->" ty)? ";";

extern_fn_decl = "pub"? "unsafe"? "extern" string_lit func_def;

// == module / use ==

mod_decl = "pub"? "mod" ident (";" | "{" statement* "}");

use_decl = "pub"? "use" use_tree ";";

use_tree =
    path (("as" ident) | ("::" "*") | ("::" "{" use_tree ("," use_tree)* ","? "}"))?
  | "{" use_tree ("," use_tree)* ","? "}";

// == items ==

enum_decl = "pub"? "enum" ident item_generic_params? where_clause? "{" (enum_variant ("," enum_variant)* ","?)? "}";
enum_variant = attribute* ident (("(" type_list? ")") | ("{" struct_field_list? "}"))?;

trait_decl = "pub"? "trait" ident trait_generic_params? (":" generic_bound ("+" generic_bound)*)? "{" trait_item* "}";
trait_item = attribute* (func_decl | assoc_type_decl);

impl_decl = "impl" generic_params? ty ("for" ty)? where_clause? "{" impl_item* "}";
impl_item = attribute* (func_decl | type_alias_decl | const_decl);

func_sig = "unsafe"? "fun" ident generic_params? "(" (param ("," param)*)? ")" ("->" ty)? where_clause?;
type_alias_decl = "pub"? "type" ident "=" ty ";";
assoc_type_decl = "pub"? "type" ident ("=" ty)? ";";
const_decl = "pub"? "const" ident ":" ty "=" expression ";";

item_generic_params = "<" item_generic_param ("," item_generic_param)* ">";
item_generic_param = ident | "const" ident ":" ty;

generic_params = "<" generic_param ("," generic_param)* ">";
generic_param = ident (":" generic_bound ("+" generic_bound)*)? | "const" ident ":" ty;
trait_generic_params = "<" trait_generic_param ("," trait_generic_param)* ">";
trait_generic_param = ident (":" generic_bound ("+" generic_bound)*)? ("=" ty)? | "const" ident ":" ty;
generic_bound = callable_bound | path ("<" generic_bound_arg ("," generic_bound_arg)* ","? ">")?;
generic_bound_arg = ident "=" ty | ty;
callable_bound = ("Fn" | "FnMut" | "FnOnce") "(" type_list? ")" "->" ty;
where_clause = "where" where_predicate ("," where_predicate)* ","?;
where_predicate = ty ":" generic_bound ("+" generic_bound)*;

type_args = "<" type_list? ">";
type_list = ty ("," ty)* ","?;

// == normal statements ==

var_decl = "let" pattern (":" ty)? ("=" expression ("else" block)?)? ";";

param = attribute* ((("&" "mut"?)? "self") | ("mut"? ident ":" ty));

func_def = "fun" ident generic_params? "(" (param ("," param)*)? ")" ("->" ty)? where_clause? block;
func_decl = "pub"? "unsafe"? "fun" ident generic_params? "(" (param ("," param)*)? ")" ("->" ty)? where_clause? (block | ";");

block = "{" statement* expression? "}";

struct_param = attribute* "pub"? ident ":" ty;

struct_decl = "pub"? "struct" ident item_generic_params? where_clause? "{" (struct_param ("," struct_param)* ","?)? "}";

break_stmt = "break" expression? ";";
continue_stmt = "continue" ";";
return_stmt = "return" expression? ";";

expr_stmt = expr_without_block ";" | expr_with_block ";"?;

// == expression ==

expression = expr_with_block | expr_without_block | range_expr;

expr_with_block = block | if_expr | while_expr | loop_expr | for_expr | match_expr | unsafe_expr;

if_expr = "if" (expression | let_condition) block ("else" (if_expr | block))?;

while_expr = "while" (expression | let_condition) block;

let_condition = "let" pattern "=" expression;

loop_expr = "loop" block;

for_expr = "for" pattern "in" expression block;

match_expr = "match" expression "{" match_arm ("," match_arm)* ","? "}";
// 块体 arm(`=> block`)的 `}` 自身终止该 arm,其后的逗号可省略。
match_arm = attribute* pattern ("if" expression)? "=>" expression;

unsafe_expr = "unsafe" block;

expr_without_block = unary (("as" ty) | (binop unary))*;

// 区间表达式:右结合,优先级低于 `||`;`for` 头部与语句表达式位置可用
range_expr = expr_without_block (".." | "..=") expr_without_block;

lambda_param = pattern (":" ty)?;

// 方括号 lambda:`[it -> it * 2]`。判别规则:`[` 组内嵌套深度 0 处出现 `->`
// 即为 lambda,否则为数组字面量。`expr [params -> body]`(后缀位置)表示
// 以该 lambda 为实参调用 `expr`(通常是方法,如 `values.map [v -> v * 2]`)。
bracket_lambda_expr = "move"? "[" bracket_lambda_body "]";
bracket_lambda_body = (lambda_param ("," lambda_param)*)? "->" expression;

unary = prefix_op unary | postfix;

postfix = primary ( "::" "<" type_arg_list ">" "(" arg_list ")" | "(" arg_list ")" | "." (ident | number) | "[" (expression | bracket_lambda_body) "]" | struct_expr_fields | "::" "<" type_arg_list ">" struct_expr_fields | "." ident "(" arg_list ")" | "?" )*;

arg_list = (expression ("," expression)*)?;

type_arg_list = type_list;

primary = literal | macro_call | path | array_expr | tuple_expr | bracket_lambda_expr | "(" expression? ")";

macro_call = path "!" token_tree;
token_tree = "(" balanced_tokens ")" | "[" balanced_tokens "]" | "{" balanced_tokens "}";
balanced_tokens = balanced token sequence;

tuple_expr = "(" expression "," ")"
           | "(" expression ("," expression)+ ","? ")";

array_expr = "[" "]"
           | "[" expression ("," expression)* ","? "]"
           | "[" expression ";" expression "]";

struct_expr = path struct_expr_fields;
struct_expr_fields = "{" (struct_expr_field ("," struct_expr_field)* ","?)? "}";

struct_expr_field = ident (":" expression)?;

pattern = attribute* ("_" | "mut"? ident | literal | macro_call | path | reference_pattern | tuple_pattern | struct_pattern | enum_pattern);

reference_pattern = ("&" "mut"? | "&&" "mut"?) pattern;
tuple_pattern = "(" (pattern ("," pattern)* ","?)? ")";
struct_pattern = path "{" (field_pattern ("," field_pattern)* ","?)? "}";
field_pattern = attribute* ident (":" pattern)?;
enum_pattern = path | path "(" (pattern ("," pattern)* ","?)? ")" | path "{" (field_pattern ("," field_pattern)* ","?)? "}";

// Precedence & Associativity (Pratt binding powers)
//
// Assignment:
//   = += -= *= /= %= &= |= ^= <<= >>=   right-assoc       (lbp=1,  rbp=1)
//
// Prefix (right):  + - & && * !       rbp = 14
//
// Postfix:
//   () . [] ?   left-assoc    (lbp = 15)
//
// Infix:
//   as                            (lbp=13, rbp=13)
//   *  /  %        left-assoc        (lbp=12, rbp=13)
//   +  -           left-assoc        (lbp=10, rbp=11)
//   & | ^ << >>    left-assoc        (lbp=9,  rbp=10)
//   <  >  <=  >=   left-assoc        (lbp=8,  rbp=9)
//   ==  !=         left-assoc        (lbp=6,  rbp=7)
//   &&             left-assoc        (lbp=4,  rbp=5)
//   ||             left-assoc        (lbp=2,  rbp=3)
//
// Range:
//   .. ..=         right-assoc       (lbp=1,  rbp=2)
//
// In `if`, `while`, `for`, and `match` heads, struct expressions are disabled so
// `if Foo { ... }` keeps parsing `{ ... }` as the control-flow block.

// == path / type ==

path_segment = (ident | "self" | "super" | "crate") ("::" type_args)?;
path = ("::")? path_segment ("::" path_segment)*;

ty = attribute* (
     "!"
   | macro_call
   | path type_args?
   | "&" "mut"? ty
   | "&&" ty
   | "*" ("const" | "mut") ty
   | "[" ty (";" expression)? "]"
   | int_lit
   | impl_callable_type
   | dyn_trait_type
   | "(" (ty ("," ty)* ","?)? ")"
   );

impl_callable_type = "impl" callable_bound;

dyn_trait_type = "dyn" generic_bound;

// == operators ==

prefix_op = "+" | "-" | "&" ("mut")? | "&&" | "*" | "!";

binop = "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>="
      | "||" | "&&" | "==" | "!=" | "<" | ">" | "<=" | ">="
      | "|" | "^" | "&" | "<<" | ">>"
      | "+" | "-" | "*" | "/" | "%";

// == literals ==

literal = int_lit | float_lit | string_lit | char_lit | bool_lit;

int_lit = (dec_lit | hex_lit | oct_lit | bin_lit) int_suffix?;
dec_lit = [0-9] [0-9_]*;
hex_lit = "0x" "_"* [0-9a-fA-F] [0-9a-fA-F_]*;
oct_lit = "0o" "_"* [0-7] [0-7_]*;
bin_lit = "0b" "_"* [01] [01_]*;
int_suffix = "i8" | "i16" | "i32" | "i64" | "i128" | "isize"
           | "u8" | "u16" | "u32" | "u64" | "u128" | "usize";
float_lit = [0-9]+ ("." [0-9]+)? ([eE] [+-]? [0-9]+)? ("f16" | "f32" | "f64" | "f128")?;
string_lit = "\"" ... "\"" | "r" "#"* "\"" ... "\"" "#"*;
char_lit = "'" ... "'";
bool_lit = "true" | "false";

ident = [a-zA-Z_][a-zA-Z0-9_]*;

&pattern&mut pattern 分别解构一层同可变性的共享引用和可变引用;它们可以嵌套,例如 &&mut value。Riddle 不提供 ref nameref mut name 绑定语法。结构化模式匹配引用时会自动解引用并让内部绑定继承引用模式;默认绑定模式变为引用后,内部不能再写 mut binding 或显式 &pattern / &mut pattern。需要显式引用模式时,应让它出现在默认 move 模式的位置。详见枚举、模式与 match

词法层接受 i128u128f16f128 字面量后缀,但类型系统只支持 8 到 64 位整数与 f32 / f64;使用不支持的尾缀会报告 E0011。整数字面量支持十进制、0x 十六进制、0o 八进制、0b 二进制和 _ 分隔符。

let 可以在声明处初始化,也可以省略初始化式并稍后赋值:let pattern = expression;let pattern: Type; 和可由首次赋值推断类型的 let pattern; 都是合法语法。带初始化式的 let 还可以写 let-else:let pattern = expression else block;,模式不可反驳时必须发散的 else 块负责提前退出;else 块不发散会报告 E0066。延迟初始化的绑定必须在每条到达使用点的路径上先完成赋值;否则会报告 E0059。引用解构依赖初始化式的值类别,因此不能用于延迟初始化声明。type Name; 只用于 trait 中声明关联类型;模块和 impl 中的类型别名需要写出 = Type

::<...> 类型实参在类型位置可以直接书写;作为表达式时,只有后面紧跟 ((调用)或 {(结构体字面量)才会被解析,Foo::<i32> 这样的裸 turbofish 表达式会被拒绝。