Refactor parse_stat_labels()
This commit is contained in:
+44
-45
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user