mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
More general evaluation interface
This commit is contained in:
parent
65aa27014d
commit
b2a3d3f235
@ -235,10 +235,12 @@ fn typeset(command: TypesetCommand) -> StrResult<()> {
|
|||||||
/// Typeset a single time.
|
/// Typeset a single time.
|
||||||
fn typeset_once(world: &mut SystemWorld, command: &TypesetCommand) -> StrResult<()> {
|
fn typeset_once(world: &mut SystemWorld, command: &TypesetCommand) -> StrResult<()> {
|
||||||
status(command, Status::Compiling).unwrap();
|
status(command, Status::Compiling).unwrap();
|
||||||
|
|
||||||
world.reset();
|
world.reset();
|
||||||
|
|
||||||
let main = world.resolve(&command.input).map_err(|err| err.to_string())?;
|
let main = world.resolve(&command.input).map_err(|err| err.to_string())?;
|
||||||
match typst::typeset(world, main) {
|
let source = world.source(main);
|
||||||
|
|
||||||
|
match typst::typeset(world, source) {
|
||||||
// Export the PDF.
|
// Export the PDF.
|
||||||
Ok(frames) => {
|
Ok(frames) => {
|
||||||
let buffer = typst::export::pdf(&frames);
|
let buffer = typst::export::pdf(&frames);
|
||||||
|
@ -11,7 +11,7 @@ pub use self::data::*;
|
|||||||
pub use self::string::*;
|
pub use self::string::*;
|
||||||
|
|
||||||
use comemo::Track;
|
use comemo::Track;
|
||||||
use typst::model::{Eval, Route, Scopes, Vm};
|
use typst::model::{self, Route, Vm};
|
||||||
use typst::syntax::Source;
|
use typst::syntax::Source;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
@ -33,22 +33,8 @@ pub fn assert(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
|
|||||||
/// Evaluate a string as Typst markup.
|
/// Evaluate a string as Typst markup.
|
||||||
pub fn eval(vm: &mut Vm, args: &mut Args) -> SourceResult<Value> {
|
pub fn eval(vm: &mut Vm, args: &mut Args) -> SourceResult<Value> {
|
||||||
let Spanned { v: text, span } = args.expect::<Spanned<String>>("source")?;
|
let Spanned { v: text, span } = args.expect::<Spanned<String>>("source")?;
|
||||||
|
|
||||||
// Parse the source and set a synthetic span for all nodes.
|
|
||||||
let source = Source::synthesized(text, span);
|
let source = Source::synthesized(text, span);
|
||||||
let ast = source.ast()?;
|
|
||||||
|
|
||||||
// Evaluate the source.
|
|
||||||
let std = &vm.world.config().scope;
|
|
||||||
let scopes = Scopes::new(Some(std));
|
|
||||||
let route = Route::default();
|
let route = Route::default();
|
||||||
let mut sub = Vm::new(vm.world, route.track(), None, scopes);
|
let module = model::eval(vm.world, route.track(), &source)?;
|
||||||
let result = ast.eval(&mut sub);
|
Ok(Value::Content(module.content))
|
||||||
|
|
||||||
// Handle control flow.
|
|
||||||
if let Some(flow) = sub.flow {
|
|
||||||
bail!(flow.forbidden());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Value::Content(result?))
|
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,7 @@ pub fn styles() -> StyleMap {
|
|||||||
/// Construct the standard lang item mapping.
|
/// Construct the standard lang item mapping.
|
||||||
pub fn items() -> LangItems {
|
pub fn items() -> LangItems {
|
||||||
LangItems {
|
LangItems {
|
||||||
root: |content, world, styles| content.layout_root(world, styles),
|
layout: |content, world, styles| content.layout_root(world, styles),
|
||||||
em: |styles| styles.get(text::TextNode::SIZE),
|
em: |styles| styles.get(text::TextNode::SIZE),
|
||||||
dir: |styles| styles.get(text::TextNode::DIR),
|
dir: |styles| styles.get(text::TextNode::DIR),
|
||||||
space: || text::SpaceNode.pack(),
|
space: || text::SpaceNode.pack(),
|
||||||
|
@ -49,6 +49,9 @@ pub use crate::__error as error;
|
|||||||
pub type SourceResult<T> = Result<T, Box<Vec<SourceError>>>;
|
pub type SourceResult<T> = Result<T, Box<Vec<SourceError>>>;
|
||||||
|
|
||||||
/// An error in a source file.
|
/// An error in a source file.
|
||||||
|
///
|
||||||
|
/// This contained spans will only be detached if any of the input source files
|
||||||
|
/// were detached.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct SourceError {
|
pub struct SourceError {
|
||||||
/// The span of the erroneous node in the source code.
|
/// The span of the erroneous node in the source code.
|
||||||
|
11
src/lib.rs
11
src/lib.rs
@ -60,14 +60,19 @@ use crate::util::Buffer;
|
|||||||
/// information.
|
/// information.
|
||||||
pub fn typeset(
|
pub fn typeset(
|
||||||
world: &(dyn World + 'static),
|
world: &(dyn World + 'static),
|
||||||
main: SourceId,
|
source: &Source,
|
||||||
) -> SourceResult<Vec<Frame>> {
|
) -> SourceResult<Vec<Frame>> {
|
||||||
|
// Set up the language items.
|
||||||
let config = world.config();
|
let config = world.config();
|
||||||
crate::model::set_lang_items(config.items);
|
crate::model::set_lang_items(config.items);
|
||||||
|
|
||||||
|
// Evaluate the source file into a module.
|
||||||
let route = Route::default();
|
let route = Route::default();
|
||||||
let module = model::eval(world.track(), route.track(), main)?;
|
let module = model::eval(world.track(), route.track(), source)?;
|
||||||
|
|
||||||
|
// Layout the module's contents.
|
||||||
let styles = StyleChain::with_root(&config.styles);
|
let styles = StyleChain::with_root(&config.styles);
|
||||||
item!(root)(&module.content, world.track(), styles)
|
item!(layout)(&module.content, world.track(), styles)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The environment in which typesetting occurs.
|
/// The environment in which typesetting occurs.
|
||||||
|
@ -13,7 +13,7 @@ use super::{
|
|||||||
use crate::diag::{bail, error, At, SourceResult, StrResult, Trace, Tracepoint};
|
use crate::diag::{bail, error, At, SourceResult, StrResult, Trace, Tracepoint};
|
||||||
use crate::geom::{Abs, Angle, Em, Fr, Ratio};
|
use crate::geom::{Abs, Angle, Em, Fr, Ratio};
|
||||||
use crate::syntax::ast::AstNode;
|
use crate::syntax::ast::AstNode;
|
||||||
use crate::syntax::{ast, SourceId, Span, Spanned, Unit};
|
use crate::syntax::{ast, Source, SourceId, Span, Spanned, Unit};
|
||||||
use crate::util::{format_eco, EcoString};
|
use crate::util::{format_eco, EcoString};
|
||||||
use crate::World;
|
use crate::World;
|
||||||
|
|
||||||
@ -26,9 +26,10 @@ use crate::World;
|
|||||||
pub fn eval(
|
pub fn eval(
|
||||||
world: Tracked<dyn World>,
|
world: Tracked<dyn World>,
|
||||||
route: Tracked<Route>,
|
route: Tracked<Route>,
|
||||||
id: SourceId,
|
source: &Source,
|
||||||
) -> SourceResult<Module> {
|
) -> SourceResult<Module> {
|
||||||
// Prevent cyclic evaluation.
|
// Prevent cyclic evaluation.
|
||||||
|
let id = source.id();
|
||||||
if route.contains(id) {
|
if route.contains(id) {
|
||||||
let path = world.source(id).path().display();
|
let path = world.source(id).path().display();
|
||||||
panic!("Tried to cyclicly evaluate {}", path);
|
panic!("Tried to cyclicly evaluate {}", path);
|
||||||
@ -36,11 +37,10 @@ pub fn eval(
|
|||||||
|
|
||||||
// Evaluate the module.
|
// Evaluate the module.
|
||||||
let route = unsafe { Route::insert(route, id) };
|
let route = unsafe { Route::insert(route, id) };
|
||||||
let ast = world.source(id).ast()?;
|
|
||||||
let std = &world.config().scope;
|
let std = &world.config().scope;
|
||||||
let scopes = Scopes::new(Some(std));
|
let scopes = Scopes::new(Some(std));
|
||||||
let mut vm = Vm::new(world, route.track(), Some(id), scopes);
|
let mut vm = Vm::new(world, route.track(), id, scopes);
|
||||||
let result = ast.eval(&mut vm);
|
let result = source.ast()?.eval(&mut vm);
|
||||||
|
|
||||||
// Handle control flow.
|
// Handle control flow.
|
||||||
if let Some(flow) = vm.flow {
|
if let Some(flow) = vm.flow {
|
||||||
@ -59,9 +59,9 @@ pub struct Route {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Route {
|
impl Route {
|
||||||
/// Create a new, empty route.
|
/// Create a new route with just one entry.
|
||||||
pub fn new(id: Option<SourceId>) -> Self {
|
pub fn new(id: SourceId) -> Self {
|
||||||
Self { id, parent: None }
|
Self { id: Some(id), parent: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert a new id into the route.
|
/// Insert a new id into the route.
|
||||||
@ -94,7 +94,7 @@ pub struct Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate an expression.
|
/// Evaluate an expression.
|
||||||
pub trait Eval {
|
pub(super) trait Eval {
|
||||||
/// The output of evaluating the expression.
|
/// The output of evaluating the expression.
|
||||||
type Output;
|
type Output;
|
||||||
|
|
||||||
@ -1038,10 +1038,9 @@ fn import(vm: &mut Vm, path: &str, span: Span) -> SourceResult<Module> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate the file.
|
// Evaluate the file.
|
||||||
let module =
|
let source = vm.world.source(id);
|
||||||
eval(vm.world, vm.route, id).trace(vm.world, || Tracepoint::Import, span)?;
|
let point = || Tracepoint::Import;
|
||||||
|
eval(vm.world, vm.route, source).trace(vm.world, point, span)
|
||||||
Ok(module)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for ast::LoopBreak {
|
impl Eval for ast::LoopBreak {
|
||||||
|
@ -97,7 +97,9 @@ impl Func {
|
|||||||
args: Args,
|
args: Args,
|
||||||
) -> SourceResult<Value> {
|
) -> SourceResult<Value> {
|
||||||
let route = Route::default();
|
let route = Route::default();
|
||||||
let mut vm = Vm::new(world, route.track(), None, Scopes::new(None));
|
let id = SourceId::detached();
|
||||||
|
let scopes = Scopes::new(None);
|
||||||
|
let mut vm = Vm::new(world, route.track(), id, scopes);
|
||||||
self.call(&mut vm, args)
|
self.call(&mut vm, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +180,7 @@ impl Hash for Native {
|
|||||||
#[derive(Hash)]
|
#[derive(Hash)]
|
||||||
pub struct Closure {
|
pub struct Closure {
|
||||||
/// The source file where the closure was defined.
|
/// The source file where the closure was defined.
|
||||||
pub location: Option<SourceId>,
|
pub location: SourceId,
|
||||||
/// The name of the closure.
|
/// The name of the closure.
|
||||||
pub name: Option<EcoString>,
|
pub name: Option<EcoString>,
|
||||||
/// Captured values from outer scopes.
|
/// Captured values from outer scopes.
|
||||||
@ -219,7 +221,7 @@ impl Closure {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine the route inside the closure.
|
// Determine the route inside the closure.
|
||||||
let detached = vm.location.is_none();
|
let detached = vm.location.is_detached();
|
||||||
let fresh = Route::new(self.location);
|
let fresh = Route::new(self.location);
|
||||||
let route = if detached { fresh.track() } else { vm.route };
|
let route = if detached { fresh.track() } else { vm.route };
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ macro_rules! item {
|
|||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct LangItems {
|
pub struct LangItems {
|
||||||
/// The root layout function.
|
/// The root layout function.
|
||||||
pub root: fn(
|
pub layout: fn(
|
||||||
content: &Content,
|
content: &Content,
|
||||||
world: Tracked<dyn World>,
|
world: Tracked<dyn World>,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
@ -104,7 +104,7 @@ impl Debug for LangItems {
|
|||||||
|
|
||||||
impl Hash for LangItems {
|
impl Hash for LangItems {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
(self.root as usize).hash(state);
|
(self.layout as usize).hash(state);
|
||||||
(self.em as usize).hash(state);
|
(self.em as usize).hash(state);
|
||||||
(self.dir as usize).hash(state);
|
(self.dir as usize).hash(state);
|
||||||
self.space.hash(state);
|
self.space.hash(state);
|
||||||
|
@ -15,7 +15,7 @@ pub struct Vm<'a> {
|
|||||||
/// The route of source ids the VM took to reach its current location.
|
/// The route of source ids the VM took to reach its current location.
|
||||||
pub route: Tracked<'a, Route>,
|
pub route: Tracked<'a, Route>,
|
||||||
/// The current location.
|
/// The current location.
|
||||||
pub location: Option<SourceId>,
|
pub location: SourceId,
|
||||||
/// The stack of scopes.
|
/// The stack of scopes.
|
||||||
pub scopes: Scopes<'a>,
|
pub scopes: Scopes<'a>,
|
||||||
/// A control flow event that is currently happening.
|
/// A control flow event that is currently happening.
|
||||||
@ -29,7 +29,7 @@ impl<'a> Vm<'a> {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
world: Tracked<'a, dyn World>,
|
world: Tracked<'a, dyn World>,
|
||||||
route: Tracked<'a, Route>,
|
route: Tracked<'a, Route>,
|
||||||
location: Option<SourceId>,
|
location: SourceId,
|
||||||
scopes: Scopes<'a>,
|
scopes: Scopes<'a>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -45,12 +45,12 @@ impl<'a> Vm<'a> {
|
|||||||
/// Resolve a user-entered path to be relative to the compilation
|
/// Resolve a user-entered path to be relative to the compilation
|
||||||
/// environment's root.
|
/// environment's root.
|
||||||
pub fn locate(&self, path: &str) -> StrResult<PathBuf> {
|
pub fn locate(&self, path: &str) -> StrResult<PathBuf> {
|
||||||
if let Some(id) = self.location {
|
if !self.location.is_detached() {
|
||||||
if let Some(path) = path.strip_prefix('/') {
|
if let Some(path) = path.strip_prefix('/') {
|
||||||
return Ok(self.world.config().root.join(path).normalize());
|
return Ok(self.world.config().root.join(path).normalize());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(dir) = self.world.source(id).path().parent() {
|
if let Some(dir) = self.world.source(self.location).path().parent() {
|
||||||
return Ok(dir.join(path).normalize());
|
return Ok(dir.join(path).normalize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,26 +21,21 @@ use crate::util::{PathExt, StrExt};
|
|||||||
pub struct Source {
|
pub struct Source {
|
||||||
id: SourceId,
|
id: SourceId,
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
text: Prehashed<String>,
|
|
||||||
lines: Vec<Line>,
|
lines: Vec<Line>,
|
||||||
|
text: Prehashed<String>,
|
||||||
root: Prehashed<SyntaxNode>,
|
root: Prehashed<SyntaxNode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Source {
|
impl Source {
|
||||||
/// Create a new source file.
|
/// Create a new source file.
|
||||||
pub fn new(id: SourceId, path: &Path, text: String) -> Self {
|
pub fn new(id: SourceId, path: &Path, text: String) -> Self {
|
||||||
let lines = std::iter::once(Line { byte_idx: 0, utf16_idx: 0 })
|
|
||||||
.chain(lines(0, 0, &text))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut root = parse(&text);
|
let mut root = parse(&text);
|
||||||
root.numberize(id, Span::FULL).unwrap();
|
root.numberize(id, Span::FULL).unwrap();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
path: path.normalize(),
|
path: path.normalize(),
|
||||||
|
lines: lines(&text),
|
||||||
text: Prehashed::new(text),
|
text: Prehashed::new(text),
|
||||||
lines,
|
|
||||||
root: Prehashed::new(root),
|
root: Prehashed::new(root),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,13 +46,16 @@ impl Source {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a source file with the same synthetic span for all nodes.
|
/// Create a source file with the same synthetic span for all nodes.
|
||||||
pub fn synthesized(text: impl Into<String>, span: Span) -> Self {
|
pub fn synthesized(text: String, span: Span) -> Self {
|
||||||
let mut file = Self::detached(text);
|
let mut root = parse(&text);
|
||||||
let mut root = file.root.into_inner();
|
|
||||||
root.synthesize(span);
|
root.synthesize(span);
|
||||||
file.root = Prehashed::new(root);
|
Self {
|
||||||
file.id = span.source();
|
id: SourceId::detached(),
|
||||||
file
|
path: PathBuf::new(),
|
||||||
|
lines: lines(&text),
|
||||||
|
text: Prehashed::new(text),
|
||||||
|
root: Prehashed::new(root),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The root node of the file's untyped syntax tree.
|
/// The root node of the file's untyped syntax tree.
|
||||||
@ -98,10 +96,9 @@ impl Source {
|
|||||||
/// Fully replace the source text.
|
/// Fully replace the source text.
|
||||||
pub fn replace(&mut self, text: String) {
|
pub fn replace(&mut self, text: String) {
|
||||||
self.text = Prehashed::new(text);
|
self.text = Prehashed::new(text);
|
||||||
self.lines = vec![Line { byte_idx: 0, utf16_idx: 0 }];
|
self.lines = lines(&self.text);
|
||||||
self.lines.extend(lines(0, 0, &self.text));
|
|
||||||
let mut root = parse(&self.text);
|
let mut root = parse(&self.text);
|
||||||
root.numberize(self.id(), Span::FULL).unwrap();
|
root.numberize(self.id, Span::FULL).unwrap();
|
||||||
self.root = Prehashed::new(root);
|
self.root = Prehashed::new(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +125,7 @@ impl Source {
|
|||||||
|
|
||||||
// Recalculate the line starts after the edit.
|
// Recalculate the line starts after the edit.
|
||||||
self.lines
|
self.lines
|
||||||
.extend(lines(start_byte, start_utf16, &self.text[start_byte..]));
|
.extend(lines_from(start_byte, start_utf16, &self.text[start_byte..]));
|
||||||
|
|
||||||
// Incrementally reparse the replaced range.
|
// Incrementally reparse the replaced range.
|
||||||
let mut root = std::mem::take(&mut self.root).into_inner();
|
let mut root = std::mem::take(&mut self.root).into_inner();
|
||||||
@ -262,11 +259,16 @@ impl Hash for Source {
|
|||||||
pub struct SourceId(u16);
|
pub struct SourceId(u16);
|
||||||
|
|
||||||
impl SourceId {
|
impl SourceId {
|
||||||
/// Create a new source id for a file that is not part of a store.
|
/// Create a new source id for a file that is not part of the world.
|
||||||
pub const fn detached() -> Self {
|
pub const fn detached() -> Self {
|
||||||
Self(u16::MAX)
|
Self(u16::MAX)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether the source id is the detached.
|
||||||
|
pub const fn is_detached(self) -> bool {
|
||||||
|
self.0 == Self::detached().0
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a source id from a number.
|
/// Create a source id from a number.
|
||||||
pub const fn from_u16(v: u16) -> Self {
|
pub const fn from_u16(v: u16) -> Self {
|
||||||
Self(v)
|
Self(v)
|
||||||
@ -287,8 +289,15 @@ struct Line {
|
|||||||
utf16_idx: usize,
|
utf16_idx: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over the lines in the string.
|
/// Create a line vector.
|
||||||
fn lines(
|
fn lines(text: &str) -> Vec<Line> {
|
||||||
|
std::iter::once(Line { byte_idx: 0, utf16_idx: 0 })
|
||||||
|
.chain(lines_from(0, 0, &text))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute a line iterator from an offset.
|
||||||
|
fn lines_from(
|
||||||
byte_offset: usize,
|
byte_offset: usize,
|
||||||
utf16_offset: usize,
|
utf16_offset: usize,
|
||||||
text: &str,
|
text: &str,
|
||||||
|
@ -27,15 +27,13 @@ use super::SourceId;
|
|||||||
pub struct Span(NonZeroU64);
|
pub struct Span(NonZeroU64);
|
||||||
|
|
||||||
impl Span {
|
impl Span {
|
||||||
// Data layout:
|
|
||||||
// | 16 bits source id | 48 bits number |
|
|
||||||
|
|
||||||
// Number of bits for and minimum and maximum numbers assignable to spans.
|
|
||||||
const BITS: usize = 48;
|
|
||||||
const DETACHED: u64 = 1;
|
|
||||||
|
|
||||||
/// The full range of numbers available for span numbering.
|
/// The full range of numbers available for span numbering.
|
||||||
pub const FULL: Range<u64> = 2..(1 << Self::BITS);
|
pub const FULL: Range<u64> = 2..(1 << Self::BITS);
|
||||||
|
const DETACHED: u64 = 1;
|
||||||
|
|
||||||
|
// Data layout:
|
||||||
|
// | 16 bits source id | 48 bits number |
|
||||||
|
const BITS: usize = 48;
|
||||||
|
|
||||||
/// Create a new span from a source id and a unique number.
|
/// Create a new span from a source id and a unique number.
|
||||||
///
|
///
|
||||||
@ -46,13 +44,26 @@ impl Span {
|
|||||||
"span number outside valid range"
|
"span number outside valid range"
|
||||||
);
|
);
|
||||||
|
|
||||||
let bits = ((id.into_u16() as u64) << Self::BITS) | number;
|
Self::pack(id, number)
|
||||||
Self(to_non_zero(bits))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A span that does not point into any source file.
|
/// A span that does not point into any source file.
|
||||||
pub const fn detached() -> Self {
|
pub const fn detached() -> Self {
|
||||||
Self(to_non_zero(Self::DETACHED))
|
Self::pack(SourceId::detached(), Self::DETACHED)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pack the components into a span.
|
||||||
|
const fn pack(id: SourceId, number: u64) -> Span {
|
||||||
|
let bits = ((id.into_u16() as u64) << Self::BITS) | number;
|
||||||
|
match NonZeroU64::new(bits) {
|
||||||
|
Some(v) => Self(v),
|
||||||
|
None => panic!("span encoding is zero"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether the span is detached.
|
||||||
|
pub const fn is_detached(self) -> bool {
|
||||||
|
self.source().is_detached()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The id of the source file the span points into.
|
/// The id of the source file the span points into.
|
||||||
@ -66,14 +77,6 @@ impl Span {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert to a non zero u64.
|
|
||||||
const fn to_non_zero(v: u64) -> NonZeroU64 {
|
|
||||||
match NonZeroU64::new(v) {
|
|
||||||
Some(v) => v,
|
|
||||||
None => panic!("span encoding is zero"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A value with a span locating it in the source code.
|
/// A value with a span locating it in the source code.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct Spanned<T> {
|
pub struct Spanned<T> {
|
||||||
|
@ -74,21 +74,18 @@ fn bench_highlight(iai: &mut Iai) {
|
|||||||
|
|
||||||
fn bench_eval(iai: &mut Iai) {
|
fn bench_eval(iai: &mut Iai) {
|
||||||
let world = BenchWorld::new();
|
let world = BenchWorld::new();
|
||||||
let id = world.source.id();
|
|
||||||
let route = typst::model::Route::default();
|
let route = typst::model::Route::default();
|
||||||
iai.run(|| typst::model::eval(world.track(), route.track(), id).unwrap());
|
iai.run(|| typst::model::eval(world.track(), route.track(), &world.source).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_typeset(iai: &mut Iai) {
|
fn bench_typeset(iai: &mut Iai) {
|
||||||
let world = BenchWorld::new();
|
let world = BenchWorld::new();
|
||||||
let id = world.source.id();
|
iai.run(|| typst::typeset(&world, &world.source));
|
||||||
iai.run(|| typst::typeset(&world, id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_render(iai: &mut Iai) {
|
fn bench_render(iai: &mut Iai) {
|
||||||
let world = BenchWorld::new();
|
let world = BenchWorld::new();
|
||||||
let id = world.source.id();
|
let frames = typst::typeset(&world, &world.source).unwrap();
|
||||||
let frames = typst::typeset(&world, id).unwrap();
|
|
||||||
iai.run(|| typst::export::render(&frames[0], 1.0))
|
iai.run(|| typst::export::render(&frames[0], 1.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,8 +107,7 @@ impl BenchWorld {
|
|||||||
|
|
||||||
let font = Font::new(FONT.into(), 0).unwrap();
|
let font = Font::new(FONT.into(), 0).unwrap();
|
||||||
let book = FontBook::from_fonts([&font]);
|
let book = FontBook::from_fonts([&font]);
|
||||||
let id = SourceId::from_u16(0);
|
let source = Source::detached(TEXT);
|
||||||
let source = Source::new(id, Path::new("bench.typ"), TEXT.into());
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
config: Prehashed::new(config),
|
config: Prehashed::new(config),
|
||||||
@ -148,6 +144,6 @@ impl World for BenchWorld {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn source(&self, _: SourceId) -> &Source {
|
fn source(&self, _: SourceId) -> &Source {
|
||||||
&self.source
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -418,13 +418,13 @@ fn test_part(
|
|||||||
ok &= test_reparse(world.source(id).text(), i, rng);
|
ok &= test_reparse(world.source(id).text(), i, rng);
|
||||||
|
|
||||||
if world.print.model {
|
if world.print.model {
|
||||||
let tracked = (world as &dyn World).track();
|
let world = (world as &dyn World).track();
|
||||||
let route = typst::model::Route::default();
|
let route = typst::model::Route::default();
|
||||||
let module = typst::model::eval(tracked, route.track(), id).unwrap();
|
let module = typst::model::eval(world, route.track(), source).unwrap();
|
||||||
println!("Model:\n{:#?}\n", module.content);
|
println!("Model:\n{:#?}\n", module.content);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut frames, errors) = match typst::typeset(world, id) {
|
let (mut frames, errors) = match typst::typeset(world, source) {
|
||||||
Ok(frames) => (frames, vec![]),
|
Ok(frames) => (frames, vec![]),
|
||||||
Err(errors) => (vec![], *errors),
|
Err(errors) => (vec![], *errors),
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user