summaryrefslogtreecommitdiff
path: root/src/syntax
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/syntax
parentf9197dcfef11c4c054a460c80ff6023dae6f1f2a (diff)
Move all pretty printing into one module and pretty print values 🦋
Diffstat (limited to 'src/syntax')
-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
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)
}
}