Move rust_tree_types contents into template

This commit is contained in:
Josh Holtrop 2026-08-11 23:46:48 -04:00
parent 89f1f84857
commit bceaad5b7e
2 changed files with 78 additions and 74 deletions

View File

@ -109,7 +109,84 @@ pub fn <%= @grammar.prefix %>value_get<%= suffix %>(pvalue: &<%= @grammar.prefix
/** Tree node ID type (index into the context node arena). ID 0 is null. */ /** Tree node ID type (index into the context node arena). ID 0 is null. */
pub type <%= @grammar.prefix %>node_id_t = u32; pub type <%= @grammar.prefix %>node_id_t = u32;
<%= rust_tree_types %> /**
* Tree node record.
*
* All tree nodes are stored contiguously in the context node arena. Child
* links are stored in a shared children array: a node's children
* occupy children[child_offset .. child_offset + n_fields]. Token payload
* fields (token, pvalue, and any user fields) are only meaningful when
* is_token is true.
*/
#[derive(Clone, Default)]
pub struct <%= @grammar.prefix %>node_data_t {
pub position: <%= @grammar.prefix %>position_t,
pub end_position: <%= @grammar.prefix %>position_t,
pub child_offset: <%= @grammar.prefix %>node_id_t,
pub n_fields: u16,
pub is_token: bool,
pub token: <%= @grammar.prefix %>token_t,
pub pvalue: <%= @grammar.prefix %>value_t,
<% unless @grammar.token_user_fields.to_s.strip.empty? %>
<%= @grammar.token_user_fields %>
<% end %>
}
/** Tree node handle types. */
/** Token tree node handle. */
#[derive(Clone, Copy)]
pub struct <%= h_type("Token") %><'a> { context: &'a <%= @grammar.prefix %>context_t, id: <%= @grammar.prefix %>node_id_t }
impl<'a> <%= h_type("Token") %><'a> {
/** Return whether this handle refers to a valid (non-null) node. */
pub fn valid(&self) -> bool { self.id != 0 }
/** Return the node ID (for identity comparison). */
pub fn node_id(&self) -> <%= @grammar.prefix %>node_id_t { self.id }
/** Access the underlying node record (token, pvalue, and user fields). */
pub fn data(&self) -> &'a <%= @grammar.prefix %>node_data_t { &self.context.<%= @grammar.prefix %>tree_nodes[self.id as usize] }
/** Text position of the first code point spanned by this node. */
pub fn position(&self) -> <%= @grammar.prefix %>position_t { self.context.<%= @grammar.prefix %>tree_nodes[self.id as usize].position }
/** Text position of the last code point spanned by this node. */
pub fn end_position(&self) -> <%= @grammar.prefix %>position_t { self.context.<%= @grammar.prefix %>tree_nodes[self.id as usize].end_position }
/** Number of child fields in this node. */
pub fn n_fields(&self) -> u16 { if self.id != 0 { self.context.<%= @grammar.prefix %>tree_nodes[self.id as usize].n_fields } else { 0 } }
/** Token ID for this token node. */
pub fn token(&self) -> <%= @grammar.prefix %>token_t { self.context.<%= @grammar.prefix %>tree_nodes[self.id as usize].token }
/** Parser value associated with this token node. */
pub fn pvalue(&self) -> <%= @grammar.prefix %>value_t { self.context.<%= @grammar.prefix %>tree_nodes[self.id as usize].pvalue.clone() }
}
<% tree_node_rule_sets.each do |rule_set| %>
/** <%= rule_set.name %> tree node handle. */
#[derive(Clone, Copy)]
pub struct <%= h_type(rule_set.name) %><'a> { context: &'a <%= @grammar.prefix %>context_t, id: <%= @grammar.prefix %>node_id_t }
impl<'a> <%= h_type(rule_set.name) %><'a> {
/** Return whether this handle refers to a valid (non-null) node. */
pub fn valid(&self) -> bool { self.id != 0 }
/** Return the node ID (for identity comparison). */
pub fn node_id(&self) -> <%= @grammar.prefix %>node_id_t { self.id }
/** Access the underlying node record. */
pub fn data(&self) -> &'a <%= @grammar.prefix %>node_data_t { &self.context.<%= @grammar.prefix %>tree_nodes[self.id as usize] }
/** Text position of the first code point spanned by this node. */
pub fn position(&self) -> <%= @grammar.prefix %>position_t { self.context.<%= @grammar.prefix %>tree_nodes[self.id as usize].position }
/** Text position of the last code point spanned by this node. */
pub fn end_position(&self) -> <%= @grammar.prefix %>position_t { self.context.<%= @grammar.prefix %>tree_nodes[self.id as usize].end_position }
/** Number of child fields in this node. */
pub fn n_fields(&self) -> u16 { if self.id != 0 { self.context.<%= @grammar.prefix %>tree_nodes[self.id as usize].n_fields } else { 0 } }
<% each_tree_field(rule_set) do |rt, field_name, child_type, slot| %>
/** Access the <%= field_name %> child node. */
pub fn <%= rust_ident(field_name) %>(&self) -> <%= child_type %><'a> {
if self.id == 0 {
return <%= child_type %> { context: self.context, id: 0 };
}
<%= child_type %> { context: self.context, id: self.context.<%= @grammar.prefix %>tree_children[self.context.<%= @grammar.prefix %>tree_nodes[self.id as usize].child_offset as usize + <%= slot %>] }
}
<% end %>
}
<% end %>
<% end %> <% end %>
/** Lexed token information. */ /** Lexed token information. */

