From b3b559eb1d60b1fba5fe8cb411db81a202f49fa6 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 7 Sep 2026 11:05:56 +0200 Subject: [PATCH] Yeast: Keep AST iteration order as in ast_types.yml. --- shared/yeast-schema/src/schema.rs | 13 ++++++++- shared/yeast/src/lib.rs | 44 ++++++++++++++++++++++--------- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/shared/yeast-schema/src/schema.rs b/shared/yeast-schema/src/schema.rs index 0675d8913422..6f5d3fe7d0a1 100644 --- a/shared/yeast-schema/src/schema.rs +++ b/shared/yeast-schema/src/schema.rs @@ -47,7 +47,7 @@ pub struct Schema { /// Per-node-kind declared field order (named fields only), as written in /// the source node-types YAML. Field ids are not a stable ordering key /// across front-ends, so this preserves the authored order for - /// presentation (see the AST dump). + /// presentation (see the AST dump) and tree traversal during extraction. field_order: BTreeMap>, } @@ -193,6 +193,17 @@ impl Schema { for name in other.field_ids.keys() { self.register_field(name); } + for (kind, order) in &other.field_order { + let order = order + .iter() + .filter_map(|&field_id| { + other + .field_name_for_id(field_id) + .map(|name| self.register_field(name)) + }) + .collect(); + self.set_field_order(kind, order); + } } /// Track a name for a kind ID without registering it as named or diff --git a/shared/yeast/src/lib.rs b/shared/yeast/src/lib.rs index 94f75faa4763..32e6889ee5a2 100644 --- a/shared/yeast/src/lib.rs +++ b/shared/yeast/src/lib.rs @@ -323,7 +323,7 @@ impl<'a> AstCursor<'a> { fn goto_first_child_opt(&mut self) -> Option<()> { let parent_id = self.node_id; let parent = self.ast.get_node(parent_id)?; - let mut children = ChildrenIter::new(parent); + let mut children = ChildrenIter::new(self.ast, parent); let first_child = children.next()?; self.node_id = first_child; self.parents.push((parent_id, children)); @@ -340,15 +340,35 @@ impl<'a> AstCursor<'a> { #[derive(Debug)] struct ChildrenIter<'a> { current_field: Option, - fields: std::collections::btree_map::Iter<'a, FieldId, Vec>, + fields: &'a BTreeMap>, + field_order: std::vec::IntoIter, field_children: Option>, } impl<'a> ChildrenIter<'a> { - fn new(node: &'a Node) -> Self { + fn new(ast: &'a Ast, node: &'a Node) -> Self { + let fields = &node.fields; + let present: Vec = fields.keys().copied().collect(); + let field_order = match ast.schema.field_order(node.kind_name()) { + Some(order) => { + let mut fields: Vec = order + .iter() + .copied() + .filter(|field| fields.contains_key(field)) + .collect(); + for field in present { + if !fields.contains(&field) { + fields.push(field); + } + } + fields.into_iter() + } + None => present.into_iter(), + }; Self { current_field: None, - fields: node.fields.iter(), + fields, + field_order, field_children: None, } } @@ -363,20 +383,20 @@ impl Iterator for ChildrenIter<'_> { fn next(&mut self) -> Option { match self.field_children.as_mut() { - None => match self.fields.next() { - Some((field, children)) => { - self.current_field = Some(*field); - self.field_children = Some(children.iter()); + None => match self.field_order.next() { + Some(field) => { + self.current_field = Some(field); + self.field_children = Some(self.fields[&field].iter()); self.next() } None => None, }, Some(children) => match children.next() { - None => match self.fields.next() { + None => match self.field_order.next() { None => None, - Some((field, children)) => { - self.current_field = Some(*field); - self.field_children = Some(children.iter()); + Some(field) => { + self.current_field = Some(field); + self.field_children = Some(self.fields[&field].iter()); self.next() } },