Partial implementation of anonymous labels
This commit is contained in:
+14
-11
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user