View File

@ -755,79 +755,6 @@ class Propane
typestring == "void *" ? "()" : typestring typestring == "void *" ? "()" : typestring
end end
# Generate the Rust tree node record and handle types.
#
# Mirrors the C tree node record plus the C++ handle structs: each rule set
# and the Token node get a handle type ({context, id}) with accessor methods.
#
# @return [String]
# Rust tree node type definitions.
def rust_tree_types
p = @grammar.prefix
out = []
out << "/** Tree node record. */"
out << "#[derive(Clone, Default)]"
out << "pub struct #{p}node_data_t {"
out << " pub position: #{p}position_t,"
out << " pub end_position: #{p}position_t,"
out << " pub child_offset: #{p}node_id_t,"
out << " pub n_fields: u16,"
out << " pub is_token: bool,"
out << " pub token: #{p}token_t,"
out << " pub pvalue: #{p}value_t,"
unless @grammar.token_user_fields.to_s.strip.empty?
out << @grammar.token_user_fields
end
out << "}"
out << ""
out << "/** Tree node handle types. */"
tree_handle_types.each do |t|
out << "#[derive(Clone, Copy)]"
out << "pub struct #{t}<'a> { context: &'a #{p}context_t, id: #{p}node_id_t }"
end
out << ""
# Common accessors for every handle type.
tree_handle_types.each do |t|
out << "impl<'a> #{t}<'a> {"
out << " /** Return whether this handle refers to a valid (non-null) node. */"
out << " pub fn valid(&self) -> bool { self.id != 0 }"
out << " /** Return the node ID (for identity comparison). */"
out << " pub fn node_id(&self) -> #{p}node_id_t { self.id }"
out << " /** Access the underlying node record. */"
out << " pub fn data(&self) -> &'a #{p}node_data_t { &self.context.#{p}tree_nodes[self.id as usize] }"
out << " /** Text position of the first code point spanned by this node. */"
out << " pub fn position(&self) -> #{p}position_t { self.context.#{p}tree_nodes[self.id as usize].position }"
out << " /** Text position of the last code point spanned by this node. */"
out << " pub fn end_position(&self) -> #{p}position_t { self.context.#{p}tree_nodes[self.id as usize].end_position }"
out << " /** Number of child fields in this node. */"
out << " pub fn n_fields(&self) -> u16 { if self.id != 0 { self.context.#{p}tree_nodes[self.id as usize].n_fields } else { 0 } }"
if t == h_type("Token")
out << " /** Token ID for this token node. */"
out << " pub fn token(&self) -> #{p}token_t { self.context.#{p}tree_nodes[self.id as usize].token }"
out << " /** Parser value associated with this token node. */"
out << " pub fn pvalue(&self) -> #{p}value_t { self.context.#{p}tree_nodes[self.id as usize].pvalue.clone() }"
end
out << "}"
end
out << ""
# Navigation accessors for rule set handles.
tree_node_rule_sets.each do |rule_set|
rtype = h_type(rule_set.name)
out << "impl<'a> #{rtype}<'a> {"
each_tree_field(rule_set) do |rt, field_name, child_type, slot|
out << " /** Access the #{field_name} child node. */"
out << " pub fn #{rust_ident(field_name)}(&self) -> #{child_type}<'a> {"
out << " if self.id == 0 {"
out << " return #{child_type} { context: self.context, id: 0 };"
out << " }"
out << " #{child_type} { context: self.context, id: self.context.#{p}tree_children[self.context.#{p}tree_nodes[self.id as usize].child_offset as usize + #{slot}] }"
out << " }"
end
out << "}"
end
out.join("\n")
end
# Get the lex function to use. # Get the lex function to use.
# #
# @return [String] # @return [String]