diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-09-20 19:49:47 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-09-20 19:49:47 +0200 |
| commit | 3760748fddd3b793c79c370398a9d4a3fc5afc04 (patch) | |
| tree | b1a615e510aa231cfe9757a9c0a35a375e32e3ba /src/library | |
| parent | 757a701c1aa2a6fb80033c7e75666661818da6f9 (diff) | |
Refactor error handling
Diffstat (limited to 'src/library')
36 files changed, 179 insertions, 150 deletions
diff --git a/src/library/graphics/hide.rs b/src/library/graphics/hide.rs index f2a423ce..505dd1f6 100644 --- a/src/library/graphics/hide.rs +++ b/src/library/graphics/hide.rs @@ -6,7 +6,7 @@ pub struct HideNode(pub LayoutNode); #[node] impl HideNode { - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { Ok(Content::inline(Self(args.expect("body")?))) } } @@ -17,7 +17,7 @@ impl Layout for HideNode { world: &dyn World, regions: &Regions, styles: StyleChain, - ) -> TypResult<Vec<Frame>> { + ) -> SourceResult<Vec<Frame>> { let mut frames = self.0.layout(world, regions, styles)?; for frame in &mut frames { frame.clear(); diff --git a/src/library/graphics/image.rs b/src/library/graphics/image.rs index 1642c7b0..c0249b3c 100644 --- a/src/library/graphics/image.rs +++ b/src/library/graphics/image.rs @@ -1,6 +1,6 @@ use std::ffi::OsStr; -use crate::image::Image; +use crate::image::{Image, ImageFormat, RasterFormat, VectorFormat}; use crate::library::prelude::*; use crate::library::text::TextNode; @@ -13,19 +13,22 @@ impl ImageNode { /// How the image should adjust itself to a given area. pub const FIT: ImageFit = ImageFit::Cover; - fn construct(vm: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(vm: &mut Vm, args: &mut Args) -> SourceResult<Content> { let Spanned { v: path, span } = args.expect::<Spanned<EcoString>>("path to image file")?; let full = vm.locate(&path).at(span)?; + let buffer = vm.world.file(&full).at(span)?; let ext = full.extension().and_then(OsStr::to_str).unwrap_or_default(); - let image = vm - .world - .file(&full) - .and_then(|buffer| Image::new(buffer, ext)) - .map_err(|err| failed_to_load("image", &full, err)) - .at(span)?; + let format = match ext.to_lowercase().as_str() { + "png" => ImageFormat::Raster(RasterFormat::Png), + "jpg" | "jpeg" => ImageFormat::Raster(RasterFormat::Jpg), + "gif" => ImageFormat::Raster(RasterFormat::Gif), + "svg" | "svgz" => ImageFormat::Vector(VectorFormat::Svg), + _ => bail!(span, "unknown image format"), + }; + let image = Image::new(buffer, format).at(span)?; let width = args.named("width")?; let height = args.named("height")?; @@ -41,7 +44,7 @@ impl Layout for ImageNode { _: &dyn World, regions: &Regions, styles: StyleChain, - ) -> TypResult<Vec<Frame>> { + ) -> SourceResult<Vec<Frame>> { let pxw = self.0.width() as f64; let pxh = self.0.height() as f64; let px_ratio = pxw / pxh; diff --git a/src/library/graphics/line.rs b/src/library/graphics/line.rs index 95c3a709..ebfec1b2 100644 --- a/src/library/graphics/line.rs +++ b/src/library/graphics/line.rs @@ -15,7 +15,7 @@ impl LineNode { #[property(resolve, fold)] pub const STROKE: RawStroke = RawStroke::default(); - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { let origin = args.named("origin")?.unwrap_or_default(); let delta = match args.named::<Spec<Relative<RawLength>>>("to")? { @@ -43,7 +43,7 @@ impl Layout for LineNode { _: &dyn World, regions: &Regions, styles: StyleChain, - ) -> TypResult<Vec<Frame>> { + ) -> SourceResult<Vec<Frame>> { let stroke = styles.get(Self::STROKE).unwrap_or_default(); let origin = self diff --git a/src/library/graphics/shape.rs b/src/library/graphics/shape.rs index ee5e43e8..d9162557 100644 --- a/src/library/graphics/shape.rs +++ b/src/library/graphics/shape.rs @@ -39,7 +39,7 @@ impl<const S: ShapeKind> ShapeNode<S> { pub const RADIUS: Corners<Option<Relative<RawLength>>> = Corners::splat(Relative::zero()); - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { let size = match S { SQUARE => args.named::<RawLength>("size")?.map(Relative::from), CIRCLE => args.named::<RawLength>("radius")?.map(|r| 2.0 * Relative::from(r)), @@ -81,7 +81,7 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> { world: &dyn World, regions: &Regions, styles: StyleChain, - ) -> TypResult<Vec<Frame>> { + ) -> SourceResult<Vec<Frame>> { let mut frames; if let Some(child) = &self.0 { let mut inset = styles.get(Self::INSET); diff --git a/src/library/graphics/transform.rs b/src/library/graphics/transform.rs index 0a4f5b5f..34d45bd0 100644 --- a/src/library/graphics/transform.rs +++ b/src/library/graphics/transform.rs @@ -12,7 +12,7 @@ pub struct MoveNode { #[node] impl MoveNode { - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { let dx = args.named("dx")?.unwrap_or_default(); let dy = args.named("dy")?.unwrap_or_default(); Ok(Content::inline(Self { @@ -28,7 +28,7 @@ impl Layout for MoveNode { world: &dyn World, regions: &Regions, styles: StyleChain, - ) -> TypResult<Vec<Frame>> { + ) -> SourceResult<Vec<Frame>> { let mut frames = self.child.layout(world, regions, styles)?; let delta = self.delta.resolve(styles); @@ -62,7 +62,7 @@ impl<const T: TransformKind> TransformNode<T> { #[property(resolve)] pub const ORIGIN: Spec<Option<RawAlign>> = Spec::default(); - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { let transform = match T { ROTATE => { let angle = args.named_or_find("angle")?.unwrap_or_default(); @@ -89,7 +89,7 @@ impl<const T: TransformKind> Layout for TransformNode<T> { world: &dyn World, regions: &Regions, styles: StyleChain, - ) -> TypResult<Vec<Frame>> { + ) -> SourceResult<Vec<Frame>> { let origin = styles.get(Self::ORIGIN).unwrap_or(Align::CENTER_HORIZON); let mut frames = self.child.layout(world, regions, styles)?; diff --git a/src/library/layout/align.rs b/src/library/layout/align.rs index 3b1a4aaf..0c758cf2 100644 --- a/src/library/layout/align.rs +++ b/src/library/layout/align.rs @@ -12,7 +12,7 @@ pub struct AlignNode { #[node] impl AlignNode { - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { let aligns: Spec<Option<RawAlign>> = args.find()?.unwrap_or_default(); let body: Content = args.expect("body")?; Ok(match (body, aligns) { @@ -31,7 +31,7 @@ impl Layout for AlignNode { world: &dyn World, regions: &Regions, styles: StyleChain, - ) -> TypResult<Vec<Frame>> { + ) -> SourceResult<Vec<Frame>> { // The child only needs to expand along an axis if there's no alignment. let mut pod = regions.clone(); pod.expand &= self.aligns.map_is_none(); diff --git a/src/library/layout/columns.rs b/src/library/layout/columns.rs index bfbbfd8d..e0163f63 100644 --- a/src/library/layout/columns.rs +++ b/src/library/layout/columns.rs @@ -17,7 +17,7 @@ impl ColumnsNode { #[property(resolve)] pub const GUTTER: Relative<RawLength> = Ratio::new(0.04).into(); - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { Ok(Content::block(Self { columns: args.expect("column count")?, child: args.expect("body")?, @@ -31,7 +31,7 @@ impl Layout for ColumnsNode { world: &dyn World, regions: &Regions, styles: StyleChain, - ) -> TypResult<Vec<Frame>> { + ) -> SourceResult<Vec<Frame>> { // Separating the infinite space into infinite columns does not make // much sense. if !regions.first.x.is_finite() { @@ -106,7 +106,7 @@ pub struct ColbreakNode; #[node] impl ColbreakNode { - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { let weak = args.named("weak")?.unwrap_or(false); Ok(Content::Colbreak { weak }) } diff --git a/src/library/layout/container.rs b/src/library/layout/container.rs index 66a43751..23556a2e 100644 --- a/src/library/layout/container.rs +++ b/src/library/layout/container.rs @@ -5,7 +5,7 @@ pub struct BoxNode; #[node] impl BoxNode { - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { let width = args.named("width")?; let height = args.named("height")?; let body: LayoutNode = args.eat()?.unwrap_or_default(); @@ -18,7 +18,7 @@ pub struct BlockNode; #[node] impl BlockNode { - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { Ok(Content::Block(args.eat()?.unwrap_or_default())) } } diff --git a/src/library/layout/flow.rs b/src/library/layout/flow.rs index 841b80aa..05c10789 100644 --- a/src/library/layout/flow.rs +++ b/src/library/layout/flow.rs @@ -28,7 +28,7 @@ impl Layout for FlowNode { world: &dyn World, regions: &Regions, styles: StyleChain, - ) -> TypResult<Vec<Frame>> { + ) -> SourceResult<Vec<Frame>> { let mut layouter = FlowLayouter::new(regions); for (child, map) in self.0.iter() { @@ -152,7 +152,7 @@ impl FlowLayouter { world: &dyn World, node: &LayoutNode, styles: StyleChain, - ) -> TypResult<()> { + ) -> SourceResult<()> { // Don't even try layouting into a full region. if self.regions.is_full() { self.finish_region(); diff --git a/src/library/layout/grid.rs b/src/library/layout/grid.rs index 3fde9c10..cd4fc6b4 100644 --- a/src/library/layout/grid.rs +++ b/src/library/layout/grid.rs @@ -13,7 +13,7 @@ pub struct GridNode { #[node] impl GridNode { - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { let columns = args.named("columns")?.unwrap_or_default(); let rows = args.named("rows")?.unwrap_or_default(); let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default(); @@ -36,7 +36,7 @@ impl Layout for GridNode { world: &dyn World, regions: &Regions, styles: StyleChain, - ) -> TypResult<Vec<Frame>> { + ) -> SourceResult<Vec<Frame>> { // Prepare grid layout by unifying content and gutter tracks. let layouter = GridLayouter::new( world, @@ -203,7 +203,7 @@ impl<'a> GridLayouter<'a> { } /// Determines the columns sizes and then layouts the grid row-by-row. - pub fn layout(mut self) -> TypResult<Vec<Frame>> { + pub fn layout(mut self) -> SourceResult<Vec<Frame>> { self.measure_columns()?; for y in 0 .. self.rows.len() { @@ -228,7 +228,7 @@ impl<'a> GridLayouter<'a> { } /// Determine all column sizes. - fn measure_columns(&mut self) -> TypResult<()> { + fn measure_columns(&mut self) -> SourceResult<()> { // Sum of sizes of resolved relative tracks. let mut rel = Length::zero(); @@ -275,7 +275,10 @@ impl<'a> GridLayouter<'a> { } /// Measure the size that is available to auto columns. - fn measure_auto_columns(&mut self, available: Length) -> TypResult<(Length, usize)> { + fn measure_auto_columns( + &mut self, + available: Length, + ) -> SourceResult<(Length, usize)> { let mut auto = Length::zero(); let mut count = 0; @@ -355,7 +358,7 @@ impl<'a> GridLayouter<'a> { /// Layout a row with automatic height. Such a row may break across multiple /// regions. - fn layout_auto_row(&mut self, y: usize) -> TypResult<()> { + fn layout_auto_row(&mut self, y: usize) -> SourceResult<()> { let mut resolved: Vec<Length> = vec![]; // Determine the size for each region of the row. @@ -423,7 +426,11 @@ impl<'a> GridLayouter<'a> { /// Layout a row with relative height. Such a row cannot break across /// multiple regions, but it may force a region break. - fn layout_relative_row(&mut self, v: Relative<RawLength>, y: usize) -> TypResult<()> { + fn layout_relative_row( + &mut self, + v: Relative<RawLength>, + y: usize, + ) -> SourceResult<()> { let resolved = v.resolve(self.styles).relative_to(self.regions.base.y); let frame = self.layout_single_row(resolved, y)?; @@ -444,7 +451,7 @@ impl<'a> GridLayouter<'a> { } /// Layout a row with fixed height and return its frame. - fn layout_single_row(&mut self, height: Length, y: usize) -> TypResult<Frame> { + fn layout_single_row(&mut self, height: Length, y: usize) -> SourceResult<Frame> { let mut output = Frame::new(Size::new(self.used.x, height)); let mut pos = Point::zero(); @@ -483,7 +490,7 @@ impl<'a> GridLayouter<'a> { &mut self, heights: &[Length], y: usize, - ) -> TypResult<Vec<Frame>> { + ) -> SourceResult<Vec<Frame>> { // Prepare frames. let mut outputs: Vec<_> = heights .iter() @@ -535,7 +542,7 @@ impl<'a> GridLayouter<'a> { } /// Finish rows for one region. - fn finish_region(&mut self) -> TypResult<()> { + fn finish_region(&mut self) -> SourceResult<()> { // Determine the size of the grid in this region, expanding fully if // there are fr rows. let mut size = self.used; diff --git a/src/library/layout/pad.rs b/src/library/layout/pad.rs index 72235ccd..983bfa11 100644 --- a/src/library/layout/pad.rs +++ b/src/library/layout/pad.rs @@ -11,7 +11,7 @@ pub struct PadNode { #[node] impl PadNode { - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { let all = args.named("rest")?.or(args.find()?); let x = args.named("x")?; let y = args.named("y")?; @@ -31,7 +31,7 @@ impl Layout for PadNode { world: &dyn World, regions: &Regions, styles: StyleChain, - ) -> TypResult<Vec<Frame>> { + ) -> SourceResult<Vec<Frame>> { // Layout child into padded regions. let padding = self.padding.resolve(styles); let pod = regions.map(|size| shrink(size, padding)); diff --git a/src/library/layout/page.rs b/src/library/layout/page.rs index 6e43c4ef..ba597263 100644 --- a/src/library/layout/page.rs +++ b/src/library/layout/page.rs @@ -41,7 +41,7 @@ impl PageNode { #[property(referenced)] pub const FOREGROUND: Marginal = Marginal::None; - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { Ok(Content::Page(Self(args.expect("body")?))) } @@ -60,7 +60,7 @@ impl PageNode { world: &dyn World, mut page: usize, styles: StyleChain, - ) -> TypResult<Vec<Frame>> { + ) -> SourceResult<Vec<Frame>> { // When one of the lengths is infinite the page fits its content along // that axis. let width = styles.get(Self::WIDTH).unwrap_or(Length::inf()); @@ -159,7 +159,7 @@ pub struct PagebreakNode; #[node] impl PagebreakNode { - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { let weak = args.named("weak")?.unwrap_or(false); Ok(Content::Pagebreak { weak }) } @@ -178,7 +178,11 @@ pub enum Marginal { impl Marginal { /// Resolve the marginal based on the page number. - pub fn resolve(&self, world: &dyn World, page: usize) -> TypResult<Option<Content>> { + pub fn resolve( + &self, + world: &dyn World, + page: usize, + ) -> SourceResult<Option<Content>> { Ok(match self { Self::None => None, Self::Content(content) => Some(content.clone()), diff --git a/src/library/layout/place.rs b/src/library/layout/place.rs index bb3aac2d..862c969e 100644 --- a/src/library/layout/place.rs +++ b/src/library/layout/place.rs @@ -7,7 +7,7 @@ pub struct PlaceNode(pub LayoutNode); #[node] impl PlaceNode { - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { let aligns = args.find()?.unwrap_or(Spec::with_x(Some(RawAlign::Start))); let dx = args.named("dx")?.unwrap_or_default(); let dy = args.named("dy")?.unwrap_or_default(); @@ -24,7 +24,7 @@ impl Layout for PlaceNode { world: &dyn World, regions: &Regions, styles: StyleChain, - ) -> TypResult<Vec<Frame>> { + ) -> SourceResult<Vec<Frame>> { let out_of_flow = self.out_of_flow(); // The pod is the base area of the region because for absolute diff --git a/src/library/layout/spacing.rs b/src/library/layout/spacing.rs index e435e60c..0c5cbb92 100644 --- a/src/library/layout/spacing.rs +++ b/src/library/layout/spacing.rs @@ -8,7 +8,7 @@ pub struct HNode; #[node] impl HNode { - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { let amount = args.expect("spacing")?; let weak = args.named("weak")?.unwrap_or(false); Ok(Content::Horizontal { amount, weak }) @@ -20,7 +20,7 @@ pub struct VNode; #[node] impl VNode { - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { let amount = args.expect("spacing")?; let weak = args.named("weak")?.unwrap_or(false); Ok(Content::Vertical { amount, weak, generated: false }) diff --git a/src/library/layout/stack.rs b/src/library/layout/stack.rs index d07dc35e..a9fc1621 100644 --- a/src/library/layout/stack.rs +++ b/src/library/layout/stack.rs @@ -15,7 +15,7 @@ pub struct StackNode { #[node] impl StackNode { - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { Ok(Content::block(Self { dir: args.named("dir")?.unwrap_or(Dir::TTB), spacing: args.named("spacing")?, @@ -30,7 +30,7 @@ impl Layout for StackNode { world: &dyn World, regions: &Regions, styles: StyleChain, - ) -> TypResult<Vec<Frame>> { + ) -> SourceResult<Vec<Frame>> { let mut layouter = StackLayouter::new(self.dir, regions, styles); // Spacing to insert before the next node. @@ -171,7 +171,7 @@ impl<'a> StackLayouter<'a> { world: &dyn World, node: &LayoutNode, styles: StyleChain, - ) -> TypResult<()> { + ) -> SourceResult<()> { if self.regions.is_full() { self.finish_region(); } diff --git a/src/library/math/mod.rs b/src/library/math/mod.rs index ed98ab1c..d71f6976 100644 --- a/src/library/math/mod.rs +++ b/src/library/math/mod.rs @@ -28,7 +28,7 @@ impl MathNode { #[property(resolve, shorthand(around))] pub const BELOW: Option<BlockSpacing> = Some(Ratio::one().into()); - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { Ok(Content::show(Self { formula: args.expect("formula")?, display: args.named("display")?.unwrap_or(false), @@ -48,7 +48,7 @@ impl Show for MathNode { } } - fn realize(&self, _: &dyn World, styles: StyleChain) -> TypResult<Content> { + fn realize(&self, _: &dyn World, styles: StyleChain) -> SourceResult<Content> { let node = self::rex::RexNode { tex: self.formula.clone(), display: self.display, @@ -67,7 +67,7 @@ impl Show for MathNode { _: &dyn World, styles: StyleChain, mut realized: Content, - ) -> TypResult<Content> { + ) -> SourceResult<Content> { let mut map = StyleMap::new(); map.set_family(styles.get(Self::FAMILY).clone(), styles); diff --git a/src/library/math/rex.rs b/src/library/math/rex.rs index 7bfdeb7a..76ba5177 100644 --- a/src/library/math/rex.rs +++ b/src/library/math/rex.rs @@ -25,13 +25,13 @@ impl Layout for RexNode { world: &dyn World, _: &Regions, styles: StyleChain, - ) -> TypResult<Vec<Frame>> { + ) -> SourceResult<Vec<Frame>> { // Load the font. let span = self.tex.span; let font = world .book() .select(self.family.as_str(), variant(styles)) - .and_then(|id| world.font(id).ok()) + .and_then(|id| world.font(id)) .ok_or("failed to find math font") .at(span)?; diff --git a/src/library/prelude.rs b/src/library/prelude.rs index a69d9791..48eebaf6 100644 --- a/src/library/prelude.rs +++ b/src/library/prelude.rs @@ -8,9 +8,7 @@ pub use std::sync::Arc; pub use typst_macros::node; -pub use crate::diag::{ - failed_to_load, with_alternative, At, Error, StrResult, TypError, TypResult, -}; +pub use crate::diag::{with_alternative, At, SourceError, SourceResult, StrResult}; pub use crate::eval::{ Arg, Args, Array, Cast, Dict, Dynamic, Func, Node, RawAlign, RawLength, RawStroke, Scope, Smart, Value, Vm, diff --git a/src/library/structure/doc.rs b/src/library/structure/doc.rs index cabdb4dc..ba848b64 100644 --- a/src/library/structure/doc.rs +++ b/src/library/structure/doc.rs @@ -7,7 +7,11 @@ pub struct DocNode(pub StyleVec<PageNode>); impl DocNode { /// Layout the document into a sequence of frames, one per page. - pub fn layout(&self, world: &dyn World, styles: StyleChain) -> TypResult<Vec<Frame>> { + pub fn layout( + &self, + world: &dyn World, + styles: StyleChain, + ) -> SourceResult<Vec<Frame>> { let mut frames = vec![]; for (page, map) in self.0.iter() { let number = 1 + frames.len(); diff --git a/src/library/structure/heading.rs b/src/library/structure/heading.rs index c177481f..855c0503 100644 --- a/src/library/structure/heading.rs +++ b/src/library/structure/heading.rs @@ -60,7 +60,7 @@ impl HeadingNode { /// Whether the heading is numbered. pub const NUMBERED: bool = true; - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { Ok(Content::show(Self { body: args.expect("body")?, level: args.named("level")?.unwrap_or(NonZeroUsize::new(1).unwrap()), @@ -82,7 +82,7 @@ impl Show for HeadingNode { } } - fn realize(&self, _: &dyn World, _: StyleChain) -> TypResult<Content> { + fn realize(&self, _: &dyn World, _: StyleChain) -> SourceResult<Content> { Ok(Content::block(self.body.clone())) } @@ -91,7 +91,7 @@ impl Show for HeadingNode { world: &dyn World, styles: StyleChain, mut realized: Content, - ) -> TypResult<Content> { + ) -> SourceResult<Content> { macro_rules! resolve { ($key:expr) => { styles.get($key).resolve(world, self.level)? @@ -149,7 +149,7 @@ pub enum Leveled<T> { impl<T: Cast + Clone> Leveled<T> { /// Resolve the value based on the level. - pub fn resolve(&self, world: &dyn World, level: NonZeroUsize) -> TypResult<T> { + pub fn resolve(&self, world: &dyn World, level: NonZeroUsize) -> SourceResult<T> { Ok(match self { Self::Value(value) => value.clone(), Self::Mapping(mapping) => mapping(level), diff --git a/src/library/structure/list.rs b/src/library/structure/list.rs index e9365cd6..f63374f3 100644 --- a/src/library/structure/list.rs +++ b/src/library/structure/list.rs @@ -56,7 +56,7 @@ impl<const L: ListKind> ListNode<L> { #[property(resolve)] pub const SPACING: BlockSpacing = Ratio::one().into(); - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { Ok(Content::show(Self { start: args.named("start")?.unwrap_or(1), tight: args.named("tight")?.unwrap_or(true), @@ -100,7 +100,7 @@ impl<const L: ListKind> Show for ListNode<L> { } } - fn realize(&self, world: &dyn World, styles: StyleChain) -> TypResult<Content> { + fn realize(&self, world: &dyn World, styles: StyleChain) -> SourceResult<Content> { let mut cells = vec![]; let mut number = self.start; @@ -148,7 +148,7 @@ impl<const L: ListKind> Show for ListNode<L> { _: &dyn World, styles: StyleChain, realized: Content, - ) -> TypResult<Content> { + ) -> SourceResult<Content> { let mut above = styles.get(Self::ABOVE); let mut below = styles.get(Self::BELOW); @@ -211,7 +211,7 @@ impl Label { world: &dyn World, kind: ListKind, number: usize, - ) -> TypResult<Content> { + ) -> SourceResult<Content> { Ok(match self { Self::Default => match kind { UNORDERED => Content::Text('•'.into()), diff --git a/src/library/structure/reference.rs b/src/library/structure/reference.rs index 22dbec01..5d1dab38 100644 --- a/src/library/structure/reference.rs +++ b/src/library/structure/reference.rs @@ -6,7 +6,7 @@ pub struct RefNode(pub EcoString); #[node(showable)] impl RefNode { - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { Ok(Content::show(Self(args.expect("label")?))) } } @@ -22,7 +22,7 @@ impl Show for RefNode { } } - fn realize(&self, _: &dyn World, _: StyleChain) -> TypResult<Content> { + fn realize(&self, _: &dyn World, _: StyleChain) -> SourceResult<Content> { Ok(Content::Text(format_eco!("@{}", self.0))) } } diff --git a/src/library/structure/table.rs b/src/library/structure/table.rs index 08fa5386..f1ca7e03 100644 --- a/src/library/structure/table.rs +++ b/src/library/structure/table.rs @@ -30,7 +30,7 @@ impl TableNode { #[property(resolve, shorthand(around))] pub const BELOW: Option<BlockSpacing> = Some(Ratio::one().into()); - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { let columns = args.named("columns")?.unwrap_or_default(); let rows = args.named("rows")?.unwrap_or_default(); let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default(); @@ -72,7 +72,7 @@ impl Show for TableNode { } } - fn realize(&self, world: &dyn World, styles: StyleChain) -> TypResult<Content> { + fn realize(&self, world: &dyn World, styles: StyleChain) -> SourceResult<Content> { let fill = styles.get(Self::FILL); let stroke = styles.get(Self::STROKE).map(RawStroke::unwrap_or_default); let padding = styles.get(Self::PADDING); @@ -98,7 +98,7 @@ impl Show for TableNode { Ok(child) }) - .collect::<TypResult<_>>()?; + .collect::<SourceResult<_>>()?; Ok(Content::block(GridNode { tracks: self.tracks.clone(), @@ -113,7 +113,7 @@ impl Show for TableNode { _: &dyn World, styles: StyleChain, realized: Content, - ) -> TypResult<Content> { + ) -> SourceResult<Content> { Ok(realized.spaced(styles.get(Self::ABOVE), styles.get(Self::BELOW))) } } @@ -129,7 +129,7 @@ pub enum Celled<T> { impl<T: Cast + Clone> Celled<T> { /// Resolve the value based on the cell position. - pub fn resolve(&self, world: &dyn World, x: usize, y: usize) -> TypResult<T> { + pub fn resolve(&self, world: &dyn World, x: usize, y: usize) -> SourceResult<T> { Ok(match self { Self::Value(value) => value.clone(), Self::Func(func, span) => { diff --git a/src/library/text/deco.rs b/src/library/text/deco.rs index c58148b4..3d030d45 100644 --- a/src/library/text/deco.rs +++ b/src/library/text/deco.rs @@ -34,7 +34,7 @@ impl<const L: DecoLine> DecoNode<L> { /// with the glyphs. Does not apply to strikethrough. pub const EVADE: bool = true; - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { Ok(Content::show(Self(args.expect("body")?))) } } @@ -48,7 +48,7 @@ impl<const L: DecoLine> Show for DecoNode<L> { dict! { "body" => Value::Content(self.0.clone()) } } - fn realize(&self, _: &dyn World, styles: StyleChain) -> TypResult<Content> { + fn realize(&self, _: &dyn World, styles: StyleChain) -> SourceResult<Content> { Ok(self.0.clone().styled(TextNode::DECO, Decoration { line: L, stroke: styles.get(Self::STROKE).unwrap_or_default(), diff --git a/src/library/text/link.rs b/src/library/text/link.rs index 7d5c3109..f89bbd67 100644 --- a/src/library/text/link.rs +++ b/src/library/text/link.rs @@ -18,7 +18,7 @@ impl LinkNode { /// Whether to underline the link. pub const UNDERLINE: Smart<bool> = Smart::Auto; - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { Ok(Content::show({ let dest = args.expect::<Destination>("destination")?; let body = match dest { @@ -64,7 +64,7 @@ impl Show for LinkNode { } } - fn realize(&self, _: &dyn World, _: StyleChain) -> TypResult<Content> { + fn realize(&self, _: &dyn World, _: StyleChain) -> SourceResult<Content> { Ok(self.body.clone().unwrap_or_else(|| match &self.dest { Destination::Url(url) => { let mut text = url.as_str(); @@ -83,7 +83,7 @@ impl Show for LinkNode { _: &dyn World, styles: StyleChain, mut realized: Content, - ) -> TypResult<Content> { + ) -> SourceResult<Content> { let mut map = StyleMap::new(); map.set(TextNode::LINK, Some(self.dest.clone())); diff --git a/src/library/text/mod.rs b/src/library/text/mod.rs index be586874..55b866cb 100644 --- a/src/library/text/mod.rs +++ b/src/library/text/mod.rs @@ -128,7 +128,7 @@ impl TextNode { #[property(skip, fold)] pub const DECO: Decoration = vec![]; - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { // The text constructor is special: It doesn't create a text node. // Instead, it leaves the passed argument structurally unchanged, but // styles all text in it. @@ -422,17 +422,17 @@ impl Fold for Vec<(Tag, u32)> { } /// Convert a string or content to lowercase. -pub fn lower(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn lower(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { case(Case::Lower, args) } /// Convert a string or content to uppercase. -pub fn upper(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn upper(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { case(Case::Upper, args) } /// Change the case of text. -fn case(case: Case, args: &mut Args) -> TypResult<Value> { +fn case(case: Case, args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect("string or content")?; Ok(match v { Value::Str(v) => Value::Str(case.apply(&v).into()), @@ -461,7 +461,7 @@ impl Case { } /// Display text in small capitals. -pub fn smallcaps(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn smallcaps(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let body: Content = args.expect("content")?; Ok(Value::Content(body.styled(TextNode::SMALLCAPS, true))) } @@ -493,7 +493,7 @@ pub struct StrongNode(pub Content); #[node(showable)] impl StrongNode { - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { Ok(Content::show(Self(args.expect("body")?))) } } @@ -507,7 +507,7 @@ impl Show for StrongNode { dict! { "body" => Value::Content(self.0.clone()) } } - fn realize(&self, _: &dyn World, _: StyleChain) -> TypResult<Content> { + fn realize(&self, _: &dyn World, _: StyleChain) -> SourceResult<Content> { Ok(self.0.clone().styled(TextNode::BOLD, Toggle)) } } @@ -518,7 +518,7 @@ pub struct EmphNode(pub Content); #[node(showable)] impl EmphNode { - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { Ok(Content::show(Self(args.expect("body")?))) } } @@ -532,7 +532,7 @@ impl Show for EmphNode { dict! { "body" => Value::Content(self.0.clone()) } } - fn realize(&self, _: &dyn World, _: StyleChain) -> TypResult<Content> { + fn realize(&self, _: &dyn World, _: StyleChain) -> SourceResult<Content> { Ok(self.0.clone().styled(TextNode::ITALIC, Toggle)) } } diff --git a/src/library/text/par.rs b/src/library/text/par.rs index e8282ef1..00a1e034 100644 --- a/src/library/text/par.rs +++ b/src/library/text/par.rs @@ -49,7 +49,7 @@ impl ParNode { #[property(resolve)] pub const LINEBREAKS: Smart<Linebreaks> = Smart::Auto; - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { // The paragraph constructor is special: It doesn't create a paragraph // node. Instead, it just ensures that the passed content lives is in a // separate paragraph and styles it. @@ -67,7 +67,7 @@ impl Layout for ParNode { world: &dyn World, regions: &Regions, styles: StyleChain, - ) -> TypResult<Vec<Frame>> { + ) -> SourceResult<Vec<Frame>> { // Collect all text into one string for BiDi analysis. let (text, segments) = collect(self, &styles); @@ -170,7 +170,7 @@ pub struct ParbreakNode; #[node] impl ParbreakNode { - fn construct(_: &mut Vm, _: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, _: &mut Args) -> SourceResult<Content> { Ok(Content::Parbreak) } } @@ -180,7 +180,7 @@ pub struct LinebreakNode; #[node] impl LinebreakNode { - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { let justified = args.named("justified")?.unwrap_or(false); Ok(Content::Linebreak { justified }) } @@ -502,7 +502,7 @@ fn prepare<'a>( segments: Vec<(Segment<'a>, StyleChain<'a>)>, regions: &Regions, styles: StyleChain<'a>, -) -> TypResult<Preparation<'a>> { +) -> SourceResult<Preparation<'a>> { let bidi = BidiInfo::new(&text, match styles.get(TextNode::DIR) { Dir::LTR => Some(Level::ltr()), Dir::RTL => Some(Level::rtl()), @@ -1025,7 +1025,7 @@ fn stack( world: &dyn World, lines: &[Line], regions: &Regions, -) -> TypResult<Vec<Frame>> { +) -> SourceResult<Vec<Frame>> { // Determine the paragraph's width: Full width of the region if we // should expand or there's fractional spacing, fit-to-width otherwise. let mut width = regions.first.x; @@ -1076,7 +1076,7 @@ fn commit( line: &Line, regions: &Regions, width: Length, -) -> TypResult<Frame> { +) -> SourceResult<Frame> { let mut remaining = width - line.width; let mut offset = Length::zero(); diff --git a/src/library/text/raw.rs b/src/library/text/raw.rs index c729fa40..5bce2a90 100644 --- a/src/library/text/raw.rs +++ b/src/library/text/raw.rs @@ -35,7 +35,7 @@ impl RawNode { #[property(resolve, shorthand(around))] pub const BELOW: Option<BlockSpacing> = Some(Ratio::one().into()); - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { Ok(Content::show(Self { text: args.expect("text")?, block: args.named("block")?.unwrap_or(false), @@ -59,7 +59,7 @@ impl Show for RawNode { } } - fn realize(&self, _: &dyn World, styles: StyleChain) -> TypResult<Content> { + fn realize(&self, _: &dyn World, styles: StyleChain) -> SourceResult<Content> { let lang = styles.get(Self::LANG).as_ref().map(|s| s.to_lowercase()); let foreground = THEME .settings @@ -114,7 +114,7 @@ impl Show for RawNode { _: &dyn World, styles: StyleChain, mut realized: Content, - ) -> TypResult<Content> { + ) -> SourceResult<Content> { let mut map = StyleMap::new(); map.set_family(styles.get(Self::FAMILY).clone(), styles); map.set(TextNode::OVERHANG, false); diff --git a/src/library/text/repeat.rs b/src/library/text/repeat.rs index c2a0de70..78a21069 100644 --- a/src/library/text/repeat.rs +++ b/src/library/text/repeat.rs @@ -6,7 +6,7 @@ pub struct RepeatNode(pub LayoutNode); #[node] impl RepeatNode { - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { Ok(Content::inline(Self(args.expect("body")?))) } } @@ -17,7 +17,7 @@ impl Layout for RepeatNode { world: &dyn World, regions: &Regions, styles: StyleChain, - ) -> TypResult<Vec<Frame>> { + ) -> SourceResult<Vec<Frame>> { // The actual repeating happens directly in the paragraph. self.0.layout(world, regions, styles) } diff --git a/src/library/text/shaping.rs b/src/library/text/shaping.rs index 6e505702..c1d0341b 100644 --- a/src/library/text/shaping.rs +++ b/src/library/text/shaping.rs @@ -165,7 +165,7 @@ impl<'a> ShapedText<'a> { if let Some(font) = world .book() .select(family, self.variant) - .and_then(|id| world.font(id).ok()) + .and_then(|id| world.font(id)) { expand(&font); break; @@ -223,7 +223,7 @@ impl<'a> ShapedText<'a> { let font = world .book() .select(family, self.variant) - .and_then(|id| world.font(id).ok())?; + .and_then(|id| world.font(id))?; let ttf = font.ttf(); let glyph_id = ttf.glyph_index('-')?; let x_advance = font.to_em(ttf.glyph_hor_advance(glyph_id)?); @@ -371,7 +371,7 @@ fn shape_segment<'a>( let book = ctx.world.book(); let mut selection = families.find_map(|family| { book.select(family, ctx.variant) - .and_then(|id| ctx.world.font(id).ok()) + .and_then(|id| ctx.world.font(id)) .filter(|font| !ctx.used.contains(font)) }); @@ -380,7 +380,7 @@ fn shape_segment<'a>( let first = ctx.used.first().map(Font::info); selection = book .select_fallback(first, ctx.variant, text) - .and_then(|id| ctx.world.font(id).ok()) + .and_then(|id| ctx.world.font(id)) .filter(|font| !ctx.used.contains(font)); } diff --git a/src/library/text/shift.rs b/src/library/text/shift.rs index 5da36da1..b359c5ed 100644 --- a/src/library/text/shift.rs +++ b/src/library/text/shift.rs @@ -28,7 +28,7 @@ impl<const S: ScriptKind> ShiftNode<S> { /// The font size for synthetic sub- and superscripts. pub const SIZE: TextSize = TextSize(Em::new(0.6).into()); - fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Content> { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { Ok(Content::show(Self(args.expect("body")?))) } } @@ -42,7 +42,7 @@ impl<const S: ScriptKind> Show for ShiftNode<S> { dict! { "body" => Value::Content(self.0.clone()) } } - fn realize(&self, world: &dyn World, styles: StyleChain) -> TypResult<Content> { + fn realize(&self, world: &dyn World, styles: StyleChain) -> SourceResult<Content> { let mut transformed = None; if styles.get(Self::TYPOGRAPHIC) { if let Some(text) = search_text(&self.0, S) { @@ -96,7 +96,7 @@ fn is_shapable(world: &dyn World, text: &str, styles: StyleChain) -> bool { if let Some(font) = world .book() .select(family.as_str(), variant(styles)) - .and_then(|id| world.font(id).ok()) + .and_then(|id| world.font(id)) { return text.chars().all(|c| font.ttf().glyph_index(c).is_some()); } diff --git a/src/library/utility/color.rs b/src/library/utility/color.rs index a7d55d1c..a5a5704d 100644 --- a/src/library/utility/color.rs +++ b/src/library/utility/color.rs @@ -3,13 +3,13 @@ use std::str::FromStr; use crate::library::prelude::*; /// Create a grayscale color. -pub fn luma(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn luma(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Component(luma) = args.expect("gray component")?; Ok(Value::Color(LumaColor::new(luma).into())) } /// Create an RGB(A) color. -pub fn rgb(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn rgb(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { Ok(Value::Color( if let Some(string) = args.find::<Spanned<EcoString>>()? { match RgbaColor::from_str(&string.v) { @@ -27,7 +27,7 @@ pub fn rgb(_: &mut Vm, args: &mut Args) -> TypResult<Value> { } /// Create a CMYK color. -pub fn cmyk(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn cmyk(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let RatioComponent(c) = args.expect("cyan component")?; let RatioComponent(m) = args.expect("magenta component")?; let RatioComponent(y) = args.expect("yellow component")?; diff --git a/src/library/utility/data.rs b/src/library/utility/data.rs index 59f3d351..1ae8949a 100644 --- a/src/library/utility/data.rs +++ b/src/library/utility/data.rs @@ -1,30 +1,43 @@ +use std::fmt::Write; + use crate::library::prelude::*; /// Read structured data from a CSV file. -pub fn csv(vm: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn csv(vm: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v: path, span } = args.expect::<Spanned<EcoString>>("path to csv file")?; let path = vm.locate(&path).at(span)?; - let try_load = || -> io::Result<Value> { - let data = vm.world.file(&path)?; + let data = vm.world.file(&path).at(span)?; - let mut builder = csv::ReaderBuilder::new(); - builder.has_headers(false); + let mut builder = csv::ReaderBuilder::new(); + builder.has_headers(false); - let mut reader = builder.from_reader(data.as_slice()); - let mut vec = vec![]; + let mut reader = builder.from_reader(data.as_slice()); + let mut vec = vec![]; - for result in reader.records() { - vec.push(Value::Array( - result?.iter().map(|field| Value::Str(field.into())).collect(), - )) - } + for result in reader.records() { + let row = result.map_err(format_csv_error).at(span)?; + let array = row.iter().map(|field| Value::Str(field.into())).collect(); + vec.push(Value::Array(array)) + } - Ok(Value::Array(Array::from_vec(vec))) - }; + Ok(Value::Array(Array::from_vec(vec))) +} - try_load() - .map_err(|err| failed_to_load("csv file", &path, err)) - .at(span) +/// Format the user-facing CSV error message. +fn format_csv_error(error: csv::Error) -> String { + match error.kind() { + csv::ErrorKind::Utf8 { .. } => "file is not valid utf-8".into(), + csv::ErrorKind::UnequalLengths { pos, expected_len, len } => { + let mut msg = format!( + "failed to parse csv file: found {len} instead of {expected_len} fields" + ); + if let Some(pos) = pos { + write!(msg, " in line {}", pos.line()).unwrap(); + } + msg + } + _ => "failed to parse csv file".into(), + } } diff --git a/src/library/utility/math.rs b/src/library/utility/math.rs index 47648282..7c3af490 100644 --- a/src/library/utility/math.rs +++ b/src/library/utility/math.rs @@ -3,7 +3,7 @@ use std::cmp::Ordering; use crate::library::prelude::*; /// Convert a value to an integer. -pub fn int(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn int(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect("value")?; Ok(Value::Int(match v { Value::Bool(v) => v as i64, @@ -18,7 +18,7 @@ pub fn int(_: &mut Vm, args: &mut Args) -> TypResult<Value> { } /// Convert a value to a float. -pub fn float(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn float(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect("value")?; Ok(Value::Float(match v { Value::Int(v) => v as f64, @@ -32,7 +32,7 @@ pub fn float(_: &mut Vm, args: &mut Args) -> TypResult<Value> { } /// The absolute value of a numeric value. -pub fn abs(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn abs(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect("numeric value")?; Ok(match v { Value::Int(v) => Value::Int(v.abs()), @@ -48,17 +48,17 @@ pub fn abs(_: &mut Vm, args: &mut Args) -> TypResult<Value> { } /// The minimum of a sequence of values. -pub fn min(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn min(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { minmax(args, Ordering::Less) } /// The maximum of a sequence of values. -pub fn max(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn max(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { minmax(args, Ordering::Greater) } /// Find the minimum or maximum of a sequence of values. -fn minmax(args: &mut Args, goal: Ordering) -> TypResult<Value> { +fn minmax(args: &mut Args, goal: Ordering) -> SourceResult<Value> { let mut extremum = args.expect::<Value>("value")?; for Spanned { v, span } in args.all::<Spanned<Value>>()? { match v.partial_cmp(&extremum) { @@ -79,17 +79,17 @@ fn minmax(args: &mut Args, goal: Ordering) -> TypResult<Value> { } /// Whether an integer is even. -pub fn even(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn even(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { Ok(Value::Bool(args.expect::<i64>("integer")? % 2 == 0)) } /// Whether an integer is odd. -pub fn odd(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn odd(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { Ok(Value::Bool(args.expect::<i64>("integer")? % 2 != 0)) } /// The modulo of two numbers. -pub fn mod_(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn mod_(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v: v1, span: span1 } = args.expect("integer or float")?; let Spanned { v: v2, span: span2 } = args.expect("integer or float")?; @@ -119,7 +119,7 @@ pub fn mod_(_: &mut Vm, args: &mut Args) -> TypResult<Value> { } /// Create a sequence of numbers. -pub fn range(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn range(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let first = args.expect::<i64>("end")?; let (start, end) = match args.eat::<i64>()? { Some(second) => (first, second), diff --git a/src/library/utility/mod.rs b/src/library/utility/mod.rs index 40a107ba..3fc413f7 100644 --- a/src/library/utility/mod.rs +++ b/src/library/utility/mod.rs @@ -15,12 +15,12 @@ use crate::library::prelude::*; use crate::source::Source; /// The name of a value's type. -pub fn type_(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn type_(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { Ok(args.expect::<Value>("value")?.type_name().into()) } /// Ensure that a condition is fulfilled. -pub fn assert(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn assert(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect::<Spanned<bool>>("condition")?; if !v { bail!(span, "assertion failed"); @@ -29,7 +29,7 @@ pub fn assert(_: &mut Vm, args: &mut Args) -> TypResult<Value> { } /// Evaluate a string as Typst markup. -pub fn eval(vm: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn eval(vm: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v: text, span } = args.expect::<Spanned<String>>("source")?; // Parse the source and set a synthetic span for all nodes. @@ -44,7 +44,7 @@ pub fn eval(vm: &mut Vm, args: &mut Args) -> TypResult<Value> { // Handle control flow. if let Some(flow) = sub.flow { - return Err(flow.forbidden()); + bail!(flow.forbidden()); } Ok(Value::Content(result?)) diff --git a/src/library/utility/string.rs b/src/library/utility/string.rs index d825d84b..91a990a9 100644 --- a/src/library/utility/string.rs +++ b/src/library/utility/string.rs @@ -2,12 +2,12 @@ use crate::eval::Regex; use crate::library::prelude::*; /// The string representation of a value. -pub fn repr(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn repr(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { Ok(args.expect::<Value>("value")?.repr().into()) } /// Convert a value to a string. -pub fn str(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn str(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect("value")?; Ok(Value::Str(match v { Value::Int(v) => format_str!("{}", v), @@ -18,33 +18,33 @@ pub fn str(_: &mut Vm, args: &mut Args) -> TypResult<Value> { } /// Create blind text. -pub fn lorem(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn lorem(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let words: usize = args.expect("number of words")?; Ok(Value::Str(lipsum::lipsum(words).into())) } /// Create a regular expression. -pub fn regex(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn regex(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect::<Spanned<EcoString>>("regular expression")?; Ok(Regex::new(&v).at(span)?.into()) } /// Converts an integer into one or multiple letters. -pub fn letter(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn letter(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { numbered(Numbering::Letter, args) } /// Converts an integer into a roman numeral. -pub fn roman(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn roman(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { numbered(Numbering::Roman, args) } /// Convert a number into a symbol. -pub fn symbol(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn symbol(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { numbered(Numbering::Symbol, args) } -fn numbered(numbering: Numbering, args: &mut Args) -> TypResult<Value> { +fn numbered(numbering: Numbering, args: &mut Args) -> SourceResult<Value> { let n = args.expect::<usize>("non-negative integer")?; Ok(Value::Str(numbering.apply(n).into())) } |
