From 1711b67877ce5c290e049775c340c9324f15341e Mon Sep 17 00:00:00 2001 From: Laurenz Date: Thu, 11 Feb 2021 17:33:13 +0100 Subject: [PATCH] =?UTF-8?q?Move=20all=20pretty=20printing=20into=20one=20m?= =?UTF-8?q?odule=20and=20pretty=20print=20values=20=F0=9F=A6=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/diag.rs | 6 +- src/env.rs | 11 + src/eval/mod.rs | 6 +- src/eval/value.rs | 120 ++----- src/exec/mod.rs | 26 +- src/parse/lines.rs | 6 +- src/parse/resolve.rs | 4 +- src/prelude.rs | 2 +- src/pretty.rs | 609 +++++++++++++++++++++++++++++++- src/syntax/expr.rs | 262 -------------- src/syntax/ident.rs | 7 - src/syntax/mod.rs | 128 ------- src/syntax/node.rs | 92 ----- src/syntax/span.rs | 75 +--- tests/lang/ref/call-bracket.png | Bin 1700 -> 1611 bytes tests/typeset.rs | 7 +- 16 files changed, 678 insertions(+), 683 deletions(-) diff --git a/src/diag.rs b/src/diag.rs index 07fd7b509..b1c477a55 100644 --- a/src/diag.rs +++ b/src/diag.rs @@ -2,7 +2,7 @@ //! //! Errors are never fatal, the document will always compile and yield a layout. -use crate::syntax::SpanVec; +use crate::syntax::Spanned; use std::fmt::{self, Display, Formatter}; /// The result of some pass: Some output `T` and [`Feedback`] data. @@ -25,9 +25,9 @@ impl Pass { #[derive(Debug, Default, Clone, Eq, PartialEq)] pub struct Feedback { /// Diagnostics about the source code. - pub diags: SpanVec, + pub diags: Vec>, /// Decorations of the source code for semantic syntax highlighting. - pub decos: SpanVec, + pub decos: Vec>, } impl Feedback { diff --git a/src/env.rs b/src/env.rs index aaa04aa27..66cc5e191 100644 --- a/src/env.rs +++ b/src/env.rs @@ -7,6 +7,7 @@ use std::fs; use std::io::Cursor; use std::path::{Path, PathBuf}; +use fontdock::fs::FsSource; use image::io::Reader as ImageReader; use image::{DynamicImage, GenericImageView, ImageFormat}; @@ -21,6 +22,16 @@ pub struct Env { pub resources: ResourceLoader, } +impl Env { + /// Create an empty environment for testing purposes. + pub fn blank() -> Self { + Self { + fonts: FontLoader::new(Box::new(FsSource::new(vec![])), vec![]), + resources: ResourceLoader::new(), + } + } +} + /// Loads resource from the file system. pub struct ResourceLoader { paths: HashMap, diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 4f0beb34b..ec71f6896 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -377,11 +377,11 @@ impl Eval for ExprArgs { .map(|arg| match arg { ExprArg::Pos(expr) => ValueArg { name: None, - value: expr.eval(ctx).with_span(expr.span()), + value: Spanned::new(expr.eval(ctx), expr.span()), }, ExprArg::Named(Named { name, expr }) => ValueArg { - name: Some(name.string.clone().with_span(name.span)), - value: expr.eval(ctx).with_span(expr.span()), + name: Some(Spanned::new(name.string.clone(), name.span)), + value: Spanned::new(expr.eval(ctx), expr.span()), }, }) .collect(); diff --git a/src/eval/value.rs b/src/eval/value.rs index 94477aa5b..ab54bf538 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -97,44 +97,9 @@ impl Default for Value { } } -impl Pretty for Value { - fn pretty(&self, p: &mut Printer) { - match self { - Value::None => p.push_str("none"), - Value::Bool(v) => v.pretty(p), - Value::Int(v) => v.pretty(p), - Value::Float(v) => v.pretty(p), - Value::Length(v) => v.pretty(p), - Value::Angle(v) => v.pretty(p), - Value::Relative(v) => v.pretty(p), - Value::Linear(v) => v.pretty(p), - Value::Color(v) => v.pretty(p), - Value::Str(v) => v.pretty(p), - Value::Array(v) => v.pretty(p), - Value::Dict(v) => v.pretty(p), - Value::Template(v) => v.pretty(p), - Value::Func(v) => v.pretty(p), - Value::Args(v) => v.pretty(p), - Value::Any(v) => v.pretty(p), - Value::Error => p.push_str(""), - } - } -} - /// An array value: `(1, "hi", 12cm)`. pub type ValueArray = Vec; -impl Pretty for ValueArray { - fn pretty(&self, p: &mut Printer) { - p.push('('); - p.join(self, ", ", |item, p| item.pretty(p)); - if self.len() == 1 { - p.push(','); - } - p.push(')'); - } -} - /// A dictionary value: `(color: #f79143, pattern: dashed)`. pub type ValueDict = BTreeMap; @@ -157,16 +122,6 @@ impl Pretty for ValueDict { /// A template value: `[*Hi* there]`. pub type ValueTemplate = Vec; -impl Pretty for ValueTemplate { - fn pretty(&self, p: &mut Printer) { - p.push('['); - for part in self { - part.pretty(p); - } - p.push(']'); - } -} - /// One chunk of a template. /// /// Evaluating a template expression creates only a single chunk. Adding two @@ -185,16 +140,6 @@ pub enum TemplateNode { Any(TemplateAny), } -impl Pretty for TemplateNode { - fn pretty(&self, p: &mut Printer) { - match self { - // TODO: Pretty-print the values. - Self::Tree { tree, .. } => tree.pretty(p), - Self::Any(any) => any.pretty(p), - } - } -} - /// A reference-counted dynamic template node (can implement custom behaviour). #[derive(Clone)] pub struct TemplateAny { @@ -210,6 +155,12 @@ impl TemplateAny { { Self { name: name.into(), f: Rc::new(f) } } + + + /// The name of the template node. + pub fn name(&self) -> &str { + &self.name + } } impl PartialEq for TemplateAny { @@ -227,14 +178,6 @@ impl Deref for TemplateAny { } } -impl Pretty for TemplateAny { - fn pretty(&self, p: &mut Printer) { - p.push('<'); - p.push_str(&self.name); - p.push('>'); - } -} - impl Debug for TemplateAny { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.debug_struct("TemplateAny").finish() @@ -256,6 +199,11 @@ impl ValueFunc { { Self { name: name.into(), f: Rc::new(f) } } + + /// The name of the function. + pub fn name(&self) -> &str { + &self.name + } } impl PartialEq for ValueFunc { @@ -273,14 +221,6 @@ impl Deref for ValueFunc { } } -impl Pretty for ValueFunc { - fn pretty(&self, p: &mut Printer) { - p.push('<'); - p.push_str(&self.name); - p.push('>'); - } -} - impl Debug for ValueFunc { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.debug_struct("ValueFunc").field("name", &self.name).finish() @@ -417,14 +357,6 @@ impl ValueArgs { } } -impl Pretty for ValueArgs { - fn pretty(&self, p: &mut Printer) { - p.push('<'); - p.join(&self.items, ", ", |item, p| item.pretty(p)); - p.push('>'); - } -} - // This is a workaround because `-> impl Trait + 'a + 'b` does not work. // // See also: https://github.com/rust-lang/rust/issues/49431 @@ -451,16 +383,6 @@ impl ValueArg { } } -impl Pretty for ValueArg { - fn pretty(&self, p: &mut Printer) { - if let Some(name) = &self.name { - p.push_str(&name.v); - p.push_str(": "); - } - self.value.v.pretty(p); - } -} - /// A wrapper around a dynamic value. pub struct ValueAny(Box); @@ -510,18 +432,18 @@ impl PartialEq for ValueAny { } } -impl Pretty for ValueAny { - fn pretty(&self, p: &mut Printer) { - write!(p, "{}", self.0).unwrap(); - } -} - impl Debug for ValueAny { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.debug_tuple("ValueAny").field(&self.0).finish() } } +impl Display for ValueAny { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + Display::fmt(&self.0, f) + } +} + trait Bounds: Debug + Display + 'static { fn as_any(&self) -> &dyn Any; fn into_any(self: Box) -> Box; @@ -618,7 +540,7 @@ where match T::cast(value.v) { CastResult::Ok(t) => CastResult::Ok(t), CastResult::Warn(t, m) => CastResult::Warn(t, m), - CastResult::Err(v) => CastResult::Err(v.with_span(span)), + CastResult::Err(v) => CastResult::Err(Spanned::new(v, span)), } } } @@ -630,9 +552,9 @@ where fn cast(value: Spanned) -> CastResult> { let span = value.span; match T::cast(value.v) { - CastResult::Ok(t) => CastResult::Ok(t.with_span(span)), - CastResult::Warn(t, m) => CastResult::Warn(t.with_span(span), m), - CastResult::Err(v) => CastResult::Err(v.with_span(span)), + CastResult::Ok(t) => CastResult::Ok(Spanned::new(t, span)), + CastResult::Warn(t, m) => CastResult::Warn(Spanned::new(t, span), m), + CastResult::Err(v) => CastResult::Err(Spanned::new(v, span)), } } } diff --git a/src/exec/mod.rs b/src/exec/mod.rs index c323cf491..a0ed946d3 100644 --- a/src/exec/mod.rs +++ b/src/exec/mod.rs @@ -33,7 +33,7 @@ pub fn exec( ) -> Pass { let mut ctx = ExecContext::new(env, state); ctx.start_page_group(Softness::Hard); - tree.exec_with(&mut ctx, &map); + tree.exec_with_map(&mut ctx, &map); ctx.end_page_group(|s| s == Softness::Hard); ctx.finish() } @@ -51,21 +51,21 @@ pub trait Exec { } /// Execute a node with an expression map that applies to it. -pub trait ExecWith { +pub trait ExecWithMap { /// Execute the node. - fn exec_with(&self, ctx: &mut ExecContext, map: &ExprMap); + fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap); } -impl ExecWith for Tree { - fn exec_with(&self, ctx: &mut ExecContext, map: &ExprMap) { +impl ExecWithMap for Tree { + fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) { for node in self { - node.exec_with(ctx, map); + node.exec_with_map(ctx, map); } } } -impl ExecWith for Node { - fn exec_with(&self, ctx: &mut ExecContext, map: &ExprMap) { +impl ExecWithMap for Node { + fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) { match self { Node::Text(text) => ctx.push_text(text), Node::Space => ctx.push_space(), @@ -73,21 +73,21 @@ impl ExecWith for Node { Node::Parbreak => ctx.apply_parbreak(), Node::Strong => ctx.state.font.strong ^= true, Node::Emph => ctx.state.font.emph ^= true, - Node::Heading(heading) => heading.exec_with(ctx, map), + Node::Heading(heading) => heading.exec_with_map(ctx, map), Node::Raw(raw) => raw.exec(ctx), Node::Expr(expr) => map[&(expr as *const _)].exec(ctx), } } } -impl ExecWith for NodeHeading { - fn exec_with(&self, ctx: &mut ExecContext, map: &ExprMap) { +impl ExecWithMap for NodeHeading { + fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) { let prev = ctx.state.clone(); let upscale = 1.5 - 0.1 * self.level as f64; ctx.state.font.scale *= upscale; ctx.state.font.strong = true; - self.contents.exec_with(ctx, map); + self.contents.exec_with_map(ctx, map); ctx.apply_parbreak(); ctx.state = prev; @@ -154,7 +154,7 @@ impl Exec for ValueTemplate { impl Exec for TemplateNode { fn exec(&self, ctx: &mut ExecContext) { match self { - Self::Tree { tree, map } => tree.exec_with(ctx, &map), + Self::Tree { tree, map } => tree.exec_with_map(ctx, &map), Self::Any(any) => any.exec(ctx), } } diff --git a/src/parse/lines.rs b/src/parse/lines.rs index c47b7534a..8693af44c 100644 --- a/src/parse/lines.rs +++ b/src/parse/lines.rs @@ -1,5 +1,5 @@ use super::Scanner; -use crate::syntax::{Location, Offset, Pos}; +use crate::syntax::{Location, Pos}; /// Enables conversion of byte position to locations. pub struct LineMap<'s> { @@ -44,7 +44,7 @@ impl<'s> LineMap<'s> { pub fn pos(&self, location: Location) -> Option { // Determine the boundaries of the line. let line_idx = location.line.checked_sub(1)? as usize; - let line_start = self.line_starts.get(line_idx)?; + let line_start = *self.line_starts.get(line_idx)?; let line_end = self .line_starts .get(location.line as usize) @@ -64,7 +64,7 @@ impl<'s> LineMap<'s> { 0 }; - Some(line_start.offset(Pos(line_offset as u32))) + Some(line_start + line_offset) } } diff --git a/src/parse/resolve.rs b/src/parse/resolve.rs index 4592acbcb..88e11784c 100644 --- a/src/parse/resolve.rs +++ b/src/parse/resolve.rs @@ -1,5 +1,5 @@ use super::{is_newline, Scanner}; -use crate::syntax::{Ident, NodeRaw, Offset, Pos}; +use crate::syntax::{Ident, NodeRaw, Pos}; /// Resolve all escape sequences in a string. pub fn resolve_string(string: &str) -> String { @@ -52,7 +52,7 @@ pub fn resolve_raw(text: &str, backticks: usize, start: Pos) -> NodeRaw { let (tag, inner) = split_at_lang_tag(text); let (lines, had_newline) = trim_and_split_raw(inner); NodeRaw { - lang: Ident::new(tag, start .. start.offset(tag.len())), + lang: Ident::new(tag, start .. start + tag.len()), lines, block: had_newline, } diff --git a/src/prelude.rs b/src/prelude.rs index 3f5bcab74..5beded398 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -12,5 +12,5 @@ pub use crate::geom::*; #[doc(no_inline)] pub use crate::layout::Node; #[doc(no_inline)] -pub use crate::syntax::{Span, Spanned, WithSpan}; +pub use crate::syntax::{Span, Spanned}; pub use crate::{error, typify, warning}; diff --git a/src/pretty.rs b/src/pretty.rs index e01955cd8..a522b1256 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -3,7 +3,9 @@ use std::fmt::{Arguments, Result, Write}; use crate::color::{Color, RgbaColor}; +use crate::eval::*; use crate::geom::{Angle, Length, Linear, Relative}; +use crate::syntax::*; /// Pretty print an item and return the resulting string. pub fn pretty(item: &T) -> String @@ -15,12 +17,37 @@ where p.finish() } -/// Pretty printing. +/// Pretty print an item with an expression map and return the resulting string. +pub fn pretty_with_map(item: &T, map: &ExprMap) -> String +where + T: PrettyWithMap + ?Sized, +{ + let mut p = Printer::new(); + item.pretty_with_map(&mut p, Some(map)); + p.finish() +} + +/// Pretty print an item. pub trait Pretty { /// Pretty print this item into the given printer. fn pretty(&self, p: &mut Printer); } +/// Pretty print an item with an expression map that applies to it. +pub trait PrettyWithMap { + /// Pretty print this item into the given printer. + fn pretty_with_map(&self, p: &mut Printer, map: Option<&ExprMap>); +} + +impl Pretty for T +where + T: PrettyWithMap, +{ + fn pretty(&self, p: &mut Printer) { + self.pretty_with_map(p, None); + } +} + /// A buffer into which items are printed. pub struct Printer { buf: String, @@ -76,6 +103,463 @@ impl Write for Printer { } } +impl PrettyWithMap for Tree { + fn pretty_with_map(&self, p: &mut Printer, map: Option<&ExprMap>) { + for node in self { + node.pretty_with_map(p, map); + } + } +} + +impl PrettyWithMap for Node { + fn pretty_with_map(&self, p: &mut Printer, map: Option<&ExprMap>) { + match self { + Self::Strong => p.push('*'), + Self::Emph => p.push('_'), + Self::Space => p.push(' '), + Self::Linebreak => p.push_str(r"\"), + Self::Parbreak => p.push_str("\n\n"), + // TODO: Handle escaping. + Self::Text(text) => p.push_str(&text), + Self::Heading(heading) => heading.pretty_with_map(p, map), + Self::Raw(raw) => raw.pretty(p), + Self::Expr(expr) => { + if let Some(map) = map { + let value = &map[&(expr as *const _)]; + value.pretty(p); + } else if let Expr::Call(call) = expr { + // Format function templates appropriately. + pretty_bracketed(call, p, false) + } else { + expr.pretty(p); + } + } + } + } +} + +impl PrettyWithMap for NodeHeading { + fn pretty_with_map(&self, p: &mut Printer, map: Option<&ExprMap>) { + for _ in 0 ..= self.level { + p.push('='); + } + self.contents.pretty_with_map(p, map); + } +} + +impl Pretty for NodeRaw { + fn pretty(&self, p: &mut Printer) { + // Find out how many backticks we need. + let mut backticks = 1; + + // Language tag and block-level are only possible with 3+ backticks. + if self.lang.is_some() || self.block { + backticks = 3; + } + + // More backticks may be required if there are lots of consecutive + // backticks in the lines. + let mut count; + for line in &self.lines { + count = 0; + for c in line.chars() { + if c == '`' { + count += 1; + backticks = backticks.max(3).max(count + 1); + } else { + count = 0; + } + } + } + + // Starting backticks. + for _ in 0 .. backticks { + p.push('`'); + } + + // Language tag. + if let Some(lang) = &self.lang { + lang.pretty(p); + } + + // Start untrimming. + if self.block { + p.push('\n'); + } else if backticks >= 3 { + p.push(' '); + } + + // The lines. + p.join(&self.lines, "\n", |line, p| p.push_str(line)); + + // End untrimming. + if self.block { + p.push('\n'); + } else if self.lines.last().map_or(false, |line| line.trim_end().ends_with('`')) { + p.push(' '); + } + + // Ending backticks. + for _ in 0 .. backticks { + p.push('`'); + } + } +} + +impl Pretty for Expr { + fn pretty(&self, p: &mut Printer) { + match self { + Self::Lit(v) => v.pretty(p), + Self::Ident(v) => v.pretty(p), + Self::Array(v) => v.pretty(p), + Self::Dict(v) => v.pretty(p), + Self::Template(v) => v.pretty(p), + Self::Group(v) => v.pretty(p), + Self::Block(v) => v.pretty(p), + Self::Unary(v) => v.pretty(p), + Self::Binary(v) => v.pretty(p), + Self::Call(v) => v.pretty(p), + Self::Let(v) => v.pretty(p), + Self::If(v) => v.pretty(p), + Self::For(v) => v.pretty(p), + } + } +} + +impl Pretty for Lit { + fn pretty(&self, p: &mut Printer) { + self.kind.pretty(p); + } +} + +impl Pretty for LitKind { + fn pretty(&self, p: &mut Printer) { + match self { + Self::None => p.push_str("none"), + Self::Bool(v) => v.pretty(p), + Self::Int(v) => v.pretty(p), + Self::Float(v) => v.pretty(p), + Self::Length(v, u) => { + write!(p, "{}{}", ryu::Buffer::new().format(*v), u).unwrap(); + } + Self::Angle(v, u) => { + write!(p, "{}{}", ryu::Buffer::new().format(*v), u).unwrap(); + } + Self::Percent(v) => { + write!(p, "{}%", ryu::Buffer::new().format(*v)).unwrap(); + } + Self::Color(v) => v.pretty(p), + Self::Str(v) => v.pretty(p), + } + } +} + +impl Pretty for ExprArray { + fn pretty(&self, p: &mut Printer) { + p.push('('); + p.join(&self.items, ", ", |item, p| item.pretty(p)); + if self.items.len() == 1 { + p.push(','); + } + p.push(')'); + } +} + +impl Pretty for ExprDict { + fn pretty(&self, p: &mut Printer) { + p.push('('); + if self.items.is_empty() { + p.push(':'); + } else { + p.join(&self.items, ", ", |named, p| named.pretty(p)); + } + p.push(')'); + } +} + +impl Pretty for Named { + fn pretty(&self, p: &mut Printer) { + self.name.pretty(p); + p.push_str(": "); + self.expr.pretty(p); + } +} + +impl Pretty for ExprTemplate { + fn pretty(&self, p: &mut Printer) { + if let [Node::Expr(Expr::Call(call))] = self.tree.as_slice() { + pretty_bracketed(call, p, false); + } else { + p.push('['); + self.tree.pretty_with_map(p, None); + p.push(']'); + } + } +} + +impl Pretty for ExprGroup { + fn pretty(&self, p: &mut Printer) { + p.push('('); + self.expr.pretty(p); + p.push(')'); + } +} + +impl Pretty for ExprBlock { + fn pretty(&self, p: &mut Printer) { + p.push('{'); + if self.exprs.len() > 1 { + p.push(' '); + } + p.join(&self.exprs, "; ", |expr, p| expr.pretty(p)); + if self.exprs.len() > 1 { + p.push(' '); + } + p.push('}'); + } +} + +impl Pretty for ExprUnary { + fn pretty(&self, p: &mut Printer) { + self.op.pretty(p); + if self.op == UnOp::Not { + p.push(' '); + } + self.expr.pretty(p); + } +} + +impl Pretty for UnOp { + fn pretty(&self, p: &mut Printer) { + p.push_str(self.as_str()); + } +} + +impl Pretty for ExprBinary { + fn pretty(&self, p: &mut Printer) { + self.lhs.pretty(p); + p.push(' '); + self.op.pretty(p); + p.push(' '); + self.rhs.pretty(p); + } +} + +impl Pretty for BinOp { + fn pretty(&self, p: &mut Printer) { + p.push_str(self.as_str()); + } +} + +impl Pretty for ExprCall { + fn pretty(&self, p: &mut Printer) { + self.callee.pretty(p); + p.push('('); + self.args.pretty(p); + p.push(')'); + } +} + +/// Pretty print a function template, with body or chaining when possible. +pub fn pretty_bracketed(call: &ExprCall, p: &mut Printer, chained: bool) { + if chained { + p.push_str(" | "); + } else { + p.push_str("#["); + } + + // Function name. + call.callee.pretty(p); + + let mut write_args = |items: &[ExprArg]| { + if !items.is_empty() { + p.push(' '); + p.join(items, ", ", |item, p| item.pretty(p)); + } + }; + + match call.args.items.as_slice() { + // This can written as a chain. + // + // Example: Transforms "#[v][[f]]" => "#[v | f]". + [head @ .., ExprArg::Pos(Expr::Call(call))] => { + write_args(head); + pretty_bracketed(call, p, true); + } + + // This can be written with a body. + // + // Example: Transforms "#[v [Hi]]" => "#[v][Hi]". + [head @ .., ExprArg::Pos(Expr::Template(template))] => { + write_args(head); + p.push(']'); + template.pretty(p); + } + + items => { + write_args(items); + p.push(']'); + } + } +} + +impl Pretty for ExprArgs { + fn pretty(&self, p: &mut Printer) { + p.join(&self.items, ", ", |item, p| item.pretty(p)); + } +} + +impl Pretty for ExprArg { + fn pretty(&self, p: &mut Printer) { + match self { + Self::Pos(expr) => expr.pretty(p), + Self::Named(named) => named.pretty(p), + } + } +} + +impl Pretty for ExprLet { + fn pretty(&self, p: &mut Printer) { + p.push_str("#let "); + self.binding.pretty(p); + if let Some(init) = &self.init { + p.push_str(" = "); + init.pretty(p); + } + } +} + +impl Pretty for ExprIf { + fn pretty(&self, p: &mut Printer) { + p.push_str("#if "); + self.condition.pretty(p); + p.push(' '); + self.if_body.pretty(p); + if let Some(expr) = &self.else_body { + p.push_str(" #else "); + expr.pretty(p); + } + } +} + +impl Pretty for ExprFor { + fn pretty(&self, p: &mut Printer) { + p.push_str("#for "); + self.pattern.pretty(p); + p.push_str(" #in "); + self.iter.pretty(p); + p.push(' '); + self.body.pretty(p); + } +} + +impl Pretty for ForPattern { + fn pretty(&self, p: &mut Printer) { + match self { + Self::Value(v) => v.pretty(p), + Self::KeyValue(k, v) => { + k.pretty(p); + p.push_str(", "); + v.pretty(p); + } + } + } +} + +impl Pretty for Ident { + fn pretty(&self, p: &mut Printer) { + p.push_str(self.as_str()); + } +} + +impl Pretty for Value { + fn pretty(&self, p: &mut Printer) { + match self { + Value::None => p.push_str("none"), + Value::Bool(v) => v.pretty(p), + Value::Int(v) => v.pretty(p), + Value::Float(v) => v.pretty(p), + Value::Length(v) => v.pretty(p), + Value::Angle(v) => v.pretty(p), + Value::Relative(v) => v.pretty(p), + Value::Linear(v) => v.pretty(p), + Value::Color(v) => v.pretty(p), + Value::Str(v) => v.pretty(p), + Value::Array(v) => v.pretty(p), + Value::Dict(v) => v.pretty(p), + Value::Template(v) => v.pretty(p), + Value::Func(v) => v.pretty(p), + Value::Args(v) => v.pretty(p), + Value::Any(v) => v.pretty(p), + Value::Error => p.push_str(""), + } + } +} + +impl Pretty for ValueArray { + fn pretty(&self, p: &mut Printer) { + p.push('('); + p.join(self, ", ", |item, p| item.pretty(p)); + if self.len() == 1 { + p.push(','); + } + p.push(')'); + } +} + +impl Pretty for ValueTemplate { + fn pretty(&self, p: &mut Printer) { + p.push('['); + for part in self { + part.pretty(p); + } + p.push(']'); + } +} + +impl Pretty for TemplateNode { + fn pretty(&self, p: &mut Printer) { + match self { + Self::Tree { tree, map } => tree.pretty_with_map(p, Some(map)), + Self::Any(any) => any.pretty(p), + } + } +} + +impl Pretty for TemplateAny { + fn pretty(&self, p: &mut Printer) { + p.push('<'); + p.push_str(self.name()); + p.push('>'); + } +} + +impl Pretty for ValueFunc { + fn pretty(&self, p: &mut Printer) { + p.push('<'); + p.push_str(self.name()); + p.push('>'); + } +} + +impl Pretty for ValueArgs { + fn pretty(&self, p: &mut Printer) { + p.push('<'); + p.join(&self.items, ", ", |item, p| item.pretty(p)); + p.push('>'); + } +} + +impl Pretty for ValueArg { + fn pretty(&self, p: &mut Printer) { + if let Some(name) = &self.name { + p.push_str(&name.v); + p.push_str(": "); + } + self.value.v.pretty(p); + } +} + impl Pretty for i64 { fn pretty(&self, p: &mut Printer) { p.push_str(itoa::Buffer::new().format(*self)); @@ -123,11 +607,134 @@ pretty_display! { Linear, RgbaColor, Color, + ValueAny, } #[cfg(test)] mod tests { use super::*; + use crate::env::Env; + use crate::eval::eval; + use crate::parse::parse; + + #[track_caller] + fn test(src: &str, exp: &str) { + let tree = parse(src).output; + let found = pretty(&tree); + if exp != found { + println!("tree: {:#?}", tree); + println!("expected: {}", exp); + println!("found: {}", found); + panic!("test failed"); + } + } + + #[track_caller] + fn roundtrip(src: &str) { + test(src, src); + } + + #[test] + fn test_pretty_print_node() { + // Basic text and markup. + roundtrip("*"); + roundtrip("_"); + roundtrip(" "); + roundtrip("\\ "); + roundtrip("\n\n"); + roundtrip("hi"); + + // Heading. + roundtrip("= *Ok*"); + + // Raw. + roundtrip("``"); + roundtrip("`nolang 1`"); + roundtrip("```lang 1```"); + roundtrip("```lang 1 ```"); + roundtrip("```hi line ```"); + roundtrip("```py\ndef\n```"); + roundtrip("```\n line \n```"); + roundtrip("```\n`\n```"); + roundtrip("``` ` ```"); + roundtrip("````\n```\n```\n````"); + test("```lang```", "```lang ```"); + test("```1 ```", "``"); + test("``` 1```", "`1`"); + test("``` 1 ```", "`1 `"); + test("```` ` ````", "``` ` ```"); + } + + #[test] + fn test_pretty_print_expr() { + // Basic expressions. + roundtrip("{none}"); + roundtrip("{hi}"); + roundtrip("{true}"); + roundtrip("{10}"); + roundtrip("{3.14}"); + roundtrip("{10.0pt}"); + roundtrip("{14.1deg}"); + roundtrip("{20.0%}"); + roundtrip("{#abcdef}"); + roundtrip(r#"{"hi"}"#); + test(r#"{"let's \" go"}"#, r#"{"let's \" go"}"#); + + // Arrays. + roundtrip("{()}"); + roundtrip("{(1)}"); + roundtrip("{(1, 2, 3)}"); + + // Dictionaries. + roundtrip("{(:)}"); + roundtrip("{(key: value)}"); + roundtrip("{(a: 1, b: 2)}"); + + // Templates. + roundtrip("[]"); + roundtrip("[*Ok*]"); + roundtrip("{[f]}"); + + // Groups. + roundtrip("{(1)}"); + + // Blocks. + roundtrip("{}"); + roundtrip("{1}"); + roundtrip("{ #let x = 1; x += 2; x + 1 }"); + roundtrip("[{}]"); + + // Operators. + roundtrip("{-x}"); + roundtrip("{not true}"); + roundtrip("{1 + 3}"); + + // Parenthesized calls. + roundtrip("{v()}"); + roundtrip("{v(1)}"); + roundtrip("{v(a: 1, b)}"); + + // Function templates. + roundtrip("#[v]"); + roundtrip("#[v 1]"); + roundtrip("#[v 1, 2][*Ok*]"); + roundtrip("#[v 1 | f 2]"); + test("{#[v]}", "{v()}"); + test("#[v 1, #[f 2]]", "#[v 1 | f 2]"); + + // Keywords. + roundtrip("#let x = 1 + 2"); + roundtrip("#if x [y] #else [z]"); + roundtrip("#for x #in y {z}"); + roundtrip("#for k, x #in y {z}"); + } + + #[test] + fn test_pretty_print_with_map() { + let tree = parse("*[{1+2}[{4}]]*{2+3}").output; + let map = eval(&mut Env::blank(), &tree, &Default::default()).output; + assert_eq!(pretty_with_map(&tree, &map), "*[3[4]]*5"); + } #[test] fn test_pretty_print_str() { diff --git a/src/syntax/expr.rs b/src/syntax/expr.rs index 8a11ebc41..d18d34048 100644 --- a/src/syntax/expr.rs +++ b/src/syntax/expr.rs @@ -56,26 +56,6 @@ impl Expr { } } -impl Pretty for Expr { - fn pretty(&self, p: &mut Printer) { - match self { - Self::Lit(v) => v.pretty(p), - Self::Ident(v) => v.pretty(p), - Self::Array(v) => v.pretty(p), - Self::Dict(v) => v.pretty(p), - Self::Template(v) => v.pretty(p), - Self::Group(v) => v.pretty(p), - Self::Block(v) => v.pretty(p), - Self::Unary(v) => v.pretty(p), - Self::Binary(v) => v.pretty(p), - Self::Call(v) => v.pretty(p), - Self::Let(v) => v.pretty(p), - Self::If(v) => v.pretty(p), - Self::For(v) => v.pretty(p), - } - } -} - /// A literal. #[derive(Debug, Clone, PartialEq)] pub struct Lit { @@ -85,12 +65,6 @@ pub struct Lit { pub kind: LitKind, } -impl Pretty for Lit { - fn pretty(&self, p: &mut Printer) { - self.kind.pretty(p); - } -} - /// A kind of literal. #[derive(Debug, Clone, PartialEq)] pub enum LitKind { @@ -117,28 +91,6 @@ pub enum LitKind { Str(String), } -impl Pretty for LitKind { - fn pretty(&self, p: &mut Printer) { - match self { - Self::None => p.push_str("none"), - Self::Bool(v) => v.pretty(p), - Self::Int(v) => v.pretty(p), - Self::Float(v) => v.pretty(p), - Self::Length(v, u) => { - write!(p, "{}{}", ryu::Buffer::new().format(*v), u).unwrap(); - } - Self::Angle(v, u) => { - write!(p, "{}{}", ryu::Buffer::new().format(*v), u).unwrap(); - } - Self::Percent(v) => { - write!(p, "{}%", ryu::Buffer::new().format(*v)).unwrap(); - } - Self::Color(v) => v.pretty(p), - Self::Str(v) => v.pretty(p), - } - } -} - /// An array expression: `(1, "hi", 12cm)`. #[derive(Debug, Clone, PartialEq)] pub struct ExprArray { @@ -148,17 +100,6 @@ pub struct ExprArray { pub items: Vec, } -impl Pretty for ExprArray { - fn pretty(&self, p: &mut Printer) { - p.push('('); - p.join(&self.items, ", ", |item, p| item.pretty(p)); - if self.items.len() == 1 { - p.push(','); - } - p.push(')'); - } -} - /// A dictionary expression: `(color: #f79143, pattern: dashed)`. #[derive(Debug, Clone, PartialEq)] pub struct ExprDict { @@ -168,18 +109,6 @@ pub struct ExprDict { pub items: Vec, } -impl Pretty for ExprDict { - fn pretty(&self, p: &mut Printer) { - p.push('('); - if self.items.is_empty() { - p.push(':'); - } else { - p.join(&self.items, ", ", |named, p| named.pretty(p)); - } - p.push(')'); - } -} - /// A pair of a name and an expression: `pattern: dashed`. #[derive(Debug, Clone, PartialEq)] pub struct Named { @@ -196,14 +125,6 @@ impl Named { } } -impl Pretty for Named { - fn pretty(&self, p: &mut Printer) { - self.name.pretty(p); - p.push_str(": "); - self.expr.pretty(p); - } -} - /// A template expression: `[*Hi* there!]`. #[derive(Debug, Clone, PartialEq)] pub struct ExprTemplate { @@ -213,18 +134,6 @@ pub struct ExprTemplate { pub tree: Rc, } -impl Pretty for ExprTemplate { - fn pretty(&self, p: &mut Printer) { - if let [Node::Expr(Expr::Call(call))] = self.tree.as_slice() { - call.pretty_bracketed(p, false); - } else { - p.push('['); - self.tree.pretty(p); - p.push(']'); - } - } -} - /// A grouped expression: `(1 + 2)`. #[derive(Debug, Clone, PartialEq)] pub struct ExprGroup { @@ -234,14 +143,6 @@ pub struct ExprGroup { pub expr: Box, } -impl Pretty for ExprGroup { - fn pretty(&self, p: &mut Printer) { - p.push('('); - self.expr.pretty(p); - p.push(')'); - } -} - /// A block expression: `{ #let x = 1; x + 2 }`. #[derive(Debug, Clone, PartialEq)] pub struct ExprBlock { @@ -253,20 +154,6 @@ pub struct ExprBlock { pub scoping: bool, } -impl Pretty for ExprBlock { - fn pretty(&self, p: &mut Printer) { - p.push('{'); - if self.exprs.len() > 1 { - p.push(' '); - } - p.join(&self.exprs, "; ", |expr, p| expr.pretty(p)); - if self.exprs.len() > 1 { - p.push(' '); - } - p.push('}'); - } -} - /// A unary operation: `-x`. #[derive(Debug, Clone, PartialEq)] pub struct ExprUnary { @@ -278,16 +165,6 @@ pub struct ExprUnary { pub expr: Box, } -impl Pretty for ExprUnary { - fn pretty(&self, p: &mut Printer) { - self.op.pretty(p); - if self.op == UnOp::Not { - p.push(' '); - } - self.expr.pretty(p); - } -} - /// A unary operator. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum UnOp { @@ -328,12 +205,6 @@ impl UnOp { } } -impl Pretty for UnOp { - fn pretty(&self, p: &mut Printer) { - p.push_str(self.as_str()); - } -} - /// A binary operation: `a + b`. #[derive(Debug, Clone, PartialEq)] pub struct ExprBinary { @@ -347,16 +218,6 @@ pub struct ExprBinary { pub rhs: Box, } -impl Pretty for ExprBinary { - fn pretty(&self, p: &mut Printer) { - self.lhs.pretty(p); - p.push(' '); - self.op.pretty(p); - p.push(' '); - self.rhs.pretty(p); - } -} - /// A binary operator. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum BinOp { @@ -484,12 +345,6 @@ impl BinOp { } } -impl Pretty for BinOp { - fn pretty(&self, p: &mut Printer) { - p.push_str(self.as_str()); - } -} - /// The associativity of a binary operator. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum Associativity { @@ -510,60 +365,6 @@ pub struct ExprCall { pub args: ExprArgs, } -impl Pretty for ExprCall { - fn pretty(&self, p: &mut Printer) { - self.callee.pretty(p); - p.push('('); - self.args.pretty(p); - p.push(')'); - } -} - -impl ExprCall { - /// Pretty print a function template, with body or chaining when possible. - pub fn pretty_bracketed(&self, p: &mut Printer, chained: bool) { - if chained { - p.push_str(" | "); - } else { - p.push_str("#["); - } - - // Function name. - self.callee.pretty(p); - - let mut write_args = |items: &[ExprArg]| { - if !items.is_empty() { - p.push(' '); - p.join(items, ", ", |item, p| item.pretty(p)); - } - }; - - match self.args.items.as_slice() { - // This can written as a chain. - // - // Example: Transforms "#[v][[f]]" => "#[v | f]". - [head @ .., ExprArg::Pos(Expr::Call(call))] => { - write_args(head); - call.pretty_bracketed(p, true); - } - - // This can be written with a body. - // - // Example: Transforms "#[v [Hi]]" => "#[v][Hi]". - [head @ .., ExprArg::Pos(Expr::Template(template))] => { - write_args(head); - p.push(']'); - template.pretty(p); - } - - items => { - write_args(items); - p.push(']'); - } - } - } -} - /// The arguments to a function: `12, draw: false`. /// /// In case of a bracketed invocation with a body, the body is _not_ @@ -576,12 +377,6 @@ pub struct ExprArgs { pub items: Vec, } -impl Pretty for ExprArgs { - fn pretty(&self, p: &mut Printer) { - p.join(&self.items, ", ", |item, p| item.pretty(p)); - } -} - /// An argument to a function call: `12` or `draw: false`. #[derive(Debug, Clone, PartialEq)] pub enum ExprArg { @@ -601,15 +396,6 @@ impl ExprArg { } } -impl Pretty for ExprArg { - fn pretty(&self, p: &mut Printer) { - match self { - Self::Pos(expr) => expr.pretty(p), - Self::Named(named) => named.pretty(p), - } - } -} - /// A let expression: `#let x = 1`. #[derive(Debug, Clone, PartialEq)] pub struct ExprLet { @@ -621,17 +407,6 @@ pub struct ExprLet { pub init: Option>, } -impl Pretty for ExprLet { - fn pretty(&self, p: &mut Printer) { - p.push_str("#let "); - self.binding.pretty(p); - if let Some(init) = &self.init { - p.push_str(" = "); - init.pretty(p); - } - } -} - /// An if expression: `#if x { y } #else { z }`. #[derive(Debug, Clone, PartialEq)] pub struct ExprIf { @@ -645,19 +420,6 @@ pub struct ExprIf { pub else_body: Option>, } -impl Pretty for ExprIf { - fn pretty(&self, p: &mut Printer) { - p.push_str("#if "); - self.condition.pretty(p); - p.push(' '); - self.if_body.pretty(p); - if let Some(expr) = &self.else_body { - p.push_str(" #else "); - expr.pretty(p); - } - } -} - /// A for expression: `#for x #in y { z }`. #[derive(Debug, Clone, PartialEq)] pub struct ExprFor { @@ -671,17 +433,6 @@ pub struct ExprFor { pub body: Box, } -impl Pretty for ExprFor { - fn pretty(&self, p: &mut Printer) { - p.push_str("#for "); - self.pattern.pretty(p); - p.push_str(" #in "); - self.iter.pretty(p); - p.push(' '); - self.body.pretty(p); - } -} - /// A pattern in a for loop. #[derive(Debug, Clone, PartialEq)] pub enum ForPattern { @@ -700,16 +451,3 @@ impl ForPattern { } } } - -impl Pretty for ForPattern { - fn pretty(&self, p: &mut Printer) { - match self { - Self::Value(v) => v.pretty(p), - Self::KeyValue(k, v) => { - k.pretty(p); - p.push_str(", "); - v.pretty(p); - } - } - } -} diff --git a/src/syntax/ident.rs b/src/syntax/ident.rs index 731a27896..26c46b988 100644 --- a/src/syntax/ident.rs +++ b/src/syntax/ident.rs @@ -3,7 +3,6 @@ use std::ops::Deref; use unicode_xid::UnicodeXID; use super::Span; -use crate::pretty::{Pretty, Printer}; /// An Unicode identifier with a few extra permissible characters. /// @@ -53,12 +52,6 @@ impl Deref for Ident { } } -impl Pretty for Ident { - fn pretty(&self, p: &mut Printer) { - p.push_str(self.as_str()); - } -} - /// Whether a string is a valid identifier. pub fn is_ident(string: &str) -> bool { let mut chars = string.chars(); diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index a8ed24576..09c445b0b 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -13,133 +13,5 @@ pub use node::*; pub use span::*; pub use token::*; -use crate::pretty::{Pretty, Printer}; - /// The abstract syntax tree. pub type Tree = Vec; - -impl Pretty for Tree { - fn pretty(&self, p: &mut Printer) { - for node in self { - node.pretty(p); - } - } -} - -#[cfg(test)] -mod tests { - use crate::parse::parse; - use crate::pretty::pretty; - - #[track_caller] - fn test(src: &str, exp: &str) { - let tree = parse(src).output; - let found = pretty(&tree); - if exp != found { - println!("tree: {:#?}", tree); - println!("expected: {}", exp); - println!("found: {}", found); - panic!("test failed"); - } - } - - #[track_caller] - fn roundtrip(src: &str) { - test(src, src); - } - - #[test] - fn test_pretty_print_node() { - // Basic text and markup. - roundtrip("*"); - roundtrip("_"); - roundtrip(" "); - roundtrip("\\ "); - roundtrip("\n\n"); - roundtrip("hi"); - - // Heading. - roundtrip("= *Ok*"); - - // Raw. - roundtrip("``"); - roundtrip("`nolang 1`"); - roundtrip("```lang 1```"); - roundtrip("```lang 1 ```"); - roundtrip("```hi line ```"); - roundtrip("```py\ndef\n```"); - roundtrip("```\n line \n```"); - roundtrip("```\n`\n```"); - roundtrip("``` ` ```"); - roundtrip("````\n```\n```\n````"); - test("```lang```", "```lang ```"); - test("```1 ```", "``"); - test("``` 1```", "`1`"); - test("``` 1 ```", "`1 `"); - test("```` ` ````", "``` ` ```"); - } - - #[test] - fn test_pretty_print_expr() { - // Basic expressions. - roundtrip("{none}"); - roundtrip("{hi}"); - roundtrip("{true}"); - roundtrip("{10}"); - roundtrip("{3.14}"); - roundtrip("{10.0pt}"); - roundtrip("{14.1deg}"); - roundtrip("{20.0%}"); - roundtrip("{#abcdef}"); - roundtrip(r#"{"hi"}"#); - test(r#"{"let's \" go"}"#, r#"{"let's \" go"}"#); - - // Arrays. - roundtrip("{()}"); - roundtrip("{(1)}"); - roundtrip("{(1, 2, 3)}"); - - // Dictionaries. - roundtrip("{(:)}"); - roundtrip("{(key: value)}"); - roundtrip("{(a: 1, b: 2)}"); - - // Templates. - roundtrip("[]"); - roundtrip("[*Ok*]"); - roundtrip("{[f]}"); - - // Groups. - roundtrip("{(1)}"); - - // Blocks. - roundtrip("{}"); - roundtrip("{1}"); - roundtrip("{ #let x = 1; x += 2; x + 1 }"); - roundtrip("[{}]"); - - // Operators. - roundtrip("{-x}"); - roundtrip("{not true}"); - roundtrip("{1 + 3}"); - - // Parenthesized calls. - roundtrip("{v()}"); - roundtrip("{v(1)}"); - roundtrip("{v(a: 1, b)}"); - - // Function templates. - roundtrip("#[v]"); - roundtrip("#[v 1]"); - roundtrip("#[v 1, 2][*Ok*]"); - roundtrip("#[v 1 | f 2]"); - test("{#[v]}", "{v()}"); - test("#[v 1, #[f 2]]", "#[v 1 | f 2]"); - - // Keywords. - roundtrip("#let x = 1 + 2"); - roundtrip("#if x [y] #else [z]"); - roundtrip("#for x #in y {z}"); - roundtrip("#for k, x #in y {z}"); - } -} diff --git a/src/syntax/node.rs b/src/syntax/node.rs index 246790f6a..19fdfa50e 100644 --- a/src/syntax/node.rs +++ b/src/syntax/node.rs @@ -23,30 +23,6 @@ pub enum Node { Expr(Expr), } -impl Pretty for Node { - fn pretty(&self, p: &mut Printer) { - match self { - Self::Strong => p.push('*'), - Self::Emph => p.push('_'), - Self::Space => p.push(' '), - Self::Linebreak => p.push_str(r"\"), - Self::Parbreak => p.push_str("\n\n"), - // TODO: Handle escaping. - Self::Text(text) => p.push_str(&text), - Self::Heading(heading) => heading.pretty(p), - Self::Raw(raw) => raw.pretty(p), - Self::Expr(expr) => { - if let Expr::Call(call) = expr { - // Format function templates appropriately. - call.pretty_bracketed(p, false) - } else { - expr.pretty(p); - } - } - } - } -} - /// A section heading: `= Introduction`. #[derive(Debug, Clone, PartialEq)] pub struct NodeHeading { @@ -56,15 +32,6 @@ pub struct NodeHeading { pub contents: Tree, } -impl Pretty for NodeHeading { - fn pretty(&self, p: &mut Printer) { - for _ in 0 ..= self.level { - p.push('='); - } - self.contents.pretty(p); - } -} - /// A raw block with optional syntax highlighting: `` `raw` ``. /// /// Raw blocks start with 1 or 3+ backticks and end with the same number of @@ -139,62 +106,3 @@ pub struct NodeRaw { /// and contains at least one newline. pub block: bool, } - -impl Pretty for NodeRaw { - fn pretty(&self, p: &mut Printer) { - // Find out how many backticks we need. - let mut backticks = 1; - - // Language tag and block-level are only possible with 3+ backticks. - if self.lang.is_some() || self.block { - backticks = 3; - } - - // More backticks may be required if there are lots of consecutive - // backticks in the lines. - let mut count; - for line in &self.lines { - count = 0; - for c in line.chars() { - if c == '`' { - count += 1; - backticks = backticks.max(3).max(count + 1); - } else { - count = 0; - } - } - } - - // Starting backticks. - for _ in 0 .. backticks { - p.push('`'); - } - - // Language tag. - if let Some(lang) = &self.lang { - lang.pretty(p); - } - - // Start untrimming. - if self.block { - p.push('\n'); - } else if backticks >= 3 { - p.push(' '); - } - - // The lines. - p.join(&self.lines, "\n", |line, p| p.push_str(line)); - - // End untrimming. - if self.block { - p.push('\n'); - } else if self.lines.last().map_or(false, |line| line.trim_end().ends_with('`')) { - p.push(' '); - } - - // Ending backticks. - for _ in 0 .. backticks { - p.push('`'); - } - } -} diff --git a/src/syntax/span.rs b/src/syntax/span.rs index 65b1d637d..d939ed285 100644 --- a/src/syntax/span.rs +++ b/src/syntax/span.rs @@ -1,40 +1,11 @@ use std::cell::Cell; use std::fmt::{self, Debug, Display, Formatter}; -use std::ops::Range; +use std::ops::{Add, Range}; thread_local! { static CMP_SPANS: Cell = Cell::new(true); } -/// Annotate a value with a span. -pub trait WithSpan: Sized { - /// Wraps `self` in a `Spanned` with the given span. - fn with_span(self, span: impl Into) -> Spanned { - Spanned::new(self, span) - } -} - -impl WithSpan for T {} - -/// Span offsetting. -pub trait Offset { - /// Offset all spans contained in `Self` by the given position. - fn offset(self, by: impl Into) -> Self; -} - -/// A vector of spanned values of type `T`. -pub type SpanVec = Vec>; - -impl Offset for SpanVec { - fn offset(mut self, by: impl Into) -> Self { - let by = by.into(); - for spanned in &mut self { - spanned.span = spanned.span.offset(by); - } - self - } -} - /// A value with the span it corresponds to in the source code. #[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Serialize))] @@ -68,29 +39,6 @@ impl Spanned { { Spanned { v: f(self.v), span: self.span } } - - /// Maps the span while keeping the value. - pub fn map_span(mut self, f: F) -> Self - where - F: FnOnce(Span) -> Span, - { - self.span = f(self.span); - self - } -} - -impl Spanned> { - /// Swap the spanned and the option. - pub fn transpose(self) -> Option> { - let Spanned { v, span } = self; - v.map(|v| v.with_span(span)) - } -} - -impl Offset for Spanned { - fn offset(self, by: impl Into) -> Self { - self.map_span(|span| span.offset(by)) - } } impl Debug for Spanned { @@ -171,16 +119,6 @@ impl Span { } } -impl Offset for Span { - fn offset(self, by: impl Into) -> Self { - let by = by.into(); - Self { - start: self.start.offset(by), - end: self.end.offset(by), - } - } -} - impl Eq for Span {} impl PartialEq for Span { @@ -234,9 +172,14 @@ impl Pos { } } -impl Offset for Pos { - fn offset(self, by: impl Into) -> Self { - Pos(self.0 + by.into().0) +impl Add for Pos +where + T: Into, +{ + type Output = Self; + + fn add(self, rhs: T) -> Self { + Pos(self.0 + rhs.into().0) } } diff --git a/tests/lang/ref/call-bracket.png b/tests/lang/ref/call-bracket.png index a1214b3d9b61c27359f6f3a89f27e653afe725c6..347907b891bd01a7741f791bf856520c30aa1309 100644 GIT binary patch delta 1458 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 (Option, SpanVec) { +fn parse_metadata(src: &str, map: &LineMap) -> (Option, Vec>) { let mut diags = vec![]; let mut compare_ref = None; @@ -304,7 +304,8 @@ fn parse_metadata(src: &str, map: &LineMap) -> (Option, SpanVec) { let mut s = Scanner::new(rest); let (start, _, end) = (pos(&mut s), s.eat_assert('-'), pos(&mut s)); - diags.push(Diag::new(level, s.rest().trim()).with_span(start .. end)); + let diag = Diag::new(level, s.rest().trim()); + diags.push(Spanned::new(diag, start .. end)); } diags.sort_by_key(|d| d.span);