Add errors for broken anonymous label references
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user