11//! Link pass: resolve node types and fields against tree-sitter grammar.
22//!
3- //! Three-phase approach:
4- //! 1. Collect and resolve all node type names (NamedNode, AnonymousNode)
5- //! 2. Collect and resolve all field names (FieldExpr, NegatedField)
6- //! 3. Validate structural constraints (field on node type, child type for field)
3+ //! Two-phase approach:
4+ //! 1. Resolve all symbols (node types and fields) against grammar
5+ //! 2. Validate structural constraints (field on node type, child type for field)
76
87use std:: collections:: HashMap ;
98
@@ -84,14 +83,13 @@ impl<'a, 'q> Linker<'a, 'q> {
8483 }
8584
8685 fn link ( & mut self , root : & ast:: Root ) {
87- self . resolve_node_types ( root) ;
88- self . resolve_fields ( root) ;
86+ self . resolve_symbols ( root) ;
8987 self . validate_structure ( root) ;
9088 }
9189
92- fn resolve_node_types ( & mut self , root : & ast:: Root ) {
93- let mut collector = NodeTypeCollector { linker : self } ;
94- collector . visit ( root) ;
90+ fn resolve_symbols ( & mut self , root : & ast:: Root ) {
91+ let mut resolver = SymbolResolver { linker : self } ;
92+ resolver . visit ( root) ;
9593 }
9694
9795 fn resolve_named_node ( & mut self , node : & NamedNode ) {
@@ -139,11 +137,6 @@ impl<'a, 'q> Linker<'a, 'q> {
139137 }
140138 }
141139
142- fn resolve_fields ( & mut self , root : & ast:: Root ) {
143- let mut collector = FieldCollector { linker : self } ;
144- collector. visit ( root) ;
145- }
146-
147140 fn resolve_field_by_token ( & mut self , name_token : Option < SyntaxToken > ) {
148141 let Some ( name_token) = name_token else {
149142 return ;
@@ -403,17 +396,23 @@ struct ValidationContext {
403396 parent_range : TextRange ,
404397}
405398
406- struct NodeTypeCollector < ' l , ' a , ' q > {
399+ /// Combined symbol resolver for node types and fields.
400+ struct SymbolResolver < ' l , ' a , ' q > {
407401 linker : & ' l mut Linker < ' a , ' q > ,
408402}
409403
410- impl Visitor for NodeTypeCollector < ' _ , ' _ , ' _ > {
404+ impl Visitor for SymbolResolver < ' _ , ' _ , ' _ > {
411405 fn visit ( & mut self , root : & ast:: Root ) {
412406 walk ( self , root) ;
413407 }
414408
415409 fn visit_named_node ( & mut self , node : & ast:: NamedNode ) {
416410 self . linker . resolve_named_node ( node) ;
411+
412+ for neg in node. as_cst ( ) . children ( ) . filter_map ( ast:: NegatedField :: cast) {
413+ self . linker . resolve_field_by_token ( neg. name ( ) ) ;
414+ }
415+
417416 super :: visitor:: walk_named_node ( self , node) ;
418417 }
419418
@@ -433,47 +432,26 @@ impl Visitor for NodeTypeCollector<'_, '_, '_> {
433432 self . linker
434433 . node_type_ids
435434 . insert ( token_src ( & value_token, self . linker . source ( ) ) , resolved) ;
435+
436436 if let Some ( id) = resolved {
437437 let sym = self . linker . interner . intern ( value) ;
438438 self . linker . output . node_type_ids . entry ( sym) . or_insert ( id) ;
439+ return ;
439440 }
440441
441- if resolved. is_none ( ) {
442- self . linker
443- . diagnostics
444- . report (
445- self . linker . source_id ,
446- DiagnosticKind :: UnknownNodeType ,
447- value_token. text_range ( ) ,
448- )
449- . message ( value)
450- . emit ( ) ;
451- }
452- }
453- }
454-
455- struct FieldCollector < ' l , ' a , ' q > {
456- linker : & ' l mut Linker < ' a , ' q > ,
457- }
458-
459- impl Visitor for FieldCollector < ' _ , ' _ , ' _ > {
460- fn visit ( & mut self , root : & ast:: Root ) {
461- walk ( self , root) ;
462- }
463-
464- fn visit_named_node ( & mut self , node : & ast:: NamedNode ) {
465- for child in node. as_cst ( ) . children ( ) {
466- if let Some ( neg) = ast:: NegatedField :: cast ( child) {
467- self . linker . resolve_field_by_token ( neg. name ( ) ) ;
468- }
469- }
470-
471- super :: visitor:: walk_named_node ( self , node) ;
442+ self . linker
443+ . diagnostics
444+ . report (
445+ self . linker . source_id ,
446+ DiagnosticKind :: UnknownNodeType ,
447+ value_token. text_range ( ) ,
448+ )
449+ . message ( value)
450+ . emit ( ) ;
472451 }
473452
474453 fn visit_field_expr ( & mut self , field : & ast:: FieldExpr ) {
475454 self . linker . resolve_field_by_token ( field. name ( ) ) ;
476-
477455 super :: visitor:: walk_field_expr ( self , field) ;
478456 }
479457}
0 commit comments