Partial implementation of anonymous labels

This commit is contained in:
2025-06-17 02:07:45 -07:00
parent 73ca64e4e9
commit b5c817d64d
2 changed files with 83 additions and 13 deletions
+14 -11
View File
@@ -8,8 +8,11 @@ use crate::{peg::ParseState, world::Stat};
pub type ParsedStat = Vec<Chunk>;
pub enum Chunk {
Verbatim(String),
Label(LabelName),
Reference(LabelName),
Label {
is_ref: bool,
is_anon: bool,
name: LabelName,
},
}
#[derive(Clone, Debug, Default)]
@@ -44,22 +47,22 @@ pub fn parse_stat_labels(stat: &Stat) -> ParsedStat {
// Convert #Labels into (span, chunk) pairs
let span_chunks = label_captures.iter().map(|(tag, cap)| {
let mut name = LabelName::default();
let mut is_anon = false;
for child in cap.children() {
match child.kind() {
Tag::Namespace => {
name.namespace = Some(child.text().into());
}
Tag::Global => {
Tag::Namespace => name.namespace = Some(child.text().into()),
Tag::Anon | Tag::Global => {
name.name = child.text().into();
is_anon = child.kind() == Tag::Anon;
}
Tag::Local => name.local = Some(child.text().into()),
_ => unimplemented!(),
_ => unreachable!(),
}
}
let chunk = match tag {
Tag::Label => Chunk::Label(name),
Tag::Reference => Chunk::Reference(name),
_ => unimplemented!(),
let chunk = Chunk::Label {
is_ref: *tag == Tag::Reference,
is_anon,
name,
};
(cap.span(), chunk)
});
+69 -2
View File
@@ -19,7 +19,11 @@ pub fn process_labels(board: &mut Board) {
for chunk in stat.iter_mut() {
match chunk {
Chunk::Verbatim(_) => {}
Chunk::Label(name) | Chunk::Reference(name) => {
Chunk::Label {
name,
is_ref: _,
is_anon: _,
} => {
let sanitized = registry.sanitize(name);
*chunk = Chunk::Verbatim(sanitized.into());
}
@@ -27,15 +31,78 @@ pub fn process_labels(board: &mut Board) {
}
}
anonymous_forward_pass(&mut stats, &mut registry);
anonymous_backward_pass(&mut stats);
// Join chunks together and replace old stats' code
for (old_stat, parsed_stat) in board.stats.iter_mut().zip(stats.into_iter()) {
let new_code = parsed_stat
.into_iter()
.map(|chunk| match chunk {
Chunk::Verbatim(s) => s,
_ => unreachable!(),
_ => unimplemented!(),
})
.collect();
old_stat.code = new_code;
}
}
fn anonymous_forward_pass(stats: &mut [ParsedStat], registry: &mut Registry) {
let mut label_names = vec![];
for stat in stats.iter_mut() {
let mut i = 0;
for chunk in stat.iter_mut() {
match chunk {
Chunk::Label {
is_ref: false,
is_anon: true,
name,
} => {
if i == label_names.len() {
label_names.push(registry.gen_anonymous());
}
name.name = label_names[i].clone();
i += 1;
}
Chunk::Label {
is_ref: true,
is_anon: true,
name,
} => {
if name.name == "@b" {
// TODO: a more explicit check that a "before" label exists
name.name = label_names[i - 1].clone();
}
}
_ => {}
}
}
}
}
fn anonymous_backward_pass(stats: &mut [ParsedStat]) {
for stat in stats.iter_mut() {
let mut last_name = None;
for chunk in stat.iter_mut().rev() {
match chunk {
Chunk::Label {
is_ref: false,
is_anon: true,
name,
} => {
last_name = Some(name.name.clone());
}
Chunk::Label {
is_ref: true,
is_anon: true,
name,
} => {
if name.name == "@f" {
name.name = last_name.clone().unwrap();
}
}
_ => {}
}
}
}
}