A little less route nesting

This commit is contained in:
Laurenz 2023-11-29 12:57:26 +01:00
parent b9d025de83
commit aa23198ad9
9 changed files with 37 additions and 33 deletions

View File

@ -8,9 +8,6 @@ use crate::introspection::{Introspector, Locator};
use crate::syntax::FileId; use crate::syntax::FileId;
use crate::World; use crate::World;
/// The maxmium stack nesting depth.
const MAX_DEPTH: usize = 64;
/// Holds all data needed during compilation. /// Holds all data needed during compilation.
pub struct Engine<'a> { pub struct Engine<'a> {
/// The compilation environment. /// The compilation environment.
@ -69,26 +66,28 @@ pub struct Route<'a> {
upper: Cell<usize>, upper: Cell<usize>,
} }
/// The maximum nesting depths. They are different so that even if show rule and
/// call checks are interleaved, show rule problems we always get the show rule.
/// The lower the max depth for a kind of error, the higher its precedence
/// compared to the others.
impl Route<'_> {
/// The maximum stack nesting depth.
pub const MAX_SHOW_RULE_DEPTH: usize = 64;
/// The maxmium layout nesting depth.
pub const MAX_LAYOUT_DEPTH: usize = 72;
/// The maxmium function call nesting depth.
pub const MAX_CALL_DEPTH: usize = 80;
}
impl<'a> Route<'a> { impl<'a> Route<'a> {
/// Create a new, empty route. /// Create a new, empty route.
pub fn root() -> Self { pub fn root() -> Self {
Self { id: None, outer: None, len: 0, upper: Cell::new(0) } Self { id: None, outer: None, len: 0, upper: Cell::new(0) }
} }
/// Insert a new id into the route. /// Extend the route with another segment with a default length of 1.
///
/// You must guarantee that `outer` lives longer than the resulting
/// route is ever used.
pub fn insert(outer: Tracked<'a, Self>, id: FileId) -> Self {
Route {
outer: Some(outer),
id: Some(id),
len: 0,
upper: Cell::new(usize::MAX),
}
}
/// Extend the route without another id.
pub fn extend(outer: Tracked<'a, Self>) -> Self { pub fn extend(outer: Tracked<'a, Self>) -> Self {
Route { Route {
outer: Some(outer), outer: Some(outer),
@ -98,6 +97,16 @@ impl<'a> Route<'a> {
} }
} }
/// Attach a file id to the route segment.
pub fn with_id(self, id: FileId) -> Self {
Self { id: Some(id), ..self }
}
/// Set the length of the route segment to zero.
pub fn unnested(self) -> Self {
Self { len: 0, ..self }
}
/// Start tracking this route. /// Start tracking this route.
/// ///
/// In comparison to [`Track::track`], this method skips this chain link /// In comparison to [`Track::track`], this method skips this chain link
@ -118,11 +127,6 @@ impl<'a> Route<'a> {
pub fn decrease(&mut self) { pub fn decrease(&mut self) {
self.len -= 1; self.len -= 1;
} }
/// Check whether the nesting depth exceeds the limit.
pub fn exceeding(&self) -> bool {
!self.within(MAX_DEPTH)
}
} }
#[comemo::track] #[comemo::track]

View File

@ -28,7 +28,7 @@ impl Eval for ast::FuncCall<'_> {
let args = self.args(); let args = self.args();
let trailing_comma = args.trailing_comma(); let trailing_comma = args.trailing_comma();
if vm.engine.route.exceeding() { if !vm.engine.route.within(Route::MAX_CALL_DEPTH) {
bail!(span, "maximum function call depth exceeded"); bail!(span, "maximum function call depth exceeded");
} }

View File

@ -53,7 +53,7 @@ pub fn eval(
let introspector = Introspector::default(); let introspector = Introspector::default();
let engine = Engine { let engine = Engine {
world, world,
route: Route::insert(route, id), route: Route::extend(route).with_id(id),
introspector: introspector.track(), introspector: introspector.track(),
locator: &mut locator, locator: &mut locator,
tracer, tracer,

View File

@ -277,7 +277,7 @@ impl Counter {
let mut engine = Engine { let mut engine = Engine {
world, world,
introspector, introspector,
route: Route::extend(route), route: Route::extend(route).unnested(),
locator: &mut locator, locator: &mut locator,
tracer, tracer,
}; };

View File

@ -228,7 +228,7 @@ impl State {
let mut engine = Engine { let mut engine = Engine {
world, world,
introspector, introspector,
route: Route::extend(route), route: Route::extend(route).unnested(),
locator: &mut locator, locator: &mut locator,
tracer, tracer,
}; };

View File

@ -28,7 +28,7 @@ use crate::text::{
use crate::util::Numeric; use crate::util::Numeric;
use crate::World; use crate::World;
/// Layout's content inline. /// Layouts content inline.
pub(crate) fn layout_inline( pub(crate) fn layout_inline(
children: &[Prehashed<Content>], children: &[Prehashed<Content>],
engine: &mut Engine, engine: &mut Engine,

View File

@ -182,7 +182,7 @@ impl LayoutRoot for Content {
let mut engine = Engine { let mut engine = Engine {
world, world,
introspector, introspector,
route: Route::extend(route), route: Route::extend(route).unnested(),
locator: &mut locator, locator: &mut locator,
tracer, tracer,
}; };
@ -237,7 +237,7 @@ impl Layout for Content {
tracer, tracer,
}; };
if engine.route.exceeding() { if !engine.route.within(Route::MAX_LAYOUT_DEPTH) {
bail!( bail!(
content.span(), "maximum layout depth exceeded"; content.span(), "maximum layout depth exceeded";
hint: "try to reduce the amount of nesting in your layout", hint: "try to reduce the amount of nesting in your layout",

View File

@ -11,7 +11,7 @@ use smallvec::smallvec;
use typed_arena::Arena; use typed_arena::Arena;
use crate::diag::{bail, SourceResult}; use crate::diag::{bail, SourceResult};
use crate::engine::Engine; use crate::engine::{Engine, Route};
use crate::foundations::{ use crate::foundations::{
Content, Finalize, Guard, NativeElement, Recipe, Selector, Show, StyleChain, Content, Finalize, Guard, NativeElement, Recipe, Selector, Show, StyleChain,
StyleVecBuilder, Styles, Synthesize, StyleVecBuilder, Styles, Synthesize,
@ -307,7 +307,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
if let Some(realized) = realize(self.engine, content, styles)? { if let Some(realized) = realize(self.engine, content, styles)? {
self.engine.route.increase(); self.engine.route.increase();
if self.engine.route.exceeding() { if !self.engine.route.within(Route::MAX_SHOW_RULE_DEPTH) {
bail!( bail!(
content.span(), "maximum show rule depth exceeded"; content.span(), "maximum show rule depth exceeded";
hint: "check whether the show rule matches its own output"; hint: "check whether the show rule matches its own output";

View File

@ -44,8 +44,8 @@
--- ---
// Test cyclic imports during layout. // Test cyclic imports during layout.
// Error: 2-38 maximum layout depth exceeded // Error: 14-37 maximum layout depth exceeded
// Hint: 2-38 try to reduce the amount of nesting in your layout // Hint: 14-37 try to reduce the amount of nesting in your layout
#layout(_ => include "recursion.typ") #layout(_ => include "recursion.typ")
--- ---