summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2020-08-29 12:02:07 +0200
committerLaurenz <laurmaedje@gmail.com>2020-08-29 12:02:07 +0200
commit236750c35fbad916b63774df917cbc436f1d1a8c (patch)
treec6e837da340f50ad64bf182d676e7228c044f08d /src
parent6febc0327304451bc956985b7cadb07a0b563c79 (diff)
Remove par nodes in favor of parbreaks 🔄
This basically reverts the earlier change from parbreaks to par nodes because: - It is simpler and less nested - It works way better with functions that layout their body inline like `font`, which where buggy before, previously The original reasons for changing to par nodes were: - the envisioned design of the layouter at that time (based on dynamic nodes etc.), which is not relevant anymore - possibly existing benefits with regards to incremental compilation, which are unsure and outweighed by the immediate benefits of the parbreak-representation
Diffstat (limited to 'src')
-rw-r--r--src/layout/tree.rs13
-rw-r--r--src/syntax/parsing.rs138
-rw-r--r--src/syntax/tree.rs4
3 files changed, 62 insertions, 93 deletions
diff --git a/src/layout/tree.rs b/src/layout/tree.rs
index e500c4ba..adc179bc 100644
--- a/src/layout/tree.rs
+++ b/src/layout/tree.rs
@@ -63,6 +63,10 @@ impl<'a> TreeLayouter<'a> {
match &node.v {
SyntaxNode::Spacing => self.layout_space(),
SyntaxNode::Linebreak => self.layouter.finish_line(),
+ SyntaxNode::Parbreak => self.layouter.add_secondary_spacing(
+ self.style.text.paragraph_spacing(),
+ SpacingKind::PARAGRAPH,
+ ),
SyntaxNode::ToggleItalic => {
self.style.text.italic = !self.style.text.italic;
@@ -80,7 +84,6 @@ impl<'a> TreeLayouter<'a> {
}
SyntaxNode::Raw(lines) => self.layout_raw(lines).await,
- SyntaxNode::Par(par) => self.layout_par(par).await,
SyntaxNode::Call(call) => {
self.layout_call(Spanned::new(call, node.span)).await;
}
@@ -128,14 +131,6 @@ impl<'a> TreeLayouter<'a> {
self.style.text.fallback = fallback;
}
- async fn layout_par(&mut self, par: &SyntaxTree) {
- self.layout_tree(par).await;
- self.layouter.add_secondary_spacing(
- self.style.text.paragraph_spacing(),
- SpacingKind::PARAGRAPH,
- );
- }
-
async fn layout_call(&mut self, call: Spanned<&CallExpr>) {
let ctx = LayoutContext {
style: &self.style,
diff --git a/src/syntax/parsing.rs b/src/syntax/parsing.rs
index 29a9d788..ea72c838 100644
--- a/src/syntax/parsing.rs
+++ b/src/syntax/parsing.rs
@@ -43,27 +43,20 @@ impl<'s> Parser<'s> {
impl Parser<'_> {
fn parse_body_contents(&mut self) -> SyntaxTree {
let mut tree = SyntaxTree::new();
- let mut par = SyntaxTree::new();
while let Some(token) = self.peek() {
- par.push(match token.v {
+ tree.push(match token.v {
// Starting from two newlines counts as a paragraph break, a single
// newline does not.
- Token::Space(newlines) => if newlines < 2 {
- self.with_span(SyntaxNode::Spacing)
+ Token::Space(newlines) => self.with_span(if newlines < 2 {
+ SyntaxNode::Spacing
} else {
- // End the current paragraph if it is not empty.
- if let (Some(first), Some(last)) = (par.first(), par.last()) {
- let span = Span::merge(first.span, last.span);
- let node = SyntaxNode::Par(std::mem::take(&mut par));
- tree.push(Spanned::new(node, span));
- }
- self.eat();
- continue;
- }
+ SyntaxNode::Parbreak
+ }),
+
Token::LineComment(_) | Token::BlockComment(_) => {
self.eat();
- continue
+ continue;
}
Token::LeftBracket => {
@@ -99,12 +92,6 @@ impl Parser<'_> {
});
}
- if let (Some(first), Some(last)) = (par.first(), par.last()) {
- let span = Span::merge(first.span, last.span);
- let node = SyntaxNode::Par(par);
- tree.push(Spanned::new(node, span));
- }
-
tree
}
}
@@ -640,6 +627,7 @@ mod tests {
use SyntaxNode::{
Spacing as S,
Linebreak as L,
+ Parbreak as P,
ToggleItalic as I,
ToggleBolder as B,
};
@@ -652,10 +640,6 @@ mod tests {
};
}
- macro_rules! P {
- ($($tts:tt)*) => { SyntaxNode::Par(Tree![@$($tts)*]) };
- }
-
macro_rules! F {
($($tts:tt)*) => { SyntaxNode::Call(Call!(@$($tts)*)) }
}
@@ -739,7 +723,7 @@ mod tests {
// Test expressions.
macro_rules! v {
($src:expr => $($tts:tt)*) => {
- t!(concat!("[val: ", $src, "]") => P![F!("val"; $($tts)*)]);
+ t!(concat!("[val: ", $src, "]") => F!("val"; $($tts)*));
}
}
@@ -802,40 +786,34 @@ mod tests {
#[test]
fn test_parse_simple_nodes() {
t!("" => );
- t!("hi" => P![T("hi")]);
- t!("*hi" => P![B, T("hi")]);
- t!("hi_" => P![T("hi"), I]);
- t!("hi you" => P![T("hi"), S, T("you")]);
- t!("\n\n\nhello" => P![T("hello")]);
- t!(r"a\ b" => P![T("a"), L, S, T("b")]);
- t!("`py`" => P![R!["py"]]);
- t!("`hi\nyou" => P![R!["hi", "you"]]);
+ t!("hi" => T("hi"));
+ t!("*hi" => B, T("hi"));
+ t!("hi_" => T("hi"), I);
+ t!("hi you" => T("hi"), S, T("you"));
+ t!("\n\n\nhello" => P, T("hello"));
+ t!(r"a\ b" => T("a"), L, S, T("b"));
+ t!("`py`" => R!["py"]);
+ t!("`hi\nyou" => R!["hi", "you"]);
e!("`hi\nyou" => s(1,3, 1,3, "expected backtick"));
- t!("`hi\\`du`" => P![R!["hi`du"]]);
- t!("💜\n\n 🌍" => P![T("💜")], P![T("🌍")]);
+ t!("`hi\\`du`" => R!["hi`du"]);
- ts!("hi" => s(0,0, 0,2, P![s(0,0, 0,2, T("hi"))]));
- ts!("*Hi*" => s(0,0, 0,4, P![
- s(0,0, 0,1, B), s(0,1, 0,3, T("Hi")), s(0,3, 0,4, B),
- ]));
- ts!("💜\n\n 🌍" =>
- s(0,0, 0,1, P![s(0,0, 0,1, T("💜"))]),
- s(2,1, 2,2, P![s(2,1, 2,2, T("🌍"))]),
- );
+ ts!("hi" => s(0,0, 0,2, T("hi")));
+ ts!("*Hi*" => s(0,0, 0,1, B), s(0,1, 0,3, T("Hi")), s(0,3, 0,4, B));
+ ts!("💜\n\n 🌍" => s(0,0, 0,1, T("💜")), s(0,1, 2,1, P), s(2,1, 2,2, T("🌍")));
}
#[test]
fn test_parse_comments() {
// In body.
- t!("hi// you\nw" => P![T("hi"), S, T("w")]);
- t!("first//\n//\nsecond" => P![T("first"), S, S, T("second")]);
- t!("first//\n \nsecond" => P![T("first")], P![T("second")]);
- t!("first/*\n \n*/second" => P![T("first"), T("second")]);
+ t!("hi// you\nw" => T("hi"), S, T("w"));
+ t!("first//\n//\nsecond" => T("first"), S, S, T("second"));
+ t!("first//\n \nsecond" => T("first"), P, T("second"));
+ t!("first/*\n \n*/second" => T("first"), T("second"));
e!("🌎\n*/n" => s(1,0, 1,2, "unexpected end of block comment"));
// In header.
- t!("[val:/*12pt*/]" => P![F!("val")]);
- t!("[val \n /* \n */:]" => P![F!("val")]);
+ t!("[val:/*12pt*/]" => F!("val"));
+ t!("[val \n /* \n */:]" => F!("val"));
e!("[val \n /* \n */:]" => );
e!("[val : 12, /* \n */ 14]" => );
}
@@ -852,7 +830,7 @@ mod tests {
#[test]
fn test_parse_function_names() {
// No closing bracket.
- t!("[" => P![F!("")]);
+ t!("[" => F!(""));
e!("[" => s(0,1, 0,1, "expected function name"),
s(0,1, 0,1, "expected closing bracket"));
@@ -862,8 +840,8 @@ mod tests {
s(0,3, 0,3, "expected closing bracket"));
// A valid name.
- t!("[hi]" => P![F!("hi")]);
- t!("[ f]" => P![F!("f")]);
+ t!("[hi]" => F!("hi"));
+ t!("[ f]" => F!("f"));
// An invalid name.
e!("[12]" => s(0,1, 0,3, "expected function name, found number"));
@@ -871,12 +849,16 @@ mod tests {
}
#[test]
- fn test_parse_subgroups() {
+ fn test_parse_chaining() {
// Things the parser has to make sense of
- t!("[hi: (5.0, 2.1 >> you]" => P![F!("hi"; Table![Num(5.0), Num(2.1)], Tree![F!("you")])]);
- t!("[bold: 400, >> emph >> sub: 1cm]" => P![F!("bold"; Num(400.0), Tree![F!("emph"; Tree!(F!("sub"; Len(Length::cm(1.0)))))])]);
- t!("[box >> pad: 1pt][Hi]" => P![F!("box"; Tree![F!("pad"; Len(Length::pt(1.0)), Tree!(P![T("Hi")]))])]);
- t!("[box >>][Hi]" => P![F!("box"; Tree![P![T("Hi")]])]);
+ t!("[hi: (5.0, 2.1 >> you]" => F!("hi"; Table![Num(5.0), Num(2.1)], Tree![F!("you")]));
+ t!("[box >>][Hi]" => F!("box"; Tree![T("Hi")]));
+ t!("[box >> pad: 1pt][Hi]" => F!("box"; Tree![
+ F!("pad"; Len(Length::pt(1.0)), Tree!(T("Hi")))
+ ]));
+ t!("[bold: 400, >> emph >> sub: 1cm]" => F!("bold"; Num(400.0), Tree![
+ F!("emph"; Tree!(F!("sub"; Len(Length::cm(1.0)))))
+ ]));
// Errors for unclosed / empty predecessor groups
e!("[hi: (5.0, 2.1 >> you]" => s(0, 15, 0, 15, "expected closing paren"));
@@ -889,7 +871,7 @@ mod tests {
e!("[val:]" => );
// Wrong token.
- t!("[val=]" => P![F!("val")]);
+ t!("[val=]" => F!("val"));
e!("[val=]" => s(0,4, 0,4, "expected colon"));
e!("[val/🌎:$]" => s(0,4, 0,4, "expected colon"));
@@ -902,27 +884,25 @@ mod tests {
#[test]
fn test_parse_function_bodies() {
- t!("[val: 1][*Hi*]" => P![F!("val"; Num(1.0), Tree![P![B, T("Hi"), B]])]);
+ t!("[val: 1][*Hi*]" => F!("val"; Num(1.0), Tree![B, T("Hi"), B]));
e!(" [val][ */ ]" => s(0,8, 0,10, "unexpected end of block comment"));
// Raw in body.
- t!("[val][`Hi]`" => P![F!("val"; Tree![P![R!["Hi]"]]])]);
+ t!("[val][`Hi]`" => F!("val"; Tree![R!["Hi]"]]));
e!("[val][`Hi]`" => s(0,11, 0,11, "expected closing bracket"));
// Crazy.
- t!("[v][[v][v][v]]" => P![F!("v"; Tree![P![
- F!("v"; Tree![P![T("v")]]), F!("v")
- ]])]);
+ t!("[v][[v][v][v]]" => F!("v"; Tree![F!("v"; Tree![T("v")]), F!("v")]));
// Spanned.
- ts!(" [box][Oh my]" => s(0,0, 0,13, P![
+ ts!(" [box][Oh my]" =>
s(0,0, 0,1, S),
s(0,1, 0,13, F!(s(0,2, 0,5, "box");
- s(0,6, 0,13, Tree![s(0,7, 0,12, P![
+ s(0,6, 0,13, Tree![
s(0,7, 0,9, T("Oh")), s(0,9, 0,10, S), s(0,10, 0,12, T("my"))
- ])])
+ ])
))
- ]));
+ );
}
#[test]
@@ -943,7 +923,7 @@ mod tests {
v!("\"a\n[]\\\"string\"" => Str("a\n[]\"string"));
// Content.
- v!("{_hi_}" => Tree![P![I, T("hi"), I]]);
+ v!("{_hi_}" => Tree![I, T("hi"), I]);
e!("[val: {_hi_}]" => );
v!("[hi]" => Tree![F!["hi"]]);
e!("[val: [hi]]" => );
@@ -961,9 +941,7 @@ mod tests {
s(0,13, 0,13, "expected closing bracket"));
// Spanned.
- ts!("[val: 1.4]" => s(0,0, 0,10, P![
- s(0,0, 0,10, F!(s(0,1, 0,4, "val"); s(0,6, 0,9, Num(1.4))))
- ]));
+ ts!("[val: 1.4]" => s(0,0, 0,10, F!(s(0,1, 0,4, "val"); s(0,6, 0,9, Num(1.4)))));
}
#[test]
@@ -993,17 +971,15 @@ mod tests {
v!("3/4*5" => Mul(Div(Num(3.0), Num(4.0)), Num(5.0)));
// Spanned.
- ts!("[val: 1 + 3]" => s(0,0, 0,12, P![s(0,0, 0,12, F!(
+ ts!("[val: 1 + 3]" => s(0,0, 0,12, F!(
s(0,1, 0,4, "val"); s(0,6, 0,11, Add(
s(0,6, 0,7, Num(1.0)),
s(0,10, 0,11, Num(3.0)),
))
- ))]));
+ )));
// Span of parenthesized expression contains parens.
- ts!("[val: (1)]" => s(0,0, 0,10, P![
- s(0,0, 0,10, F!(s(0,1, 0,4, "val"); s(0,6, 0,9, Num(1.0))))
- ]));
+ ts!("[val: (1)]" => s(0,0, 0,10, F!(s(0,1, 0,4, "val"); s(0,6, 0,9, Num(1.0)))));
// Invalid expressions.
v!("4pt--" => Len(Length::pt(4.0)));
@@ -1030,12 +1006,10 @@ mod tests {
d!("[val: f(key=hi)]" => s(0,8, 0,11, TableKey));
// Spanned with spacing around keyword arguments.
- ts!("[val: \n hi \n = /* //\n */ \"s\n\"]" => s(0,0, 4,2, P![
- s(0,0, 4,2, F!(
- s(0,1, 0,4, "val");
- s(1,1, 1,3, "hi") => s(3,4, 4,1, Str("s\n"))
- ))
- ]));
+ ts!("[val: \n hi \n = /* //\n */ \"s\n\"]" => s(0,0, 4,2, F!(
+ s(0,1, 0,4, "val");
+ s(1,1, 1,3, "hi") => s(3,4, 4,1, Str("s\n"))
+ )));
e!("[val: \n hi \n = /* //\n */ \"s\n\"]" => );
}
diff --git a/src/syntax/tree.rs b/src/syntax/tree.rs
index ae2e9892..31f334d2 100644
--- a/src/syntax/tree.rs
+++ b/src/syntax/tree.rs
@@ -23,6 +23,8 @@ pub enum SyntaxNode {
Spacing,
/// A forced line break.
Linebreak,
+ /// A paragraph break.
+ Parbreak,
/// Italics were enabled / disabled.
ToggleItalic,
/// Bolder was enabled / disabled.
@@ -31,8 +33,6 @@ pub enum SyntaxNode {
Text(String),
/// Lines of raw text.
Raw(Vec<String>),
- /// A paragraph of child nodes.
- Par(SyntaxTree),
/// A function call.
Call(CallExpr),
}