[(block) (declaration_list) (impl_item) ;; let expressions create scopes (if_expression [(let_condition) (let_chain)]) ;; each match arm can bind variables with ;; patterns, without creating a block scope; ;; ;; match _ { ;; (a, b) => a, ;; } ;; ;; The bindings for a, b are constrained to ;; the match arm. (match_arm) ;; loop labels are defs that are available only ;; within the scope they create: ;; ;; 'outer: loop { ;; let x = 2; ;; }; ;; let y = 2; ;; ;; Produces a scope graph like so: ;; ;; { ;; defs: [ y ], ;; scopes: [ ;; { ;; defs: [ 'outer ], ;; scopes: [ ;; { ;; defs: [ x ] ;; } ;; ] ;; } ;; ] ;; } ;; (loop_expression) (for_expression) (while_expression)] @cap { (scope (range @cap)) } (function_item (identifier) @i (parameters) @params (block) @body) { (def @i "function") (scope (cover @params @body)) } ;; impl items can define types and lifetimes: ;; ;; impl<'a, T> Trait for Struct { .. } ;; ;; in order to constrain those to the impl block, ;; we add a local scope here: [(struct_item (type_identifier) @i (type_parameters)? @t body: (_) @b) (union_item (type_identifier) @i (type_parameters)? @t body: (_) @b) (enum_item (type_identifier) @i (type_parameters)? @t body: (_) @b) (type_item (type_identifier) @i (type_parameters)? @t type: (_) @b) (trait_item (type_identifier) @i (type_parameters)? @t body: (_) @b)] { (def @i) (scope (cover @t @b)) (scope (range @b)) } ;; DEFS ;; ---- ;; let x = ...; (let_declaration pattern: (identifier) @cap) { (def @cap "variable") } ;; if let x = ...; ;; while let x = ...; (let_condition (identifier) @cap . "=") { (def @cap "variable") } ;; let (a, b, ...) = ..; ;; if let (a, b, ...) = {} ;; while let (a, b, ...) = {} ;; match _ { (a, b) => { .. } } (tuple_pattern (identifier) @cap) { (def @cap "variable") } ;; Some(a) (tuple_struct_pattern type: (_) (identifier) @cap) { (def @cap "variable") } ;; let S { field: a } = ..; (struct_pattern (field_pattern (identifier) @cap)) { (def @cap "variable") } [ ;; (mut x: T) (mut_pattern (identifier) @i) ;; (ref x: T) (ref_pattern (identifier) @i) ;; const x = ...; (const_item (identifier) @i) ;; static x = ...; (static_item (identifier) @i)] { (def @i "variable") } ;; fn _(x: _) (parameters (parameter pattern: (identifier) @cap)) { (def @cap) } ;; fn _(self) (parameters (self_parameter (self) @cap)) { (def @cap) } ;; type parameters (type_parameters (type_identifier) @cap) { (def @cap) } (type_parameters (lifetime) @cap) { (def @cap) } (constrained_type_parameter left: (type_identifier) @cap) { (def @cap) } ;; |x| { ... } ;; no type (closure_parameters (identifier) @cap) { (def @cap) } ;; |x: T| { ... } ;; with type (closure_parameters (parameter (identifier) @cap)) { (def @cap) } ;; 'outer: loop { .. } (loop_expression (loop_label) @cap) { (def @cap) } ;; `for` exprs create two defs: a label (if any) and the ;; loop variable (for_expression . (identifier) @cap) { (def @cap) } (for_expression (loop_label) @cap) { (def @cap) } ;; 'label: while cond { .. } (while_expression (loop_label) @cap) { (def @cap) } ;; struct and union fields (field_declaration_list (field_declaration (field_identifier) @cap)) { (def @cap) } ;; enum variants (enum_variant_list (enum_variant (identifier) @cap)) { (def @cap) } ;; mod x; (mod_item (identifier) @cap) { (def @cap) } ;; IMPORTS ;; ------- ;; use item; (use_declaration (identifier) @cap) { (def @cap) } ;; use path as item; (use_as_clause alias: (identifier) @cap) { (def @cap) } ;; use path::item; (use_declaration (scoped_identifier name: (identifier) @cap)) { (def @cap) } ;; use module::{member1, member2, member3}; (use_list (identifier) @cap) { (def @cap) } (use_list (scoped_identifier name: (identifier) @cap)) { (def @cap) } ;; REFS ;; ---- [ ;; !x (unary_expression (identifier) @cap) ;; &x (reference_expression (identifier) @cap) ;; (x) (parenthesized_expression (identifier) @cap) ;; x? (try_expression (identifier) @cap) ;; a = b (assignment_expression (identifier) @cap) ;; a op b (binary_expression (identifier) @cap) ;; a op= b (compound_assignment_expr (identifier) @cap) ;; a as b (type_cast_expression (identifier) @cap) ;; a() (call_expression (identifier) @cap) ;; return a (return_expression (identifier) @cap) ;; break a (break_expression (identifier) @cap) ;; break 'label (break_expression (loop_label) @cap) ;; continue 'label; (continue_expression (loop_label) @cap) ;; yield x; (yield_expression (identifier) @cap) ;; await a (await_expression (identifier) @cap) ;; (a, b) (tuple_expression (identifier) @cap) ;; a[] (index_expression (identifier) @cap) ;; ident; (expression_statement (identifier) @cap) ;; a..b (range_expression (identifier) @cap) ;; [ident; N] (array_expression (identifier) @cap) ;; path::to::item ;; ;; `path` is a ref (scoped_identifier path: (identifier) @cap) ;; rhs of let decls (let_declaration value: (identifier) @cap) ;; type T = [T; N] ;; ;; N is a ident ref (array_type length: (identifier) @cap) ;; S { _ } (struct_expression (type_identifier) @cap) ;; S { a } (struct_expression (field_initializer_list (shorthand_field_initializer (identifier) @cap))) ;; S { a: value } (struct_expression (field_initializer_list (field_initializer (identifier) @cap))) ;; S { ..a } (struct_expression (field_initializer_list (base_field_initializer (identifier) @cap))) ;; if a {} (if_expression (identifier) @cap) ;; for pattern in value {} ;; ;; `value` is a ref (for_expression value: (identifier) @cap) ;; while a {} (while_expression (identifier) @cap) ;; match a (match_expression (identifier) @cap) ;; match _ { ;; pattern => a, ;; } ;; ;; this `a` is somehow not any expression form (match_arm (identifier) @cap) ;; a.b ;; ;; `b` is ignored (field_expression (identifier) @cap) ;; { stmt; foo } (block (identifier) @cap) ;; arguments to method calls or function calls (arguments (identifier) @cap) ;; impl S { .. } (impl_item (type_identifier) @cap) ;; where T: ... (where_predicate left: (type_identifier) @cap) ;; trait bounds (trait_bounds (type_identifier) @cap) (trait_bounds (lifetime) @cap) ;; idents in macros (token_tree (identifier) @cap) ;; types ;; (T, U) (tuple_type (type_identifier) @cap) ;; &T (reference_type (type_identifier) @cap) ;; &'a T (reference_type (lifetime) @cap) ;; &'a self (self_parameter (lifetime) @cap) ;; *mut T ;; *const T (pointer_type (type_identifier) @cap) ;; A<_> (generic_type (type_identifier) @cap) ;; _ (type_arguments (type_identifier) @cap) (type_arguments (lifetime) @cap) ;; T ;; ;; U is ignored ;; V is a ref (type_binding name: (_) type: (type_identifier) @cap) ;; [T] (array_type (type_identifier) @cap) ;; type T = U; ;; ;; T is a def ;; U is a ref (type_item name: (_) type: (type_identifier) @cap) (function_item return_type: (type_identifier) @cap) ;; type refs in params ;; ;; fn _(_: T) (parameters (parameter type: (type_identifier) @cap)) ;; dyn T (dynamic_type (type_identifier) @cap) ;; ::call() (bracketed_type (type_identifier) @cap) ;; T as Trait (qualified_type (type_identifier) @cap) ;; module::T ;; ;; `module` is a def ;; `T` is a ref (scoped_type_identifier path: (identifier) @cap) ;; struct _ { field: Type } ;; `Type` is a ref (field_declaration name: (_) type: (type_identifier) @cap) ;; Self::foo() ;; ;; `foo` can be resolved (call_expression (scoped_identifier (identifier) @_self_type (identifier) @cap) (#match? @_self_type "Self")) ;; self.foo() ;; ;; `foo` can be resolved (call_expression (field_expression (self) (field_identifier) @cap)) ;; if let _ = a {} ;; ;; the ident following the `=` is a ref ;; the ident preceding the `=` is a def ;; while let _ = a {} (let_condition "=" . (identifier) @cap) ] { (ref @cap) }