mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Refactor depth checks and apply them in math (#4845)
This commit is contained in:
parent
4365e18454
commit
92f2c7b470
@ -7,7 +7,7 @@ use comemo::{Track, Tracked, TrackedMut, Validate};
|
||||
use ecow::EcoVec;
|
||||
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
|
||||
|
||||
use crate::diag::{SourceDiagnostic, SourceResult};
|
||||
use crate::diag::{bail, HintedStrResult, SourceDiagnostic, SourceResult, StrResult};
|
||||
use crate::foundations::{Styles, Value};
|
||||
use crate::introspection::Introspector;
|
||||
use crate::syntax::{FileId, Span};
|
||||
@ -229,21 +229,6 @@ pub struct Route<'a> {
|
||||
upper: AtomicUsize,
|
||||
}
|
||||
|
||||
/// 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 maximum layout nesting depth.
|
||||
pub const MAX_LAYOUT_DEPTH: usize = 72;
|
||||
|
||||
/// The maximum function call nesting depth.
|
||||
pub const MAX_CALL_DEPTH: usize = 80;
|
||||
}
|
||||
|
||||
impl<'a> Route<'a> {
|
||||
/// Create a new, empty route.
|
||||
pub fn root() -> Self {
|
||||
@ -297,6 +282,51 @@ impl<'a> Route<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The maximum nesting depths. They are different so that even if show rule and
|
||||
/// call checks are interleaved, for show rule problems we always get the show
|
||||
/// rule error. 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.
|
||||
const MAX_SHOW_RULE_DEPTH: usize = 64;
|
||||
|
||||
/// The maximum layout nesting depth.
|
||||
const MAX_LAYOUT_DEPTH: usize = 72;
|
||||
|
||||
/// The maximum function call nesting depth.
|
||||
const MAX_CALL_DEPTH: usize = 80;
|
||||
|
||||
/// Ensures that we are within the maximum show rule depth.
|
||||
pub fn check_show_depth(&self) -> HintedStrResult<()> {
|
||||
if !self.within(Route::MAX_SHOW_RULE_DEPTH) {
|
||||
bail!(
|
||||
"maximum show rule depth exceeded";
|
||||
hint: "check whether the show rule matches its own output"
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Ensures that we are within the maximum layout depth.
|
||||
pub fn check_layout_depth(&self) -> HintedStrResult<()> {
|
||||
if !self.within(Route::MAX_LAYOUT_DEPTH) {
|
||||
bail!(
|
||||
"maximum layout depth exceeded";
|
||||
hint: "try to reduce the amount of nesting in your layout",
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Ensures that we are within the maximum function call depth.
|
||||
pub fn check_call_depth(&self) -> StrResult<()> {
|
||||
if !self.within(Route::MAX_CALL_DEPTH) {
|
||||
bail!("maximum function call depth exceeded");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[comemo::track]
|
||||
impl<'a> Route<'a> {
|
||||
/// Whether the given id is part of the route.
|
||||
|
@ -30,9 +30,7 @@ impl Eval for ast::FuncCall<'_> {
|
||||
let args = self.args();
|
||||
let trailing_comma = args.trailing_comma();
|
||||
|
||||
if !vm.engine.route.within(Route::MAX_CALL_DEPTH) {
|
||||
bail!(span, "maximum function call depth exceeded");
|
||||
}
|
||||
vm.engine.route.check_call_depth().at(span)?;
|
||||
|
||||
// Try to evaluate as a call to an associated function or field.
|
||||
let (callee, args) = if let ast::Expr::FieldAccess(access) = callee {
|
||||
|
@ -7,7 +7,7 @@ use std::num::NonZeroUsize;
|
||||
|
||||
use comemo::{Track, Tracked, TrackedMut};
|
||||
|
||||
use crate::diag::{bail, SourceResult};
|
||||
use crate::diag::{bail, At, SourceResult};
|
||||
use crate::engine::{Engine, Route, Sink, Traced};
|
||||
use crate::foundations::{
|
||||
Content, NativeElement, Packed, Resolve, Smart, StyleChain, Styles,
|
||||
@ -724,12 +724,7 @@ fn layout_fragment_impl(
|
||||
route: Route::extend(route),
|
||||
};
|
||||
|
||||
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",
|
||||
);
|
||||
}
|
||||
engine.route.check_layout_depth().at(content.span())?;
|
||||
|
||||
// If we are in a `PageElem`, this might already be a realized flow.
|
||||
let arenas = Arenas::default();
|
||||
|
@ -42,7 +42,7 @@ use self::fragment::*;
|
||||
use self::row::*;
|
||||
use self::spacing::*;
|
||||
|
||||
use crate::diag::SourceResult;
|
||||
use crate::diag::{At, SourceResult};
|
||||
use crate::foundations::{
|
||||
category, Category, Content, Module, Resolve, Scope, SequenceElem, StyleChain,
|
||||
StyledElem,
|
||||
@ -239,6 +239,9 @@ impl LayoutMath for Content {
|
||||
if let Some((tag, realized)) =
|
||||
process(ctx.engine, &mut ctx.locator, self, styles)?
|
||||
{
|
||||
ctx.engine.route.increase();
|
||||
ctx.engine.route.check_show_depth().at(self.span())?;
|
||||
|
||||
if let Some(tag) = &tag {
|
||||
ctx.push(MathFragment::Tag(tag.clone()));
|
||||
}
|
||||
@ -246,6 +249,8 @@ impl LayoutMath for Content {
|
||||
if let Some(tag) = tag {
|
||||
ctx.push(MathFragment::Tag(tag.with_kind(TagKind::End)));
|
||||
}
|
||||
|
||||
ctx.engine.route.decrease();
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,8 @@ pub use self::process::process;
|
||||
|
||||
use std::mem;
|
||||
|
||||
use crate::diag::{bail, SourceResult};
|
||||
use crate::engine::{Engine, Route};
|
||||
use crate::diag::{bail, At, SourceResult};
|
||||
use crate::engine::Engine;
|
||||
use crate::foundations::{
|
||||
Content, ContextElem, NativeElement, Packed, SequenceElem, Smart, StyleChain,
|
||||
StyleVec, StyledElem, Styles,
|
||||
@ -139,12 +139,7 @@ impl<'a, 'v> Builder<'a, 'v> {
|
||||
process(self.engine, self.locator, content, styles)?
|
||||
{
|
||||
self.engine.route.increase();
|
||||
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"
|
||||
);
|
||||
}
|
||||
self.engine.route.check_show_depth().at(content.span())?;
|
||||
|
||||
if let Some(tag) = &tag {
|
||||
self.accept(self.arenas.store(TagElem::packed(tag.clone())), styles)?;
|
||||
|
@ -53,3 +53,9 @@
|
||||
// Hint: 22-25 check whether the show rule matches its own output
|
||||
#show math.equation: $x$
|
||||
$ x $
|
||||
|
||||
--- recursion-show-math-realize ---
|
||||
// Error: 22-33 maximum show rule depth exceeded
|
||||
// Hint: 22-33 check whether the show rule matches its own output
|
||||
#show heading: it => heading[it]
|
||||
$ #heading[hi] $
|
||||
|
Loading…
x
Reference in New Issue
Block a user