diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-02-11 17:33:13 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-02-11 17:33:13 +0100 |
| commit | 1711b67877ce5c290e049775c340c9324f15341e (patch) | |
| tree | 92d6ff7285cdc2d694ccfdf733ce8757866636ec /src/syntax | |
| parent | f9197dcfef11c4c054a460c80ff6023dae6f1f2a (diff) | |
Move all pretty printing into one module and pretty print values 🦋
Diffstat (limited to 'src/syntax')
| -rw-r--r-- | src/syntax/expr.rs | 262 | ||||
| -rw-r--r-- | src/syntax/ident.rs | 7 | ||||
| -rw-r--r-- | src/syntax/mod.rs | 128 | ||||
| -rw-r--r-- | src/syntax/node.rs | 92 | ||||
| -rw-r--r-- | src/syntax/span.rs | 75 |
5 files changed, 9 insertions, 555 deletions
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) } } |
