@@ -524,10 +524,15 @@ impl Ast {
524524 self . schema . register_field ( name)
525525 }
526526
527- fn union_source_range_of_children (
528- & self ,
529- fields : & BTreeMap < FieldId , Vec < Id > > ,
530- ) -> Option < Range > {
527+ /// Register every kind and field name from `schema` into this AST's schema
528+ /// (idempotent). Used before desugaring an externally-built AST so that
529+ /// rules can build output nodes whose kind/field names come from the
530+ /// desugarer's output schema.
531+ pub fn register_names_from_schema ( & mut self , schema : & schema:: Schema ) {
532+ self . schema . register_names_from ( schema) ;
533+ }
534+
535+ fn union_source_range_of_children ( & self , fields : & BTreeMap < FieldId , Vec < Id > > ) -> Option < Range > {
531536 let mut start_byte: Option < usize > = None ;
532537 let mut end_byte: Option < usize > = None ;
533538 let mut start_point = Point { row : 0 , column : 0 } ;
@@ -1448,6 +1453,18 @@ impl<'a, C: Clone + Default> Runner<'a, C> {
14481453 let mut user_ctx = C :: default ( ) ;
14491454 self . run_with_ctx ( input, & mut user_ctx)
14501455 }
1456+
1457+ /// Run all phases over an already-built `ast`, using the default context
1458+ /// (`C::default()`). Unlike [`run_from_tree`](Self::run_from_tree), the AST
1459+ /// is supplied by the caller (e.g. built from an external parser's output)
1460+ /// rather than constructed from a tree-sitter tree. The caller is
1461+ /// responsible for ensuring the AST's schema knows any output kind/field
1462+ /// names the rules will build (see [`Ast::register_names_from_schema`]).
1463+ pub fn run_from_ast ( & self , mut ast : Ast ) -> Result < Ast , String > {
1464+ let mut user_ctx = C :: default ( ) ;
1465+ self . run_phases ( & mut ast, & mut user_ctx) ?;
1466+ Ok ( ast)
1467+ }
14511468}
14521469
14531470// ---------------------------------------------------------------------------
@@ -1470,6 +1487,12 @@ pub trait Desugarer: Send + Sync {
14701487 /// Parse `tree` against `source` and run the desugaring pipeline.
14711488 /// Each call constructs a fresh default user context internally.
14721489 fn run_from_tree ( & self , tree : & tree_sitter:: Tree , source : & [ u8 ] ) -> Result < Ast , String > ;
1490+
1491+ /// Run the desugaring pipeline over an already-built `ast` (e.g. produced
1492+ /// by an external parser rather than tree-sitter). The desugarer ensures
1493+ /// the AST's schema knows its output kind/field names before running the
1494+ /// rules. Each call constructs a fresh default user context internally.
1495+ fn run_from_ast ( & self , ast : Ast ) -> Result < Ast , String > ;
14731496}
14741497
14751498/// A concrete [`Desugarer`] backed by a [`DesugaringConfig<C>`] for a
@@ -1507,4 +1530,12 @@ impl<C: Default + Clone + Send + Sync + 'static> Desugarer for ConcreteDesugarer
15071530 let runner = Runner :: with_schema ( self . language . clone ( ) , & self . schema , & self . config . phases ) ;
15081531 runner. run_from_tree ( tree, source)
15091532 }
1533+
1534+ fn run_from_ast ( & self , mut ast : Ast ) -> Result < Ast , String > {
1535+ // The AST was built against its own (external) schema; make sure the
1536+ // output kind/field names the rules build are resolvable in it.
1537+ ast. register_names_from_schema ( & self . schema ) ;
1538+ let runner = Runner :: with_schema ( self . language . clone ( ) , & self . schema , & self . config . phases ) ;
1539+ runner. run_from_ast ( ast)
1540+ }
15101541}
0 commit comments