Add errors for broken anonymous label references

This commit is contained in:
2025-07-04 16:32:59 -07:00
parent a86c4f9e4a
commit 2b35fe30e9
4 changed files with 25 additions and 10 deletions
+2
View File
@@ -1,3 +1,5 @@
pub mod parse; pub mod parse;
pub mod process; pub mod process;
pub mod sanitize; pub mod sanitize;
pub use process::process_labels;
+2
View File
@@ -22,6 +22,7 @@ pub struct LabelName {
pub namespace: Option<CompactString>, pub namespace: Option<CompactString>,
pub name: CompactString, pub name: CompactString,
pub local: Option<CompactString>, pub local: Option<CompactString>,
pub span: Range<usize>,
} }
pub fn parse_stat_labels(stat: &Stat, ctx: &Context) -> ParsedStat { pub fn parse_stat_labels(stat: &Stat, ctx: &Context) -> ParsedStat {
@@ -59,6 +60,7 @@ pub fn parse_stat_labels(stat: &Stat, ctx: &Context) -> 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();
name.span = cap.span();
let mut is_anon = false; let mut is_anon = false;
for child in cap.children() { for child in cap.children() {
match child.kind() { match child.kind() {
+20 -9
View File
@@ -22,8 +22,8 @@ pub fn process_labels(board: &mut Board, ctx: &Context) {
assign_named_labels(&mut stats, &mut registry); assign_named_labels(&mut stats, &mut registry);
// Assign names to anonymous labels // Assign names to anonymous labels
anonymous_forward_pass(&mut stats, &mut registry); anonymous_forward_pass(&mut stats, &mut registry, ctx);
anonymous_backward_pass(&mut stats); anonymous_backward_pass(&mut stats, ctx);
// 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()) {
@@ -124,11 +124,11 @@ fn assign_named_labels(stats: &mut [ParsedStat], registry: &mut Registry) {
/// Simultaneously: /// Simultaneously:
/// 1. Assign names to anonymous labels. /// 1. Assign names to anonymous labels.
/// 2. Resolve anonymous backward references to their label names. /// 2. Resolve anonymous backward references to their label names.
fn anonymous_forward_pass(stats: &mut [ParsedStat], registry: &mut Registry) { fn anonymous_forward_pass(stats: &mut [ParsedStat], registry: &mut Registry, ctx: &Context) {
// Save generated label names so they can be reused across multiple objects // Save generated label names so they can be reused across multiple objects
let mut label_names = vec![]; let mut label_names = vec![];
for stat in stats.iter_mut() { for (stat_index, stat) in stats.iter_mut().enumerate() {
// Helper: Get the next label name that hasn't been used in this object yet // Helper: Get the next label name that hasn't been used in this object yet
let mut i = 0; let mut i = 0;
let mut get_next_name = || -> CompactString { let mut get_next_name = || -> CompactString {
@@ -144,6 +144,7 @@ fn anonymous_forward_pass(stats: &mut [ParsedStat], registry: &mut Registry) {
let mut namespace_to_latest: FxHashMap<Option<CompactString>, CompactString> = let mut namespace_to_latest: FxHashMap<Option<CompactString>, CompactString> =
FxHashMap::default(); FxHashMap::default();
let ctx = ctx.with_stat(stat_index);
for chunk in stat.iter_mut() { for chunk in stat.iter_mut() {
match chunk { match chunk {
Chunk::Label { Chunk::Label {
@@ -161,8 +162,12 @@ fn anonymous_forward_pass(stats: &mut [ParsedStat], registry: &mut Registry) {
name, name,
} => { } => {
if name.name == "@b" { if name.name == "@b" {
// TODO: a more explicit check that a "before" label exists if let Some(backward) = namespace_to_latest.get(&name.namespace) {
name.name = namespace_to_latest.get(&name.namespace).unwrap().clone(); name.name = backward.clone();
} else {
ctx.with_span(name.span.clone())
.error("backward reference @b without prior anonymous label :@");
}
} }
} }
_ => {} _ => {}
@@ -172,9 +177,10 @@ fn anonymous_forward_pass(stats: &mut [ParsedStat], registry: &mut Registry) {
} }
/// Resolve anonymous forward references to their label names. /// Resolve anonymous forward references to their label names.
fn anonymous_backward_pass(stats: &mut [ParsedStat]) { fn anonymous_backward_pass(stats: &mut [ParsedStat], ctx: &Context) {
for stat in stats.iter_mut() { for (stat_index, stat) in stats.iter_mut().enumerate() {
let mut namespace_to_latest = FxHashMap::default(); let mut namespace_to_latest = FxHashMap::default();
let ctx = ctx.with_stat(stat_index);
for chunk in stat.iter_mut().rev() { for chunk in stat.iter_mut().rev() {
match chunk { match chunk {
Chunk::Label { Chunk::Label {
@@ -190,7 +196,12 @@ fn anonymous_backward_pass(stats: &mut [ParsedStat]) {
name, name,
} => { } => {
if name.name == "@f" { if name.name == "@f" {
name.name = namespace_to_latest.get(&name.namespace).unwrap().clone(); if let Some(forward) = namespace_to_latest.get(&name.namespace) {
name.name = forward.clone();
} else {
ctx.with_span(name.span.clone())
.error("forward reference @f without following anonymous label :@");
}
} }
} }
_ => {} _ => {}
+1 -1
View File
@@ -7,7 +7,7 @@ mod world;
use anyhow::anyhow; use anyhow::anyhow;
use error::Context as ErrContext; use error::Context as ErrContext;
use labels::process::process_labels; use labels::process_labels;
use preprocess::eval::Context; use preprocess::eval::Context;
use std::{env, error::Error, fs, path::PathBuf, process::exit}; use std::{env, error::Error, fs, path::PathBuf, process::exit};
use world::World; use world::World;