Refactor parse_stat_labels()

This commit is contained in:
2025-06-15 13:11:16 -07:00
parent 68938b5e00
commit 0b2fc58fae
2 changed files with 45 additions and 47 deletions
+44 -45
View File
@@ -3,10 +3,7 @@ use std::ops::Range;
use compact_str::CompactString; use compact_str::CompactString;
use grammar::Tag; use grammar::Tag;
use crate::{ use crate::{peg::ParseState, world::Stat};
peg::{Capture, ParseState},
world::Stat,
};
pub type ParsedStat = Vec<Chunk>; pub type ParsedStat = Vec<Chunk>;
pub enum Chunk { pub enum Chunk {
@@ -15,7 +12,7 @@ pub enum Chunk {
Reference(LabelName), Reference(LabelName),
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug, Default)]
pub struct LabelName { pub struct LabelName {
pub namespace: Option<CompactString>, pub namespace: Option<CompactString>,
pub name: CompactString, pub name: CompactString,
@@ -31,53 +28,55 @@ pub fn parse_stat_labels(stat: &Stat) -> ParsedStat {
code code
); );
// Split code along capture group boundaries // Find all #Label captures and record which ones were references
let mut result = vec![]; let mut label_captures = vec![];
let mut offset = 0;
let mut push_label = |cap: Capture<_>| {
let Range { start, end } = cap.span();
if offset < start {
result.push(Chunk::Verbatim(code[offset..start].into()))
}
let mut label = LabelName {
namespace: None,
name: CompactString::with_capacity(0),
local: None,
};
for child in cap.children() {
match child.kind() {
Tag::Namespace => {
label.namespace = Some(child.text().into());
}
Tag::Global => {
label.name = child.text().into();
}
Tag::Local => label.local = Some(child.text().into()),
_ => unimplemented!(),
}
}
result.push(Chunk::Label(label));
offset = end;
};
for cap in parser.captures() { for cap in parser.captures() {
match cap.kind() { match cap.kind() {
Tag::Label => { Tag::Label => label_captures.push((Tag::Label, cap)),
push_label(cap);
}
Tag::Reference => { Tag::Reference => {
for child in cap.children() { let label = cap.children().find(|c| c.kind() == Tag::Label).unwrap();
if child.kind() == Tag::Label { label_captures.push((Tag::Reference, label));
push_label(child);
}
}
} }
_ => {} _ => {}
} }
} }
if offset < code.len() {
result.push(Chunk::Verbatim(code[offset..code.len()].into())); // Convert #Labels into (span, chunk) pairs
let span_chunks = label_captures.iter().map(|(tag, cap)| {
let mut name = LabelName::default();
for child in cap.children() {
match child.kind() {
Tag::Namespace => {
name.namespace = Some(child.text().into());
}
Tag::Global => {
name.name = child.text().into();
}
Tag::Local => name.local = Some(child.text().into()),
_ => unimplemented!(),
}
}
let chunk = match tag {
Tag::Label => Chunk::Label(name),
Tag::Reference => Chunk::Reference(name),
_ => unimplemented!(),
};
(cap.span(), chunk)
});
// Split code along #Label boundaries
let mut last_index = 0;
let mut result = vec![];
for (span, chunk) in span_chunks {
let Range { start, end } = span;
if last_index < span.start {
result.push(Chunk::Verbatim(code[last_index..start].into()));
}
result.push(chunk);
last_index = end;
}
if last_index < code.len() {
result.push(Chunk::Verbatim(code[last_index..code.len()].into()));
} }
result result
} }
+1 -2
View File
@@ -181,11 +181,10 @@ fn increment(s: &mut CompactString) {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use core::num;
use std::collections::HashSet; use std::collections::HashSet;
use compact_str::CompactString; use compact_str::CompactString;
use insta::{assert_debug_snapshot, assert_snapshot}; use insta::assert_snapshot;
use crate::labels::{parse::LabelName, sanitize::Registry}; use crate::labels::{parse::LabelName, sanitize::Registry};