mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Remove Tracer
(#4365)
This commit is contained in:
parent
f91cad7d78
commit
a68a241570
@ -8,8 +8,7 @@ use codespan_reporting::term;
|
|||||||
use ecow::{eco_format, eco_vec, EcoString, EcoVec};
|
use ecow::{eco_format, eco_vec, EcoString, EcoVec};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
||||||
use typst::diag::{bail, FileError, Severity, SourceDiagnostic, StrResult};
|
use typst::diag::{bail, FileError, Severity, SourceDiagnostic, StrResult, Warned};
|
||||||
use typst::eval::Tracer;
|
|
||||||
use typst::foundations::{Datetime, Smart};
|
use typst::foundations::{Datetime, Smart};
|
||||||
use typst::layout::{Frame, PageRanges};
|
use typst::layout::{Frame, PageRanges};
|
||||||
use typst::model::Document;
|
use typst::model::Document;
|
||||||
@ -112,11 +111,9 @@ pub fn compile_once(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut tracer = Tracer::new();
|
let Warned { output, warnings } = typst::compile(world);
|
||||||
let result = typst::compile(world, &mut tracer);
|
|
||||||
let warnings = tracer.warnings();
|
|
||||||
|
|
||||||
match result {
|
match output {
|
||||||
// Export the PDF / PNG.
|
// Export the PDF / PNG.
|
||||||
Ok(document) => {
|
Ok(document) => {
|
||||||
export(world, &document, command, watching)?;
|
export(world, &document, command, watching)?;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use comemo::Track;
|
use comemo::Track;
|
||||||
use ecow::{eco_format, EcoString};
|
use ecow::{eco_format, EcoString};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use typst::diag::{bail, HintedStrResult, StrResult};
|
use typst::diag::{bail, HintedStrResult, StrResult, Warned};
|
||||||
use typst::eval::{eval_string, EvalMode, Tracer};
|
use typst::eval::{eval_string, EvalMode};
|
||||||
use typst::foundations::{Content, IntoValue, LocatableSelector, Scope};
|
use typst::foundations::{Content, IntoValue, LocatableSelector, Scope};
|
||||||
use typst::model::Document;
|
use typst::model::Document;
|
||||||
use typst::syntax::Span;
|
use typst::syntax::Span;
|
||||||
@ -21,11 +21,9 @@ pub fn query(command: &QueryCommand) -> HintedStrResult<()> {
|
|||||||
world.reset();
|
world.reset();
|
||||||
world.source(world.main()).map_err(|err| err.to_string())?;
|
world.source(world.main()).map_err(|err| err.to_string())?;
|
||||||
|
|
||||||
let mut tracer = Tracer::new();
|
let Warned { output, warnings } = typst::compile(&world);
|
||||||
let result = typst::compile(&world, &mut tracer);
|
|
||||||
let warnings = tracer.warnings();
|
|
||||||
|
|
||||||
match result {
|
match output {
|
||||||
// Retrieve and print query results.
|
// Retrieve and print query results.
|
||||||
Ok(document) => {
|
Ok(document) => {
|
||||||
let data = retrieve(&world, command, &document)?;
|
let data = retrieve(&world, command, &document)?;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use comemo::Track;
|
use comemo::Track;
|
||||||
use ecow::{eco_vec, EcoString, EcoVec};
|
use ecow::{eco_vec, EcoString, EcoVec};
|
||||||
use typst::engine::{Engine, Route};
|
use typst::engine::{Engine, Route, Sink, Traced};
|
||||||
use typst::eval::{Tracer, Vm};
|
use typst::eval::Vm;
|
||||||
use typst::foundations::{Context, Label, Scopes, Styles, Value};
|
use typst::foundations::{Context, Label, Scopes, Styles, Value};
|
||||||
use typst::introspection::Introspector;
|
use typst::introspection::Introspector;
|
||||||
use typst::model::{BibliographyElem, Document};
|
use typst::model::{BibliographyElem, Document};
|
||||||
@ -38,10 +38,7 @@ pub fn analyze_expr(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut tracer = Tracer::new();
|
return typst::trace(world, node.span());
|
||||||
tracer.inspect(node.span());
|
|
||||||
typst::compile(world, &mut tracer).ok();
|
|
||||||
return tracer.values();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -59,12 +56,14 @@ pub fn analyze_import(world: &dyn World, source: &LinkedNode) -> Option<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let introspector = Introspector::default();
|
let introspector = Introspector::default();
|
||||||
let mut tracer = Tracer::new();
|
let traced = Traced::default();
|
||||||
|
let mut sink = Sink::new();
|
||||||
let engine = Engine {
|
let engine = Engine {
|
||||||
world: world.track(),
|
world: world.track(),
|
||||||
route: Route::default(),
|
|
||||||
introspector: introspector.track(),
|
introspector: introspector.track(),
|
||||||
tracer: tracer.track_mut(),
|
traced: traced.track(),
|
||||||
|
sink: sink.track_mut(),
|
||||||
|
route: Route::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let context = Context::none();
|
let context = Context::none();
|
||||||
|
@ -1406,7 +1406,6 @@ impl<'a> CompletionContext<'a> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use typst::eval::Tracer;
|
|
||||||
|
|
||||||
use super::autocomplete;
|
use super::autocomplete;
|
||||||
use crate::tests::TestWorld;
|
use crate::tests::TestWorld;
|
||||||
@ -1414,7 +1413,7 @@ mod tests {
|
|||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn test(text: &str, cursor: usize, contains: &[&str], excludes: &[&str]) {
|
fn test(text: &str, cursor: usize, contains: &[&str], excludes: &[&str]) {
|
||||||
let world = TestWorld::new(text);
|
let world = TestWorld::new(text);
|
||||||
let doc = typst::compile(&world, &mut Tracer::new()).ok();
|
let doc = typst::compile(&world).output.ok();
|
||||||
let (_, completions) =
|
let (_, completions) =
|
||||||
autocomplete(&world, doc.as_ref(), &world.main, cursor, true)
|
autocomplete(&world, doc.as_ref(), &world.main, cursor, true)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
@ -170,7 +170,6 @@ fn is_in_rect(pos: Point, size: Size, click: Point) -> bool {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
|
||||||
use typst::eval::Tracer;
|
|
||||||
use typst::layout::{Abs, Point, Position};
|
use typst::layout::{Abs, Point, Position};
|
||||||
|
|
||||||
use super::{jump_from_click, jump_from_cursor, Jump};
|
use super::{jump_from_click, jump_from_cursor, Jump};
|
||||||
@ -200,14 +199,14 @@ mod tests {
|
|||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn test_click(text: &str, click: Point, expected: Option<Jump>) {
|
fn test_click(text: &str, click: Point, expected: Option<Jump>) {
|
||||||
let world = TestWorld::new(text);
|
let world = TestWorld::new(text);
|
||||||
let doc = typst::compile(&world, &mut Tracer::new()).unwrap();
|
let doc = typst::compile(&world).output.unwrap();
|
||||||
assert_eq!(jump_from_click(&world, &doc, &doc.pages[0].frame, click), expected);
|
assert_eq!(jump_from_click(&world, &doc, &doc.pages[0].frame, click), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn test_cursor(text: &str, cursor: usize, expected: Option<Position>) {
|
fn test_cursor(text: &str, cursor: usize, expected: Option<Position>) {
|
||||||
let world = TestWorld::new(text);
|
let world = TestWorld::new(text);
|
||||||
let doc = typst::compile(&world, &mut Tracer::new()).unwrap();
|
let doc = typst::compile(&world).output.unwrap();
|
||||||
let pos = jump_from_cursor(&doc, &world.main, cursor);
|
let pos = jump_from_cursor(&doc, &world.main, cursor);
|
||||||
assert_eq!(pos.is_some(), expected.is_some());
|
assert_eq!(pos.is_some(), expected.is_some());
|
||||||
if let (Some(pos), Some(expected)) = (pos, expected) {
|
if let (Some(pos), Some(expected)) = (pos, expected) {
|
||||||
|
@ -2,7 +2,8 @@ use std::fmt::Write;
|
|||||||
|
|
||||||
use ecow::{eco_format, EcoString};
|
use ecow::{eco_format, EcoString};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use typst::eval::{CapturesVisitor, Tracer};
|
use typst::engine::Sink;
|
||||||
|
use typst::eval::CapturesVisitor;
|
||||||
use typst::foundations::{repr, Capturer, CastInfo, Repr, Value};
|
use typst::foundations::{repr, Capturer, CastInfo, Repr, Value};
|
||||||
use typst::layout::Length;
|
use typst::layout::Length;
|
||||||
use typst::model::Document;
|
use typst::model::Document;
|
||||||
@ -79,7 +80,7 @@ fn expr_tooltip(world: &dyn World, leaf: &LinkedNode) -> Option<Tooltip> {
|
|||||||
let mut last = None;
|
let mut last = None;
|
||||||
let mut pieces: Vec<EcoString> = vec![];
|
let mut pieces: Vec<EcoString> = vec![];
|
||||||
let mut iter = values.iter();
|
let mut iter = values.iter();
|
||||||
for (value, _) in (&mut iter).take(Tracer::MAX_VALUES - 1) {
|
for (value, _) in (&mut iter).take(Sink::MAX_VALUES - 1) {
|
||||||
if let Some((prev, count)) = &mut last {
|
if let Some((prev, count)) = &mut last {
|
||||||
if *prev == value {
|
if *prev == value {
|
||||||
*count += 1;
|
*count += 1;
|
||||||
@ -253,7 +254,6 @@ fn font_tooltip(world: &dyn World, leaf: &LinkedNode) -> Option<Tooltip> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use typst::eval::Tracer;
|
|
||||||
use typst::syntax::Side;
|
use typst::syntax::Side;
|
||||||
|
|
||||||
use super::{tooltip, Tooltip};
|
use super::{tooltip, Tooltip};
|
||||||
@ -270,7 +270,7 @@ mod tests {
|
|||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn test(text: &str, cursor: usize, side: Side, expected: Option<Tooltip>) {
|
fn test(text: &str, cursor: usize, side: Side, expected: Option<Tooltip>) {
|
||||||
let world = TestWorld::new(text);
|
let world = TestWorld::new(text);
|
||||||
let doc = typst::compile(&world, &mut Tracer::new()).ok();
|
let doc = typst::compile(&world).output.ok();
|
||||||
assert_eq!(tooltip(&world, doc.as_ref(), &world.main, cursor, side), expected);
|
assert_eq!(tooltip(&world, doc.as_ref(), &world.main, cursor, side), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,6 +138,15 @@ pub use {
|
|||||||
/// A result that can carry multiple source errors.
|
/// A result that can carry multiple source errors.
|
||||||
pub type SourceResult<T> = Result<T, EcoVec<SourceDiagnostic>>;
|
pub type SourceResult<T> = Result<T, EcoVec<SourceDiagnostic>>;
|
||||||
|
|
||||||
|
/// An output alongside warnings generated while producing it.
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
|
pub struct Warned<T> {
|
||||||
|
/// The produced output.
|
||||||
|
pub output: T,
|
||||||
|
/// Warnings generated while producing the output.
|
||||||
|
pub warnings: EcoVec<SourceDiagnostic>,
|
||||||
|
}
|
||||||
|
|
||||||
/// An error or warning in a source file.
|
/// An error or warning in a source file.
|
||||||
///
|
///
|
||||||
/// The contained spans will only be detached if any of the input source files
|
/// The contained spans will only be detached if any of the input source files
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
//! Definition of the central compilation context.
|
//! Definition of the central compilation context.
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
use comemo::{Track, Tracked, TrackedMut, Validate};
|
use comemo::{Track, Tracked, TrackedMut, Validate};
|
||||||
|
use ecow::EcoVec;
|
||||||
|
|
||||||
use crate::diag::SourceResult;
|
use crate::diag::{SourceDiagnostic, SourceResult};
|
||||||
use crate::eval::Tracer;
|
use crate::foundations::{Styles, Value};
|
||||||
use crate::introspection::Introspector;
|
use crate::introspection::Introspector;
|
||||||
use crate::syntax::FileId;
|
use crate::syntax::{FileId, Span};
|
||||||
use crate::World;
|
use crate::World;
|
||||||
|
|
||||||
/// Holds all data needed during compilation.
|
/// Holds all data needed during compilation.
|
||||||
@ -16,18 +18,20 @@ pub struct Engine<'a> {
|
|||||||
pub world: Tracked<'a, dyn World + 'a>,
|
pub world: Tracked<'a, dyn World + 'a>,
|
||||||
/// Provides access to information about the document.
|
/// Provides access to information about the document.
|
||||||
pub introspector: Tracked<'a, Introspector>,
|
pub introspector: Tracked<'a, Introspector>,
|
||||||
|
/// May hold a span that is currently under inspection.
|
||||||
|
pub traced: Tracked<'a, Traced>,
|
||||||
|
/// A pure sink for warnings, delayed errors, and spans under inspection.
|
||||||
|
pub sink: TrackedMut<'a, Sink>,
|
||||||
/// The route the engine took during compilation. This is used to detect
|
/// The route the engine took during compilation. This is used to detect
|
||||||
/// cyclic imports and excessive nesting.
|
/// cyclic imports and excessive nesting.
|
||||||
pub route: Route<'a>,
|
pub route: Route<'a>,
|
||||||
/// The tracer for inspection of the values an expression produces.
|
|
||||||
pub tracer: TrackedMut<'a, Tracer>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Engine<'_> {
|
impl Engine<'_> {
|
||||||
/// Performs a fallible operation that does not immediately terminate further
|
/// Performs a fallible operation that does not immediately terminate further
|
||||||
/// execution. Instead it produces a delayed error that is only promoted to
|
/// execution. Instead it produces a delayed error that is only promoted to
|
||||||
/// a fatal one if it remains at the end of the introspection loop.
|
/// a fatal one if it remains at the end of the introspection loop.
|
||||||
pub fn delayed<F, T>(&mut self, f: F) -> T
|
pub fn delay<F, T>(&mut self, f: F) -> T
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut Self) -> SourceResult<T>,
|
F: FnOnce(&mut Self) -> SourceResult<T>,
|
||||||
T: Default,
|
T: Default,
|
||||||
@ -35,13 +39,112 @@ impl Engine<'_> {
|
|||||||
match f(self) {
|
match f(self) {
|
||||||
Ok(value) => value,
|
Ok(value) => value,
|
||||||
Err(errors) => {
|
Err(errors) => {
|
||||||
self.tracer.delay(errors);
|
self.sink.delay(errors);
|
||||||
T::default()
|
T::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// May hold a span that is currently under inspection.
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Traced(Option<Span>);
|
||||||
|
|
||||||
|
impl Traced {
|
||||||
|
/// Wraps a to-be-traced `Span`.
|
||||||
|
///
|
||||||
|
/// Call `Traced::default()` to trace nothing.
|
||||||
|
pub fn new(traced: Span) -> Self {
|
||||||
|
Self(Some(traced))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[comemo::track]
|
||||||
|
impl Traced {
|
||||||
|
/// Returns the traced span _if_ it is part of the given source file or
|
||||||
|
/// `None` otherwise.
|
||||||
|
///
|
||||||
|
/// We hide the span if it isn't in the given file so that only results for
|
||||||
|
/// the file with the traced span are invalidated.
|
||||||
|
pub fn get(&self, id: FileId) -> Option<Span> {
|
||||||
|
if self.0.and_then(Span::id) == Some(id) {
|
||||||
|
self.0
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A push-only sink for delayed errors, warnings, and traced values.
|
||||||
|
///
|
||||||
|
/// All tracked methods of this type are of the form `(&mut self, ..) -> ()`, so
|
||||||
|
/// in principle they do not need validation (though that optimization is not
|
||||||
|
/// yet implemented in comemo).
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub struct Sink {
|
||||||
|
/// Delayed errors: Those are errors that we can ignore until the last
|
||||||
|
/// iteration. For instance, show rules may throw during earlier iterations
|
||||||
|
/// because the introspector is not yet ready. We first ignore that and
|
||||||
|
/// proceed with empty content and only if the error remains by the end
|
||||||
|
/// of the last iteration, we promote it.
|
||||||
|
delayed: EcoVec<SourceDiagnostic>,
|
||||||
|
/// Warnings emitted during iteration.
|
||||||
|
warnings: EcoVec<SourceDiagnostic>,
|
||||||
|
/// Hashes of all warning's spans and messages for warning deduplication.
|
||||||
|
warnings_set: HashSet<u128>,
|
||||||
|
/// A sequence of traced values for a span.
|
||||||
|
values: EcoVec<(Value, Option<Styles>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sink {
|
||||||
|
/// The maximum number of traced values.
|
||||||
|
pub const MAX_VALUES: usize = 10;
|
||||||
|
|
||||||
|
/// Create a new empty sink.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the stored delayed errors.
|
||||||
|
pub fn delayed(&mut self) -> EcoVec<SourceDiagnostic> {
|
||||||
|
std::mem::take(&mut self.delayed)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the stored warnings.
|
||||||
|
pub fn warnings(self) -> EcoVec<SourceDiagnostic> {
|
||||||
|
self.warnings
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the values for the traced span.
|
||||||
|
pub fn values(self) -> EcoVec<(Value, Option<Styles>)> {
|
||||||
|
self.values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[comemo::track]
|
||||||
|
impl Sink {
|
||||||
|
/// Push delayed errors.
|
||||||
|
pub fn delay(&mut self, errors: EcoVec<SourceDiagnostic>) {
|
||||||
|
self.delayed.extend(errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a warning.
|
||||||
|
pub fn warn(&mut self, warning: SourceDiagnostic) {
|
||||||
|
// Check if warning is a duplicate.
|
||||||
|
let hash = crate::utils::hash128(&(&warning.span, &warning.message));
|
||||||
|
if self.warnings_set.insert(hash) {
|
||||||
|
self.warnings.push(warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trace a value and optionally styles for the traced span.
|
||||||
|
pub fn value(&mut self, value: Value, styles: Option<Styles>) {
|
||||||
|
if self.values.len() < Self::MAX_VALUES {
|
||||||
|
self.values.push((value, styles));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The route the engine took during compilation. This is used to detect
|
/// The route the engine took during compilation. This is used to detect
|
||||||
/// cyclic imports and excessive nesting.
|
/// cyclic imports and excessive nesting.
|
||||||
pub struct Route<'a> {
|
pub struct Route<'a> {
|
||||||
|
@ -2,8 +2,8 @@ use comemo::{Tracked, TrackedMut};
|
|||||||
use ecow::{eco_format, EcoVec};
|
use ecow::{eco_format, EcoVec};
|
||||||
|
|
||||||
use crate::diag::{bail, error, At, HintedStrResult, SourceResult, Trace, Tracepoint};
|
use crate::diag::{bail, error, At, HintedStrResult, SourceResult, Trace, Tracepoint};
|
||||||
use crate::engine::Engine;
|
use crate::engine::{Engine, Sink, Traced};
|
||||||
use crate::eval::{Access, Eval, FlowEvent, Route, Tracer, Vm};
|
use crate::eval::{Access, Eval, FlowEvent, Route, Vm};
|
||||||
use crate::foundations::{
|
use crate::foundations::{
|
||||||
call_method_mut, is_mutating_method, Arg, Args, Bytes, Capturer, Closure, Content,
|
call_method_mut, is_mutating_method, Arg, Args, Bytes, Capturer, Closure, Content,
|
||||||
Context, Func, IntoValue, NativeElement, Scope, Scopes, Value,
|
Context, Func, IntoValue, NativeElement, Scope, Scopes, Value,
|
||||||
@ -275,8 +275,9 @@ pub(crate) fn call_closure(
|
|||||||
closure: &LazyHash<Closure>,
|
closure: &LazyHash<Closure>,
|
||||||
world: Tracked<dyn World + '_>,
|
world: Tracked<dyn World + '_>,
|
||||||
introspector: Tracked<Introspector>,
|
introspector: Tracked<Introspector>,
|
||||||
|
traced: Tracked<Traced>,
|
||||||
|
sink: TrackedMut<Sink>,
|
||||||
route: Tracked<Route>,
|
route: Tracked<Route>,
|
||||||
tracer: TrackedMut<Tracer>,
|
|
||||||
context: Tracked<Context>,
|
context: Tracked<Context>,
|
||||||
mut args: Args,
|
mut args: Args,
|
||||||
) -> SourceResult<Value> {
|
) -> SourceResult<Value> {
|
||||||
@ -294,8 +295,9 @@ pub(crate) fn call_closure(
|
|||||||
let engine = Engine {
|
let engine = Engine {
|
||||||
world,
|
world,
|
||||||
introspector,
|
introspector,
|
||||||
|
traced,
|
||||||
|
sink,
|
||||||
route: Route::extend(route),
|
route: Route::extend(route),
|
||||||
tracer,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Prepare VM.
|
// Prepare VM.
|
||||||
|
@ -35,7 +35,7 @@ impl Eval for ast::ModuleImport<'_> {
|
|||||||
if let ast::Expr::Ident(ident) = self.source() {
|
if let ast::Expr::Ident(ident) = self.source() {
|
||||||
if ident.as_str() == new_name.as_str() {
|
if ident.as_str() == new_name.as_str() {
|
||||||
// Warn on `import x as x`
|
// Warn on `import x as x`
|
||||||
vm.engine.tracer.warn(warning!(
|
vm.engine.sink.warn(warning!(
|
||||||
new_name.span(),
|
new_name.span(),
|
||||||
"unnecessary import rename to same name",
|
"unnecessary import rename to same name",
|
||||||
));
|
));
|
||||||
@ -110,7 +110,7 @@ impl Eval for ast::ModuleImport<'_> {
|
|||||||
if renamed_item.original_name().as_str()
|
if renamed_item.original_name().as_str()
|
||||||
== renamed_item.new_name().as_str()
|
== renamed_item.new_name().as_str()
|
||||||
{
|
{
|
||||||
vm.engine.tracer.warn(warning!(
|
vm.engine.sink.warn(warning!(
|
||||||
renamed_item.new_name().span(),
|
renamed_item.new_name().span(),
|
||||||
"unnecessary import rename to same name",
|
"unnecessary import rename to same name",
|
||||||
));
|
));
|
||||||
@ -185,8 +185,9 @@ fn import_package(vm: &mut Vm, spec: PackageSpec, span: Span) -> SourceResult<Mo
|
|||||||
let point = || Tracepoint::Import;
|
let point = || Tracepoint::Import;
|
||||||
Ok(eval(
|
Ok(eval(
|
||||||
vm.world(),
|
vm.world(),
|
||||||
|
vm.engine.traced,
|
||||||
|
TrackedMut::reborrow_mut(&mut vm.engine.sink),
|
||||||
vm.engine.route.track(),
|
vm.engine.route.track(),
|
||||||
TrackedMut::reborrow_mut(&mut vm.engine.tracer),
|
|
||||||
&source,
|
&source,
|
||||||
)
|
)
|
||||||
.trace(vm.world(), point, span)?
|
.trace(vm.world(), point, span)?
|
||||||
@ -209,8 +210,9 @@ fn import_file(vm: &mut Vm, path: &str, span: Span) -> SourceResult<Module> {
|
|||||||
let point = || Tracepoint::Import;
|
let point = || Tracepoint::Import;
|
||||||
eval(
|
eval(
|
||||||
world,
|
world,
|
||||||
|
vm.engine.traced,
|
||||||
|
TrackedMut::reborrow_mut(&mut vm.engine.sink),
|
||||||
vm.engine.route.track(),
|
vm.engine.route.track(),
|
||||||
TrackedMut::reborrow_mut(&mut vm.engine.tracer),
|
|
||||||
&source,
|
&source,
|
||||||
)
|
)
|
||||||
.trace(world, point, span)
|
.trace(world, point, span)
|
||||||
|
@ -134,7 +134,7 @@ impl Eval for ast::Strong<'_> {
|
|||||||
let body = self.body();
|
let body = self.body();
|
||||||
if body.exprs().next().is_none() {
|
if body.exprs().next().is_none() {
|
||||||
vm.engine
|
vm.engine
|
||||||
.tracer
|
.sink
|
||||||
.warn(warning!(
|
.warn(warning!(
|
||||||
self.span(), "no text within stars";
|
self.span(), "no text within stars";
|
||||||
hint: "using multiple consecutive stars (e.g. **) has no additional effect",
|
hint: "using multiple consecutive stars (e.g. **) has no additional effect",
|
||||||
@ -152,7 +152,7 @@ impl Eval for ast::Emph<'_> {
|
|||||||
let body = self.body();
|
let body = self.body();
|
||||||
if body.exprs().next().is_none() {
|
if body.exprs().next().is_none() {
|
||||||
vm.engine
|
vm.engine
|
||||||
.tracer
|
.sink
|
||||||
.warn(warning!(
|
.warn(warning!(
|
||||||
self.span(), "no text within underscores";
|
self.span(), "no text within underscores";
|
||||||
hint: "using multiple consecutive underscores (e.g. __) has no additional effect"
|
hint: "using multiple consecutive underscores (e.g. __) has no additional effect"
|
||||||
|
@ -11,12 +11,10 @@ mod import;
|
|||||||
mod markup;
|
mod markup;
|
||||||
mod math;
|
mod math;
|
||||||
mod rules;
|
mod rules;
|
||||||
mod tracer;
|
|
||||||
mod vm;
|
mod vm;
|
||||||
|
|
||||||
pub use self::call::*;
|
pub use self::call::*;
|
||||||
pub use self::import::*;
|
pub use self::import::*;
|
||||||
pub use self::tracer::*;
|
|
||||||
pub use self::vm::*;
|
pub use self::vm::*;
|
||||||
|
|
||||||
pub(crate) use self::access::*;
|
pub(crate) use self::access::*;
|
||||||
@ -26,7 +24,7 @@ pub(crate) use self::flow::*;
|
|||||||
use comemo::{Track, Tracked, TrackedMut};
|
use comemo::{Track, Tracked, TrackedMut};
|
||||||
|
|
||||||
use crate::diag::{bail, SourceResult};
|
use crate::diag::{bail, SourceResult};
|
||||||
use crate::engine::{Engine, Route};
|
use crate::engine::{Engine, Route, Sink, Traced};
|
||||||
use crate::foundations::{Cast, Context, Module, NativeElement, Scope, Scopes, Value};
|
use crate::foundations::{Cast, Context, Module, NativeElement, Scope, Scopes, Value};
|
||||||
use crate::introspection::Introspector;
|
use crate::introspection::Introspector;
|
||||||
use crate::math::EquationElem;
|
use crate::math::EquationElem;
|
||||||
@ -38,8 +36,9 @@ use crate::World;
|
|||||||
#[typst_macros::time(name = "eval", span = source.root().span())]
|
#[typst_macros::time(name = "eval", span = source.root().span())]
|
||||||
pub fn eval(
|
pub fn eval(
|
||||||
world: Tracked<dyn World + '_>,
|
world: Tracked<dyn World + '_>,
|
||||||
|
traced: Tracked<Traced>,
|
||||||
|
sink: TrackedMut<Sink>,
|
||||||
route: Tracked<Route>,
|
route: Tracked<Route>,
|
||||||
tracer: TrackedMut<Tracer>,
|
|
||||||
source: &Source,
|
source: &Source,
|
||||||
) -> SourceResult<Module> {
|
) -> SourceResult<Module> {
|
||||||
// Prevent cyclic evaluation.
|
// Prevent cyclic evaluation.
|
||||||
@ -52,9 +51,10 @@ pub fn eval(
|
|||||||
let introspector = Introspector::default();
|
let introspector = Introspector::default();
|
||||||
let engine = Engine {
|
let engine = Engine {
|
||||||
world,
|
world,
|
||||||
route: Route::extend(route).with_id(id),
|
|
||||||
introspector: introspector.track(),
|
introspector: introspector.track(),
|
||||||
tracer,
|
traced,
|
||||||
|
sink,
|
||||||
|
route: Route::extend(route).with_id(id),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Prepare VM.
|
// Prepare VM.
|
||||||
@ -115,13 +115,15 @@ pub fn eval_string(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Prepare the engine.
|
// Prepare the engine.
|
||||||
let mut tracer = Tracer::new();
|
let mut sink = Sink::new();
|
||||||
let introspector = Introspector::default();
|
let introspector = Introspector::default();
|
||||||
|
let traced = Traced::default();
|
||||||
let engine = Engine {
|
let engine = Engine {
|
||||||
world,
|
world,
|
||||||
introspector: introspector.track(),
|
introspector: introspector.track(),
|
||||||
|
traced: traced.track(),
|
||||||
|
sink: sink.track_mut(),
|
||||||
route: Route::default(),
|
route: Route::default(),
|
||||||
tracer: tracer.track_mut(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Prepare VM.
|
// Prepare VM.
|
||||||
|
@ -1,82 +0,0 @@
|
|||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use ecow::EcoVec;
|
|
||||||
|
|
||||||
use crate::diag::SourceDiagnostic;
|
|
||||||
use crate::foundations::{Styles, Value};
|
|
||||||
use crate::syntax::{FileId, Span};
|
|
||||||
use crate::utils::hash128;
|
|
||||||
|
|
||||||
/// Traces warnings and which values existed for an expression at a span.
|
|
||||||
#[derive(Default, Clone)]
|
|
||||||
pub struct Tracer {
|
|
||||||
inspected: Option<Span>,
|
|
||||||
warnings: EcoVec<SourceDiagnostic>,
|
|
||||||
warnings_set: HashSet<u128>,
|
|
||||||
delayed: EcoVec<SourceDiagnostic>,
|
|
||||||
values: EcoVec<(Value, Option<Styles>)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Tracer {
|
|
||||||
/// The maximum number of inspected values.
|
|
||||||
pub const MAX_VALUES: usize = 10;
|
|
||||||
|
|
||||||
/// Create a new tracer.
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the stored delayed errors.
|
|
||||||
pub fn delayed(&mut self) -> EcoVec<SourceDiagnostic> {
|
|
||||||
std::mem::take(&mut self.delayed)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the stored warnings.
|
|
||||||
pub fn warnings(self) -> EcoVec<SourceDiagnostic> {
|
|
||||||
self.warnings
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mark a span as inspected. All values observed for this span can be
|
|
||||||
/// retrieved via `values` later.
|
|
||||||
pub fn inspect(&mut self, span: Span) {
|
|
||||||
self.inspected = Some(span);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the values for the inspected span.
|
|
||||||
pub fn values(self) -> EcoVec<(Value, Option<Styles>)> {
|
|
||||||
self.values
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[comemo::track]
|
|
||||||
impl Tracer {
|
|
||||||
/// Push delayed errors.
|
|
||||||
pub fn delay(&mut self, errors: EcoVec<SourceDiagnostic>) {
|
|
||||||
self.delayed.extend(errors);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a warning.
|
|
||||||
pub fn warn(&mut self, warning: SourceDiagnostic) {
|
|
||||||
// Check if warning is a duplicate.
|
|
||||||
let hash = hash128(&(&warning.span, &warning.message));
|
|
||||||
if self.warnings_set.insert(hash) {
|
|
||||||
self.warnings.push(warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The inspected span if it is part of the given source file.
|
|
||||||
pub fn inspected(&self, id: FileId) -> Option<Span> {
|
|
||||||
if self.inspected.and_then(Span::id) == Some(id) {
|
|
||||||
self.inspected
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trace a value for the span.
|
|
||||||
pub fn value(&mut self, value: Value, styles: Option<Styles>) {
|
|
||||||
if self.values.len() < Self::MAX_VALUES {
|
|
||||||
self.values.push((value, styles));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -32,7 +32,7 @@ impl<'a> Vm<'a> {
|
|||||||
scopes: Scopes<'a>,
|
scopes: Scopes<'a>,
|
||||||
target: Span,
|
target: Span,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let inspected = target.id().and_then(|id| engine.tracer.inspected(id));
|
let inspected = target.id().and_then(|id| engine.traced.get(id));
|
||||||
Self { engine, context, flow: None, scopes, inspected }
|
Self { engine, context, flow: None, scopes, inspected }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ impl<'a> Vm<'a> {
|
|||||||
#[cold]
|
#[cold]
|
||||||
pub fn trace(&mut self, value: Value) {
|
pub fn trace(&mut self, value: Value) {
|
||||||
self.engine
|
self.engine
|
||||||
.tracer
|
.sink
|
||||||
.value(value.clone(), self.context.styles().ok().map(|s| s.to_map()));
|
.value(value.clone(), self.context.styles().ok().map(|s| s.to_map()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,8 +297,9 @@ impl Func {
|
|||||||
closure,
|
closure,
|
||||||
engine.world,
|
engine.world,
|
||||||
engine.introspector,
|
engine.introspector,
|
||||||
|
engine.traced,
|
||||||
|
TrackedMut::reborrow_mut(&mut engine.sink),
|
||||||
engine.route.track(),
|
engine.route.track(),
|
||||||
TrackedMut::reborrow_mut(&mut engine.tracer),
|
|
||||||
context,
|
context,
|
||||||
args,
|
args,
|
||||||
),
|
),
|
||||||
|
@ -6,8 +6,7 @@ use ecow::{eco_format, eco_vec, EcoString, EcoVec};
|
|||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
|
||||||
use crate::diag::{bail, At, HintedStrResult, SourceResult};
|
use crate::diag::{bail, At, HintedStrResult, SourceResult};
|
||||||
use crate::engine::{Engine, Route};
|
use crate::engine::{Engine, Route, Sink, Traced};
|
||||||
use crate::eval::Tracer;
|
|
||||||
use crate::foundations::{
|
use crate::foundations::{
|
||||||
cast, elem, func, scope, select_where, ty, Args, Array, Construct, Content, Context,
|
cast, elem, func, scope, select_where, ty, Args, Array, Construct, Content, Context,
|
||||||
Element, Func, IntoValue, Label, LocatableSelector, NativeElement, Packed, Repr,
|
Element, Func, IntoValue, Label, LocatableSelector, NativeElement, Packed, Repr,
|
||||||
@ -281,8 +280,9 @@ impl Counter {
|
|||||||
self.sequence_impl(
|
self.sequence_impl(
|
||||||
engine.world,
|
engine.world,
|
||||||
engine.introspector,
|
engine.introspector,
|
||||||
|
engine.traced,
|
||||||
|
TrackedMut::reborrow_mut(&mut engine.sink),
|
||||||
engine.route.track(),
|
engine.route.track(),
|
||||||
TrackedMut::reborrow_mut(&mut engine.tracer),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,14 +292,16 @@ impl Counter {
|
|||||||
&self,
|
&self,
|
||||||
world: Tracked<dyn World + '_>,
|
world: Tracked<dyn World + '_>,
|
||||||
introspector: Tracked<Introspector>,
|
introspector: Tracked<Introspector>,
|
||||||
|
traced: Tracked<Traced>,
|
||||||
|
sink: TrackedMut<Sink>,
|
||||||
route: Tracked<Route>,
|
route: Tracked<Route>,
|
||||||
tracer: TrackedMut<Tracer>,
|
|
||||||
) -> SourceResult<EcoVec<(CounterState, NonZeroUsize)>> {
|
) -> SourceResult<EcoVec<(CounterState, NonZeroUsize)>> {
|
||||||
let mut engine = Engine {
|
let mut engine = Engine {
|
||||||
world,
|
world,
|
||||||
introspector,
|
introspector,
|
||||||
|
traced,
|
||||||
|
sink,
|
||||||
route: Route::extend(route).unnested(),
|
route: Route::extend(route).unnested(),
|
||||||
tracer,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut state = CounterState::init(&self.0);
|
let mut state = CounterState::init(&self.0);
|
||||||
|
@ -2,8 +2,7 @@ use comemo::{Track, Tracked, TrackedMut};
|
|||||||
use ecow::{eco_format, eco_vec, EcoString, EcoVec};
|
use ecow::{eco_format, eco_vec, EcoString, EcoVec};
|
||||||
|
|
||||||
use crate::diag::{bail, At, SourceResult};
|
use crate::diag::{bail, At, SourceResult};
|
||||||
use crate::engine::{Engine, Route};
|
use crate::engine::{Engine, Route, Sink, Traced};
|
||||||
use crate::eval::Tracer;
|
|
||||||
use crate::foundations::{
|
use crate::foundations::{
|
||||||
cast, elem, func, scope, select_where, ty, Args, Construct, Content, Context, Func,
|
cast, elem, func, scope, select_where, ty, Args, Construct, Content, Context, Func,
|
||||||
LocatableSelector, NativeElement, Packed, Repr, Selector, Show, Str, StyleChain,
|
LocatableSelector, NativeElement, Packed, Repr, Selector, Show, Str, StyleChain,
|
||||||
@ -214,8 +213,9 @@ impl State {
|
|||||||
self.sequence_impl(
|
self.sequence_impl(
|
||||||
engine.world,
|
engine.world,
|
||||||
engine.introspector,
|
engine.introspector,
|
||||||
|
engine.traced,
|
||||||
|
TrackedMut::reborrow_mut(&mut engine.sink),
|
||||||
engine.route.track(),
|
engine.route.track(),
|
||||||
TrackedMut::reborrow_mut(&mut engine.tracer),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,14 +225,16 @@ impl State {
|
|||||||
&self,
|
&self,
|
||||||
world: Tracked<dyn World + '_>,
|
world: Tracked<dyn World + '_>,
|
||||||
introspector: Tracked<Introspector>,
|
introspector: Tracked<Introspector>,
|
||||||
|
traced: Tracked<Traced>,
|
||||||
|
sink: TrackedMut<Sink>,
|
||||||
route: Tracked<Route>,
|
route: Tracked<Route>,
|
||||||
tracer: TrackedMut<Tracer>,
|
|
||||||
) -> SourceResult<EcoVec<Value>> {
|
) -> SourceResult<EcoVec<Value>> {
|
||||||
let mut engine = Engine {
|
let mut engine = Engine {
|
||||||
world,
|
world,
|
||||||
introspector,
|
introspector,
|
||||||
|
traced,
|
||||||
|
sink,
|
||||||
route: Route::extend(route).unnested(),
|
route: Route::extend(route).unnested(),
|
||||||
tracer,
|
|
||||||
};
|
};
|
||||||
let mut state = self.init.clone();
|
let mut state = self.init.clone();
|
||||||
let mut stops = eco_vec![state.clone()];
|
let mut stops = eco_vec![state.clone()];
|
||||||
|
@ -11,8 +11,7 @@ use self::shaping::{
|
|||||||
END_PUNCT_PAT,
|
END_PUNCT_PAT,
|
||||||
};
|
};
|
||||||
use crate::diag::{bail, SourceResult};
|
use crate::diag::{bail, SourceResult};
|
||||||
use crate::engine::{Engine, Route};
|
use crate::engine::{Engine, Route, Sink, Traced};
|
||||||
use crate::eval::Tracer;
|
|
||||||
use crate::foundations::{Packed, Resolve, Smart, StyleChain};
|
use crate::foundations::{Packed, Resolve, Smart, StyleChain};
|
||||||
use crate::introspection::{Introspector, Locator, LocatorLink, Tag, TagElem};
|
use crate::introspection::{Introspector, Locator, LocatorLink, Tag, TagElem};
|
||||||
use crate::layout::{
|
use crate::layout::{
|
||||||
@ -45,8 +44,9 @@ pub(crate) fn layout_inline(
|
|||||||
children: &StyleVec,
|
children: &StyleVec,
|
||||||
world: Tracked<dyn World + '_>,
|
world: Tracked<dyn World + '_>,
|
||||||
introspector: Tracked<Introspector>,
|
introspector: Tracked<Introspector>,
|
||||||
|
traced: Tracked<Traced>,
|
||||||
|
sink: TrackedMut<Sink>,
|
||||||
route: Tracked<Route>,
|
route: Tracked<Route>,
|
||||||
tracer: TrackedMut<Tracer>,
|
|
||||||
locator: Tracked<Locator>,
|
locator: Tracked<Locator>,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
consecutive: bool,
|
consecutive: bool,
|
||||||
@ -58,8 +58,9 @@ pub(crate) fn layout_inline(
|
|||||||
let mut engine = Engine {
|
let mut engine = Engine {
|
||||||
world,
|
world,
|
||||||
introspector,
|
introspector,
|
||||||
|
traced,
|
||||||
|
sink,
|
||||||
route: Route::extend(route),
|
route: Route::extend(route),
|
||||||
tracer,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Collect all text into one string for BiDi analysis.
|
// Collect all text into one string for BiDi analysis.
|
||||||
@ -83,8 +84,9 @@ pub(crate) fn layout_inline(
|
|||||||
children,
|
children,
|
||||||
engine.world,
|
engine.world,
|
||||||
engine.introspector,
|
engine.introspector,
|
||||||
|
engine.traced,
|
||||||
|
TrackedMut::reborrow_mut(&mut engine.sink),
|
||||||
engine.route.track(),
|
engine.route.track(),
|
||||||
TrackedMut::reborrow_mut(&mut engine.tracer),
|
|
||||||
locator.track(),
|
locator.track(),
|
||||||
styles,
|
styles,
|
||||||
consecutive,
|
consecutive,
|
||||||
|
@ -72,8 +72,7 @@ pub(crate) use self::inline::*;
|
|||||||
use comemo::{Track, Tracked, TrackedMut};
|
use comemo::{Track, Tracked, TrackedMut};
|
||||||
|
|
||||||
use crate::diag::{bail, SourceResult};
|
use crate::diag::{bail, SourceResult};
|
||||||
use crate::engine::{Engine, Route};
|
use crate::engine::{Engine, Route, Sink, Traced};
|
||||||
use crate::eval::Tracer;
|
|
||||||
use crate::foundations::{category, Category, Content, Scope, StyleChain};
|
use crate::foundations::{category, Category, Content, Scope, StyleChain};
|
||||||
use crate::introspection::{Introspector, Locator, LocatorLink};
|
use crate::introspection::{Introspector, Locator, LocatorLink};
|
||||||
use crate::model::Document;
|
use crate::model::Document;
|
||||||
@ -137,16 +136,18 @@ impl Content {
|
|||||||
content: &Content,
|
content: &Content,
|
||||||
world: Tracked<dyn World + '_>,
|
world: Tracked<dyn World + '_>,
|
||||||
introspector: Tracked<Introspector>,
|
introspector: Tracked<Introspector>,
|
||||||
|
traced: Tracked<Traced>,
|
||||||
|
sink: TrackedMut<Sink>,
|
||||||
route: Tracked<Route>,
|
route: Tracked<Route>,
|
||||||
tracer: TrackedMut<Tracer>,
|
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> SourceResult<Document> {
|
) -> SourceResult<Document> {
|
||||||
let mut locator = Locator::root().split();
|
let mut locator = Locator::root().split();
|
||||||
let mut engine = Engine {
|
let mut engine = Engine {
|
||||||
world,
|
world,
|
||||||
introspector,
|
introspector,
|
||||||
|
traced,
|
||||||
|
sink,
|
||||||
route: Route::extend(route).unnested(),
|
route: Route::extend(route).unnested(),
|
||||||
tracer,
|
|
||||||
};
|
};
|
||||||
let arenas = Arenas::default();
|
let arenas = Arenas::default();
|
||||||
let (document, styles) =
|
let (document, styles) =
|
||||||
@ -158,8 +159,9 @@ impl Content {
|
|||||||
self,
|
self,
|
||||||
engine.world,
|
engine.world,
|
||||||
engine.introspector,
|
engine.introspector,
|
||||||
|
engine.traced,
|
||||||
|
TrackedMut::reborrow_mut(&mut engine.sink),
|
||||||
engine.route.track(),
|
engine.route.track(),
|
||||||
TrackedMut::reborrow_mut(&mut engine.tracer),
|
|
||||||
styles,
|
styles,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -178,8 +180,9 @@ impl Content {
|
|||||||
content: &Content,
|
content: &Content,
|
||||||
world: Tracked<dyn World + '_>,
|
world: Tracked<dyn World + '_>,
|
||||||
introspector: Tracked<Introspector>,
|
introspector: Tracked<Introspector>,
|
||||||
|
traced: Tracked<Traced>,
|
||||||
|
sink: TrackedMut<Sink>,
|
||||||
route: Tracked<Route>,
|
route: Tracked<Route>,
|
||||||
tracer: TrackedMut<Tracer>,
|
|
||||||
locator: Tracked<Locator>,
|
locator: Tracked<Locator>,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
regions: Regions,
|
regions: Regions,
|
||||||
@ -189,8 +192,9 @@ impl Content {
|
|||||||
let mut engine = Engine {
|
let mut engine = Engine {
|
||||||
world,
|
world,
|
||||||
introspector,
|
introspector,
|
||||||
|
traced,
|
||||||
|
sink,
|
||||||
route: Route::extend(route),
|
route: Route::extend(route),
|
||||||
tracer,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !engine.route.within(Route::MAX_LAYOUT_DEPTH) {
|
if !engine.route.within(Route::MAX_LAYOUT_DEPTH) {
|
||||||
@ -218,8 +222,9 @@ impl Content {
|
|||||||
self,
|
self,
|
||||||
engine.world,
|
engine.world,
|
||||||
engine.introspector,
|
engine.introspector,
|
||||||
|
engine.traced,
|
||||||
|
TrackedMut::reborrow_mut(&mut engine.sink),
|
||||||
engine.route.track(),
|
engine.route.track(),
|
||||||
TrackedMut::reborrow_mut(&mut engine.tracer),
|
|
||||||
locator.track(),
|
locator.track(),
|
||||||
styles,
|
styles,
|
||||||
regions,
|
regions,
|
||||||
|
@ -63,11 +63,10 @@ use comemo::{Track, Tracked, Validate};
|
|||||||
use ecow::{EcoString, EcoVec};
|
use ecow::{EcoString, EcoVec};
|
||||||
use typst_timing::{timed, TimingScope};
|
use typst_timing::{timed, TimingScope};
|
||||||
|
|
||||||
use crate::diag::{warning, FileResult, SourceDiagnostic, SourceResult};
|
use crate::diag::{warning, FileResult, SourceDiagnostic, SourceResult, Warned};
|
||||||
use crate::engine::{Engine, Route};
|
use crate::engine::{Engine, Route, Sink, Traced};
|
||||||
use crate::eval::Tracer;
|
|
||||||
use crate::foundations::{
|
use crate::foundations::{
|
||||||
Array, Bytes, Content, Datetime, Dict, Module, Scope, StyleChain, Styles, Value,
|
Array, Bytes, Datetime, Dict, Module, Scope, StyleChain, Styles, Value,
|
||||||
};
|
};
|
||||||
use crate::introspection::Introspector;
|
use crate::introspection::Introspector;
|
||||||
use crate::layout::{Alignment, Dir};
|
use crate::layout::{Alignment, Dir};
|
||||||
@ -78,62 +77,68 @@ use crate::text::{Font, FontBook};
|
|||||||
use crate::utils::LazyHash;
|
use crate::utils::LazyHash;
|
||||||
use crate::visualize::Color;
|
use crate::visualize::Color;
|
||||||
|
|
||||||
/// Compile a source file into a fully layouted document.
|
/// Compile sources into a fully layouted document.
|
||||||
///
|
///
|
||||||
/// - Returns `Ok(document)` if there were no fatal errors.
|
/// - Returns `Ok(document)` if there were no fatal errors.
|
||||||
/// - Returns `Err(errors)` if there were fatal errors.
|
/// - Returns `Err(errors)` if there were fatal errors.
|
||||||
///
|
#[typst_macros::time]
|
||||||
/// Requires a mutable reference to a tracer. Such a tracer can be created with
|
pub fn compile(world: &dyn World) -> Warned<SourceResult<Document>> {
|
||||||
/// `Tracer::new()`. Independently of whether compilation succeeded, calling
|
let mut sink = Sink::new();
|
||||||
/// `tracer.warnings()` after compilation will return all compiler warnings.
|
let output = compile_inner(world.track(), Traced::default().track(), &mut sink)
|
||||||
#[typst_macros::time(name = "compile")]
|
.map_err(deduplicate);
|
||||||
pub fn compile(world: &dyn World, tracer: &mut Tracer) -> SourceResult<Document> {
|
Warned { output, warnings: sink.warnings() }
|
||||||
// Call `track` on the world just once to keep comemo's ID stable.
|
}
|
||||||
let world = world.track();
|
|
||||||
|
|
||||||
// Try to evaluate the source file into a module.
|
/// Compiles sources and returns all values and styles observed at the given
|
||||||
let module = crate::eval::eval(
|
/// `span` during compilation.
|
||||||
world,
|
#[typst_macros::time]
|
||||||
Route::default().track(),
|
pub fn trace(world: &dyn World, span: Span) -> EcoVec<(Value, Option<Styles>)> {
|
||||||
tracer.track_mut(),
|
let mut sink = Sink::new();
|
||||||
&world.main(),
|
let traced = Traced::new(span);
|
||||||
)
|
compile_inner(world.track(), traced.track(), &mut sink).ok();
|
||||||
.map_err(deduplicate)?;
|
sink.values()
|
||||||
|
|
||||||
// Typeset the module's content, relayouting until convergence.
|
|
||||||
typeset(world, tracer, &module.content()).map_err(deduplicate)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Relayout until introspection converges.
|
/// Relayout until introspection converges.
|
||||||
fn typeset(
|
fn compile_inner(
|
||||||
world: Tracked<dyn World + '_>,
|
world: Tracked<dyn World + '_>,
|
||||||
tracer: &mut Tracer,
|
traced: Tracked<Traced>,
|
||||||
content: &Content,
|
sink: &mut Sink,
|
||||||
) -> SourceResult<Document> {
|
) -> SourceResult<Document> {
|
||||||
// The name of the iterations for timing scopes.
|
|
||||||
const ITER_NAMES: &[&str] =
|
|
||||||
&["typeset (1)", "typeset (2)", "typeset (3)", "typeset (4)", "typeset (5)"];
|
|
||||||
|
|
||||||
let library = world.library();
|
let library = world.library();
|
||||||
let styles = StyleChain::new(&library.styles);
|
let styles = StyleChain::new(&library.styles);
|
||||||
|
|
||||||
|
// First evaluate the main source file into a module.
|
||||||
|
let content = crate::eval::eval(
|
||||||
|
world,
|
||||||
|
traced,
|
||||||
|
sink.track_mut(),
|
||||||
|
Route::default().track(),
|
||||||
|
&world.main(),
|
||||||
|
)?
|
||||||
|
.content();
|
||||||
|
|
||||||
let mut iter = 0;
|
let mut iter = 0;
|
||||||
let mut document = Document::default();
|
let mut document = Document::default();
|
||||||
|
|
||||||
// Relayout until all introspections stabilize.
|
// Relayout until all introspections stabilize.
|
||||||
// If that doesn't happen within five attempts, we give up.
|
// If that doesn't happen within five attempts, we give up.
|
||||||
loop {
|
loop {
|
||||||
|
// The name of the iterations for timing scopes.
|
||||||
|
const ITER_NAMES: &[&str] =
|
||||||
|
&["layout (1)", "layout (2)", "layout (3)", "layout (4)", "layout (5)"];
|
||||||
let _scope = TimingScope::new(ITER_NAMES[iter], None);
|
let _scope = TimingScope::new(ITER_NAMES[iter], None);
|
||||||
|
|
||||||
// Clear delayed errors.
|
// Clear delayed errors.
|
||||||
tracer.delayed();
|
sink.delayed();
|
||||||
|
|
||||||
let constraint = <Introspector as Validate>::Constraint::new();
|
let constraint = <Introspector as Validate>::Constraint::new();
|
||||||
let mut engine = Engine {
|
let mut engine = Engine {
|
||||||
world,
|
world,
|
||||||
route: Route::default(),
|
|
||||||
tracer: tracer.track_mut(),
|
|
||||||
introspector: document.introspector.track_with(&constraint),
|
introspector: document.introspector.track_with(&constraint),
|
||||||
|
traced,
|
||||||
|
sink: sink.track_mut(),
|
||||||
|
route: Route::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Layout!
|
// Layout!
|
||||||
@ -146,7 +151,7 @@ fn typeset(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if iter >= 5 {
|
if iter >= 5 {
|
||||||
tracer.warn(warning!(
|
sink.warn(warning!(
|
||||||
Span::detached(), "layout did not converge within 5 attempts";
|
Span::detached(), "layout did not converge within 5 attempts";
|
||||||
hint: "check if any states or queries are updating themselves"
|
hint: "check if any states or queries are updating themselves"
|
||||||
));
|
));
|
||||||
@ -155,7 +160,7 @@ fn typeset(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Promote delayed errors.
|
// Promote delayed errors.
|
||||||
let delayed = tracer.delayed();
|
let delayed = sink.delayed();
|
||||||
if !delayed.is_empty() {
|
if !delayed.is_empty() {
|
||||||
return Err(delayed);
|
return Err(delayed);
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ pub fn process(
|
|||||||
//
|
//
|
||||||
// This way, we can ignore errors that only occur in earlier
|
// This way, we can ignore errors that only occur in earlier
|
||||||
// iterations and also show more useful errors at once.
|
// iterations and also show more useful errors at once.
|
||||||
engine.delayed(|engine| show(engine, target, step, styles.chain(&map)))
|
engine.delay(|engine| show(engine, target, step, styles.chain(&map)))
|
||||||
}
|
}
|
||||||
None => target,
|
None => target,
|
||||||
};
|
};
|
||||||
|
@ -132,7 +132,7 @@ pub struct TextElem {
|
|||||||
let book = engine.world.book();
|
let book = engine.world.book();
|
||||||
for family in &font_list.v {
|
for family in &font_list.v {
|
||||||
if !book.contains_family(family.as_str()) {
|
if !book.contains_family(family.as_str()) {
|
||||||
engine.tracer.warn(warning!(
|
engine.sink.warn(warning!(
|
||||||
font_list.span,
|
font_list.span,
|
||||||
"unknown font family: {}",
|
"unknown font family: {}",
|
||||||
family.as_str(),
|
family.as_str(),
|
||||||
|
@ -7,7 +7,6 @@ use pulldown_cmark as md;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use typed_arena::Arena;
|
use typed_arena::Arena;
|
||||||
use typst::diag::{FileResult, StrResult};
|
use typst::diag::{FileResult, StrResult};
|
||||||
use typst::eval::Tracer;
|
|
||||||
use typst::foundations::{Bytes, Datetime};
|
use typst::foundations::{Bytes, Datetime};
|
||||||
use typst::layout::{Abs, Point, Size};
|
use typst::layout::{Abs, Point, Size};
|
||||||
use typst::syntax::{FileId, Source, VirtualPath};
|
use typst::syntax::{FileId, Source, VirtualPath};
|
||||||
@ -411,8 +410,7 @@ fn code_block(resolver: &dyn Resolver, lang: &str, text: &str) -> Html {
|
|||||||
let source = Source::new(id, compile);
|
let source = Source::new(id, compile);
|
||||||
let world = DocWorld(source);
|
let world = DocWorld(source);
|
||||||
|
|
||||||
let mut tracer = Tracer::new();
|
let mut document = match typst::compile(&world).output {
|
||||||
let mut document = match typst::compile(&world, &mut tracer) {
|
|
||||||
Ok(doc) => doc,
|
Ok(doc) => doc,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let msg = &err[0].message;
|
let msg = &err[0].message;
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
use libfuzzer_sys::fuzz_target;
|
use libfuzzer_sys::fuzz_target;
|
||||||
use typst::diag::{FileError, FileResult};
|
use typst::diag::{FileError, FileResult};
|
||||||
use typst::eval::Tracer;
|
|
||||||
use typst::foundations::{Bytes, Datetime};
|
use typst::foundations::{Bytes, Datetime};
|
||||||
use typst::syntax::{FileId, Source};
|
use typst::syntax::{FileId, Source};
|
||||||
use typst::text::{Font, FontBook};
|
use typst::text::{Font, FontBook};
|
||||||
@ -63,8 +62,7 @@ impl World for FuzzWorld {
|
|||||||
|
|
||||||
fuzz_target!(|text: &str| {
|
fuzz_target!(|text: &str| {
|
||||||
let world = FuzzWorld::new(text);
|
let world = FuzzWorld::new(text);
|
||||||
let mut tracer = Tracer::new();
|
if let Ok(document) = typst::compile(&world).output {
|
||||||
if let Ok(document) = typst::compile(&world, &mut tracer) {
|
|
||||||
if let Some(page) = document.pages.first() {
|
if let Some(page) = document.pages.first() {
|
||||||
std::hint::black_box(typst_render::render(&page.frame, 1.0, Color::WHITE));
|
std::hint::black_box(typst_render::render(&page.frame, 1.0, Color::WHITE));
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,7 @@ use std::path::Path;
|
|||||||
|
|
||||||
use ecow::eco_vec;
|
use ecow::eco_vec;
|
||||||
use tiny_skia as sk;
|
use tiny_skia as sk;
|
||||||
use typst::diag::SourceDiagnostic;
|
use typst::diag::{SourceDiagnostic, Warned};
|
||||||
use typst::eval::Tracer;
|
|
||||||
use typst::foundations::Smart;
|
use typst::foundations::Smart;
|
||||||
use typst::layout::{Abs, Frame, FrameItem, Page, Transform};
|
use typst::layout::{Abs, Frame, FrameItem, Page, Transform};
|
||||||
use typst::model::Document;
|
use typst::model::Document;
|
||||||
@ -80,13 +79,12 @@ impl<'a> Runner<'a> {
|
|||||||
log!(into: self.result.infos, "tree: {:#?}", self.test.source.root());
|
log!(into: self.result.infos, "tree: {:#?}", self.test.source.root());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut tracer = Tracer::new();
|
let Warned { output, warnings } = typst::compile(&self.world);
|
||||||
let (doc, errors) = match typst::compile(&self.world, &mut tracer) {
|
let (doc, errors) = match output {
|
||||||
Ok(doc) => (Some(doc), eco_vec![]),
|
Ok(doc) => (Some(doc), eco_vec![]),
|
||||||
Err(errors) => (None, errors),
|
Err(errors) => (None, errors),
|
||||||
};
|
};
|
||||||
|
|
||||||
let warnings = tracer.warnings();
|
|
||||||
if doc.is_none() && errors.is_empty() {
|
if doc.is_none() && errors.is_empty() {
|
||||||
log!(self, "no document, but also no errors");
|
log!(self, "no document, but also no errors");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user