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 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
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user