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::World;
/// The maxmium stack nesting depth.
const MAX_DEPTH: usize = 64;
/// Holds all data needed during compilation.
pub struct Engine<'a> {
/// The compilation environment.
@ -69,26 +66,28 @@ pub struct Route<'a> {
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> {
/// Create a new, empty route.
pub fn root() -> Self {
Self { id: None, outer: None, len: 0, upper: Cell::new(0) }
}
/// Insert a new id into the route.
///
/// 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.
/// Extend the route with another segment with a default length of 1.
pub fn extend(outer: Tracked<'a, Self>) -> Self {
Route {
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.
///
/// In comparison to [`Track::track`], this method skips this chain link
@ -118,11 +127,6 @@ impl<'a> Route<'a> {
pub fn decrease(&mut self) {
self.len -= 1;
}
/// Check whether the nesting depth exceeds the limit.
pub fn exceeding(&self) -> bool {
!self.within(MAX_DEPTH)
}
}
#[comemo::track]

View File

@ -28,7 +28,7 @@ impl Eval for ast::FuncCall<'_> {
let args = self.args();
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");
}

View File

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

View File

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

View File

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

View File

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

View File

@ -182,7 +182,7 @@ impl LayoutRoot for Content {
let mut engine = Engine {
world,
introspector,
route: Route::extend(route),
route: Route::extend(route).unnested(),
locator: &mut locator,
tracer,
};
@ -237,7 +237,7 @@ impl Layout for Content {
tracer,
};
if engine.route.exceeding() {
if !engine.route.within(Route::MAX_LAYOUT_DEPTH) {
bail!(
content.span(), "maximum layout depth exceeded";
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 crate::diag::{bail, SourceResult};
use crate::engine::Engine;
use crate::engine::{Engine, Route};
use crate::foundations::{
Content, Finalize, Guard, NativeElement, Recipe, Selector, Show, StyleChain,
StyleVecBuilder, Styles, Synthesize,
@ -307,7 +307,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
if let Some(realized) = realize(self.engine, content, styles)? {
self.engine.route.increase();
if self.engine.route.exceeding() {
if !self.engine.route.within(Route::MAX_SHOW_RULE_DEPTH) {
bail!(
content.span(), "maximum show rule depth exceeded";
hint: "check whether the show rule matches its own output";

View File

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