summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-02-11 17:33:13 +0100
committerLaurenz <laurmaedje@gmail.com>2021-02-11 17:33:13 +0100
commit1711b67877ce5c290e049775c340c9324f15341e (patch)
tree92d6ff7285cdc2d694ccfdf733ce8757866636ec /src
parentf9197dcfef11c4c054a460c80ff6023dae6f1f2a (diff)
Move all pretty printing into one module and pretty print values 🦋
Diffstat (limited to 'src')
-rw-r--r--src/diag.rs6
-rw-r--r--src/env.rs11
-rw-r--r--src/eval/mod.rs6
-rw-r--r--src/eval/value.rs118
-rw-r--r--src/exec/mod.rs26
-rw-r--r--src/parse/lines.rs6
-rw-r--r--src/parse/resolve.rs4
-rw-r--r--src/prelude.rs2
-rw-r--r--src/pretty.rs609
-rw-r--r--src/syntax/expr.rs262
-rw-r--r--src/syntax/ident.rs7
-rw-r--r--src/syntax/mod.rs128
-rw-r--r--src/syntax/node.rs92
-rw-r--r--src/syntax/span.rs75
14 files changed, 673 insertions, 679 deletions
diff --git a/src/diag.rs b/src/diag.rs
index 07fd7b50..b1c477a5 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<T> Pass<T> {
#[derive(Debug, Default, Clone, Eq, PartialEq)]
pub struct Feedback {
/// Diagnostics about the source code.
- pub diags: SpanVec<Diag>,
+ pub diags: Vec<Spanned<Diag>>,
/// Decorations of the source code for semantic syntax highlighting.
- pub decos: SpanVec<Deco>,
+ pub decos: Vec<Spanned<Deco>>,
}
impl Feedback {
diff --git a/src/env.rs b/src/env.rs
index aaa04aa2..66cc5e19 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<PathBuf, ResourceId>,
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index 4f0beb34..ec71f689 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 94477aa5..ab54bf53 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("<error>"),
- }
- }
-}
-
/// An array value: `(1, "hi", 12cm)`.
pub type ValueArray = Vec<Value>;
-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<String, Value>;
@@ -157,16 +122,6 @@ impl Pretty for ValueDict {
/// A template value: `[*Hi* there]`.
pub type ValueTemplate = Vec<TemplateNode>;
-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<dyn Bounds>);
@@ -510,15 +432,15 @@ 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 Debug for ValueAny {
+impl Display for ValueAny {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.debug_tuple("ValueAny").field(&self.0).finish()
+ Display::fmt(&self.0, f)
}
}
@@ -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<Value>) -> CastResult<Self, Spanned<Value>> {
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 c323cf49..a0ed946d 100644
--- a/src/exec/mod.rs
+++ b/src/exec/mod.rs
@@ -33,7 +33,7 @@ pub fn exec(
) -> Pass<layout::Tree> {
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 c47b7534..8693af44 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<Pos> {
// 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 4592acbc..88e11784 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 3f5bcab7..5beded39 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 e01955cd..a522b125 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<T>(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<T>(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<T> 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("<error>"),
+ }
+ }
+}
+
+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 8a11ebc4..d18d3404 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<Expr>,
}
-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<Named>,
}
-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<Tree>,
}
-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<Expr>,
}
-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<Expr>,
}
-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<Expr>,
}
-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<ExprArg>,
}
-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<Box<Expr>>,
}
-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<Box<Expr>>,
}
-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<Expr>,
}
-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 731a2789..26c46b98 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 a8ed2457..09c445b0 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<Node>;
-
-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 246790f6..19fdfa50 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 65b1d637..d939ed28 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<bool> = 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<Span>) -> Spanned<Self> {
- Spanned::new(self, span)
- }
-}
-
-impl<T> WithSpan for T {}
-
-/// Span offsetting.
-pub trait Offset {
- /// Offset all spans contained in `Self` by the given position.
- fn offset(self, by: impl Into<Pos>) -> Self;
-}
-
-/// A vector of spanned values of type `T`.
-pub type SpanVec<T> = Vec<Spanned<T>>;
-
-impl<T> Offset for SpanVec<T> {
- fn offset(mut self, by: impl Into<Pos>) -> 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<T> Spanned<T> {
{
Spanned { v: f(self.v), span: self.span }
}
-
- /// Maps the span while keeping the value.
- pub fn map_span<F>(mut self, f: F) -> Self
- where
- F: FnOnce(Span) -> Span,
- {
- self.span = f(self.span);
- self
- }
-}
-
-impl<T> Spanned<Option<T>> {
- /// Swap the spanned and the option.
- pub fn transpose(self) -> Option<Spanned<T>> {
- let Spanned { v, span } = self;
- v.map(|v| v.with_span(span))
- }
-}
-
-impl<T> Offset for Spanned<T> {
- fn offset(self, by: impl Into<Pos>) -> Self {
- self.map_span(|span| span.offset(by))
- }
}
impl<T: Debug> Debug for Spanned<T> {
@@ -171,16 +119,6 @@ impl Span {
}
}
-impl Offset for Span {
- fn offset(self, by: impl Into<Pos>) -> 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<Pos>) -> Self {
- Pos(self.0 + by.into().0)
+impl<T> Add<T> for Pos
+where
+ T: Into<Pos>,
+{
+ type Output = Self;
+
+ fn add(self, rhs: T) -> Self {
+ Pos(self.0 + rhs.into().0)
}
}