mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
A little less route nesting
This commit is contained in:
parent
b9d025de83
commit
aa23198ad9
@ -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]
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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";
|
||||
|
@ -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")
|
||||
|
||||
---
|
||||
|
Loading…
x
Reference in New Issue
Block a user