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 type ParsedStat = Vec<Chunk>;
pub enum Chunk { pub enum Chunk {
Verbatim(String), Verbatim(String),
Label(LabelName), Label {
Reference(LabelName), is_ref: bool,
is_anon: bool,
name: LabelName,
},
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
@@ -44,22 +47,22 @@ pub fn parse_stat_labels(stat: &Stat) -> ParsedStat {
// Convert #Labels into (span, chunk) pairs // Convert #Labels into (span, chunk) pairs
let span_chunks = label_captures.iter().map(|(tag, cap)| { let span_chunks = label_captures.iter().map(|(tag, cap)| {
let mut name = LabelName::default(); let mut name = LabelName::default();
let mut is_anon = false;
for child in cap.children() { for child in cap.children() {
match child.kind() { match child.kind() {
Tag::Namespace => { Tag::Namespace => name.namespace = Some(child.text().into()),
name.namespace = Some(child.text().into()); Tag::Anon | Tag::Global => {
}
Tag::Global => {
name.name = child.text().into(); name.name = child.text().into();
is_anon = child.kind() == Tag::Anon;
} }
Tag::Local => name.local = Some(child.text().into()), Tag::Local => name.local = Some(child.text().into()),
_ => unimplemented!(), _ => unreachable!(),
} }
} }
let chunk = match tag { let chunk = Chunk::Label {
Tag::Label => Chunk::Label(name), is_ref: *tag == Tag::Reference,
Tag::Reference => Chunk::Reference(name), is_anon,
_ => unimplemented!(), name,
}; };
(cap.span(), chunk) (cap.span(), chunk)
}); });
+69 -2
View File
@@ -19,7 +19,11 @@ pub fn process_labels(board: &mut Board) {
for chunk in stat.iter_mut() { for chunk in stat.iter_mut() {
match chunk { match chunk {
Chunk::Verbatim(_) => {} Chunk::Verbatim(_) => {}
Chunk::Label(name) | Chunk::Reference(name) => { Chunk::Label {
name,
is_ref: _,
is_anon: _,
} => {
let sanitized = registry.sanitize(name); let sanitized = registry.sanitize(name);
*chunk = Chunk::Verbatim(sanitized.into()); *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 // Join chunks together and replace old stats' code
for (old_stat, parsed_stat) in board.stats.iter_mut().zip(stats.into_iter()) { for (old_stat, parsed_stat) in board.stats.iter_mut().zip(stats.into_iter()) {
let new_code = parsed_stat let new_code = parsed_stat
.into_iter() .into_iter()
.map(|chunk| match chunk { .map(|chunk| match chunk {
Chunk::Verbatim(s) => s, Chunk::Verbatim(s) => s,
_ => unreachable!(), _ => unimplemented!(),
}) })
.collect(); .collect();
old_stat.code = new_code; 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();
}
}
_ => {}
}
}
}
}