summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-01-16 15:08:03 +0100
committerLaurenz <laurmaedje@gmail.com>2021-01-16 15:08:03 +0100
commit51efb0f4d69943e290d977673970cd3c8ada306f (patch)
tree6478ba698749eec120755e283adf7932a6a98d2f
parentd763f0f5a6a700352ee8926c15c8e58624f705c9 (diff)
Port remaining parser tests 🚚
-rw-r--r--src/eval/state.rs10
-rw-r--r--src/font.rs1
-rw-r--r--src/geom/length.rs6
-rw-r--r--src/parse/mod.rs3
-rw-r--r--src/parse/tests.rs291
-rw-r--r--src/parse/tokens.rs16
-rw-r--r--src/syntax/span.rs1
-rw-r--r--tests/ref/lang/blocks.pngbin0 -> 1363 bytes
-rw-r--r--tests/ref/lang/bracket-call.pngbin22962 -> 22257 bytes
-rw-r--r--tests/ref/lang/expressions.pngbin0 -> 2351 bytes
-rw-r--r--tests/ref/lang/raw.pngbin0 -> 4212 bytes
-rw-r--r--tests/ref/lang/values.pngbin24313 -> 8531 bytes
-rw-r--r--tests/typ/lang/blocks.typ21
-rw-r--r--tests/typ/lang/bracket-call.typ15
-rw-r--r--tests/typ/lang/expressions.typ37
-rw-r--r--tests/typ/lang/raw.typ23
16 files changed, 121 insertions, 303 deletions
diff --git a/src/eval/state.rs b/src/eval/state.rs
index a88dfd07..21fb7fb6 100644
--- a/src/eval/state.rs
+++ b/src/eval/state.rs
@@ -11,15 +11,15 @@ use crate::paper::{Paper, PaperClass, PAPER_A4};
/// The evaluation state.
#[derive(Debug, Clone, PartialEq)]
pub struct State {
- /// The current page state.
+ /// The current page settings.
pub page: PageSettings,
- /// The current paragraph state.
+ /// The current paragraph settings.
pub par: ParSettings,
- /// The current font state.
+ /// The current font settings.
pub font: FontSettings,
- /// The current directions.
+ /// The current layouting directions.
pub dirs: LayoutDirs,
- /// The current alignments.
+ /// The current alignments of an item in its parent.
pub align: ChildAlign,
}
diff --git a/src/font.rs b/src/font.rs
index 01ea48c0..e5718331 100644
--- a/src/font.rs
+++ b/src/font.rs
@@ -51,6 +51,7 @@ impl ContainsChar for FaceBuf {
}
}
+/// Simplify font loader construction from an [`FsIndex`].
#[cfg(feature = "fs")]
pub trait FsIndexExt {
/// Create a font loader backed by a boxed [`FsSource`] which serves all
diff --git a/src/geom/length.rs b/src/geom/length.rs
index 00803e13..1a45c63c 100644
--- a/src/geom/length.rs
+++ b/src/geom/length.rs
@@ -99,10 +99,12 @@ impl Length {
impl Display for Length {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ use LengthUnit::*;
+
// Format with the unit that yields the shortest output, preferring
- // larger units when tied.
+ // larger / metrics units when tied.
let mut buf = ryu::Buffer::new();
- let unit = [LengthUnit::Cm, LengthUnit::Mm, LengthUnit::Pt]
+ let unit = [Cm, Mm, In, Pt]
.iter()
.copied()
.min_by_key(|&unit| buf.format(self.to_unit(unit)).len())
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index 5fdaa4ce..b6836d38 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -412,6 +412,3 @@ fn expr_let(p: &mut Parser) -> Option<Expr> {
p.end_group();
pat.map(|pat| Expr::Let(ExprLet { pat, expr: rhs }))
}
-
-#[cfg(test)]
-mod tests;
diff --git a/src/parse/tests.rs b/src/parse/tests.rs
deleted file mode 100644
index 9a35f552..00000000
--- a/src/parse/tests.rs
+++ /dev/null
@@ -1,291 +0,0 @@
-#![allow(non_snake_case)]
-
-use std::fmt::Debug;
-
-use super::parse;
-use crate::diag::{Diag, Level, Pass};
-use crate::geom::LengthUnit;
-use crate::syntax::*;
-
-use BinOp::*;
-use Expr::{Float, Int, Length};
-use Node::{Space, Strong};
-use UnOp::{Neg, Pos};
-
-macro_rules! t {
- ($src:literal
- nodes: [$($node:expr),* $(,)?]
- $(, errors: [$($err:expr),* $(,)?])?
- $(, warnings: [$($warn:expr),* $(,)?])?
- $(, spans: $spans:expr)?
- $(,)?
- ) => {{
- #[allow(unused)]
- let mut spans = false;
- $(spans = $spans;)?
-
- let Pass { output, feedback } = parse($src);
- check($src, Template![@$($node),*], output, spans);
- check(
- $src,
- vec![
- $($(into!($err).map(|s: &str| Diag::new(Level::Error, s)),)*)?
- $($(into!($warn).map(|s: &str| Diag::new(Level::Warning, s)),)*)?
- ],
- feedback.diags,
- true,
- );
- }};
-
- ($src:literal $($node:expr),* $(,)?) => {
- t!($src nodes: [$($node),*]);
- };
-}
-
-/// Assert that expected and found are equal, printing both and the source of
-/// the test case if they aren't.
-///
-/// When `cmp_spans` is false, spans are ignored.
-#[track_caller]
-pub fn check<T>(src: &str, exp: T, found: T, cmp_spans: bool)
-where
- T: Debug + PartialEq,
-{
- Span::set_cmp(cmp_spans);
-
- if exp != found {
- println!("source: {:?}", src);
- println!("expected: {:#?}", exp);
- println!("found: {:#?}", found);
- panic!("test failed");
- }
-
- Span::set_cmp(true);
-}
-
-/// Shorthand for `Spanned::new`.
-fn S<T>(span: impl Into<Span>, v: T) -> Spanned<T> {
- Spanned::new(v, span)
-}
-
-// Enables tests to optionally specify spans.
-impl<T> From<T> for Spanned<T> {
- fn from(t: T) -> Self {
- Spanned::zero(t)
- }
-}
-
-/// Shorthand for `Into::<Spanned<_>>::into`.
-macro_rules! into {
- ($val:expr) => {
- Into::<Spanned<_>>::into($val)
- };
-}
-
-fn Text(text: &str) -> Node {
- Node::Text(text.into())
-}
-
-fn Raw(lang: Option<&str>, lines: &[&str], inline: bool) -> Node {
- Node::Raw(NodeRaw {
- lang: lang.map(|id| Ident(id.into())),
- lines: lines.iter().map(ToString::to_string).collect(),
- inline,
- })
-}
-
-fn Id(ident: &str) -> Expr {
- Expr::Ident(Ident(ident.to_string()))
-}
-
-fn Str(string: &str) -> Expr {
- Expr::Str(string.to_string())
-}
-
-fn Binary(
- lhs: impl Into<Spanned<Expr>>,
- op: impl Into<Spanned<BinOp>>,
- rhs: impl Into<Spanned<Expr>>,
-) -> Expr {
- Expr::Binary(ExprBinary {
- lhs: Box::new(lhs.into()),
- op: op.into(),
- rhs: Box::new(rhs.into()),
- })
-}
-
-fn Unary(op: impl Into<Spanned<UnOp>>, expr: impl Into<Spanned<Expr>>) -> Expr {
- Expr::Unary(ExprUnary {
- op: op.into(),
- expr: Box::new(expr.into()),
- })
-}
-
-fn Group(expr: Expr) -> Expr {
- Expr::Group(Box::new(expr))
-}
-
-macro_rules! Call {
- (@@$name:expr) => {
- Call!(@@$name, Args![])
- };
- (@@$name:expr, $args:expr) => {
- ExprCall {
- name: into!($name).map(|s: &str| Ident(s.into())),
- args: into!($args),
- }
- };
- (@$($tts:tt)*) => {
- Expr::Call(Call!(@@$($tts)*))
- };
- ($($tts:tt)*) => {
- Node::Expr(Call!(@$($tts)*))
- };
-}
-
-macro_rules! Args {
- (@$a:expr) => {
- Argument::Pos(into!($a))
- };
- (@$a:expr => $b:expr) => {
- Argument::Named(Named {
- name: into!($a).map(|s: &str| Ident(s.into())),
- expr: into!($b)
- })
- };
- ($($a:expr $(=> $b:expr)?),* $(,)?) => {
- vec![$(Args!(@$a $(=> $b)?)),*]
- };
-}
-
-macro_rules! Array {
- (@$($expr:expr),* $(,)?) => {
- vec![$(into!($expr)),*]
- };
- ($($tts:tt)*) => {
- Expr::Array(Array![@$($tts)*])
- };
-}
-
-macro_rules! Template {
- (@$($node:expr),* $(,)?) => {
- vec![$(into!($node)),*]
- };
- ($($tts:tt)*) => {
- Expr::Template(Template![@$($tts)*])
- };
-}
-
-macro_rules! Block {
- (@$expr:expr) => {
- Expr::Block(Box::new($expr))
- };
- ($expr:expr) => {
- Node::Expr(Block!(@$expr))
- };
-}
-
-#[test]
-fn test_parse_raw() {
- // Basic, mostly tested in tokenizer and resolver.
- t!("`py`" nodes: [S(0..4, Raw(None, &["py"], true))], spans: true);
- t!("`endless"
- nodes: [Raw(None, &["endless"], true)],
- errors: [S(8..8, "expected backtick(s)")]);
-}
-
-#[test]
-fn test_parse_groups() {
- // Test paren group.
- t!("{({1) + 3}"
- nodes: [Block!(Binary(Group(Block!(@Int(1))), Add, Int(3)))],
- errors: [S(4..4, "expected closing brace")]);
-
- // Test bracket group.
- t!("[)"
- nodes: [Call!("")],
- errors: [S(1..2, "expected function name, found closing paren"),
- S(2..2, "expected closing bracket")]);
-
- t!("[v [*]"
- nodes: [Call!("v", Args![Template![Strong]])],
- errors: [S(6..6, "expected closing bracket")]);
-
- // Test brace group.
- t!("{1 + [}"
- nodes: [Block!(Binary(Int(1), Add, Template![]))],
- errors: [S(6..6, "expected closing bracket")]);
-
- // Test subheader group.
- t!("[v (|u )]"
- nodes: [Call!("v", Args![Array![], Template![Call!("u")]])],
- errors: [S(4..4, "expected closing paren"),
- S(7..8, "expected expression, found closing paren")]);
-}
-
-#[test]
-fn test_parse_blocks() {
- // Basic with spans.
- t!("{1}" nodes: [S(0..3, Block!(Int(1)))], spans: true);
-
- // Function calls.
- t!("{f()}" Block!(Call!(@"f")));
- t!("{[[f]]}" Block!(Template![Call!("f")]));
-
- // Missing or bad value.
- t!("{}{1u}"
- nodes: [],
- errors: [S(1..1, "expected expression"),
- S(3..5, "expected expression, found invalid token")]);
-
- // Too much stuff.
- t!("{1 #{} end"
- nodes: [Block!(Int(1)), Space, Text("end")],
- errors: [S(3..4, "unexpected hex value"),
- S(4..5, "unexpected opening brace")]);
-}
-
-#[test]
-fn test_parse_expressions() {
- // Parentheses.
- t!("{(x)}{(1)}" Block!(Group(Id("x"))), Block!(Group(Int(1))));
-
- // Unary operations.
- t!("{+1}" Block!(Unary(Pos, Int(1))));
- t!("{-1}" Block!(Unary(Neg, Int(1))));
- t!("{--1}" Block!(Unary(Neg, Unary(Neg, Int(1)))));
-
- // Binary operations.
- t!(r#"{"x"+"y"}"# Block!(Binary(Str("x"), Add, Str("y"))));
- t!("{1-2}" Block!(Binary(Int(1), Sub, Int(2))));
- t!("{a * b}" Block!(Binary(Id("a"), Mul, Id("b"))));
- t!("{12pt/.4}" Block!(Binary(Length(12.0, LengthUnit::Pt), Div, Float(0.4))));
-
- // Associativity.
- t!("{1+2+3}" Block!(Binary(Binary(Int(1), Add, Int(2)), Add, Int(3))));
- t!("{1/2*3}" Block!(Binary(Binary(Int(1), Div, Int(2)), Mul, Int(3))));
-
- // Precedence.
- t!("{1+2*-3}" Block!(Binary(
- Int(1), Add, Binary(Int(2), Mul, Unary(Neg, Int(3))),
- )));
-
- // Confusion with floating-point literal.
- t!("{1e-3-4e+4}" Block!(Binary(Float(1e-3), Sub, Float(4e+4))));
-
- // Spans + parentheses winning over precedence.
- t!("{(1+2)*3}"
- nodes: [S(0..9, Block!(Binary(
- S(1..6, Group(Binary(S(2..3, Int(1)), S(3..4, Add), S(4..5, Int(2))))),
- S(6..7, Mul),
- S(7..8, Int(3)),
- )))],
- spans: true);
-
- // Errors.
- t!("{-}{1+}{2*}"
- nodes: [Block!(Int(1)), Block!(Int(2))],
- errors: [S(2..2, "expected expression"),
- S(6..6, "expected expression"),
- S(10..10, "expected expression")]);
-}
diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs
index 85fc4978..68b31a87 100644
--- a/src/parse/tokens.rs
+++ b/src/parse/tokens.rs
@@ -441,7 +441,6 @@ impl Debug for Tokens<'_> {
#[allow(non_snake_case)]
mod tests {
use super::*;
- use crate::parse::tests::check;
use Option::None;
use Token::{Ident, *};
@@ -539,10 +538,23 @@ mod tests {
let src = $src;
let exp = vec![$($token),*];
let found = Tokens::new(&src, $mode).collect::<Vec<_>>();
- check(&src, exp, found, false);
+ check(&src, exp, found);
}};
}
+ #[track_caller]
+ fn check<T>(src: &str, exp: T, found: T)
+ where
+ T: Debug + PartialEq,
+ {
+ if exp != found {
+ println!("source: {:?}", src);
+ println!("expected: {:#?}", exp);
+ println!("found: {:#?}", found);
+ panic!("test failed");
+ }
+ }
+
#[test]
fn test_tokenize_brackets() {
// Test in markup.
diff --git a/src/syntax/span.rs b/src/syntax/span.rs
index e924b03b..fbde35af 100644
--- a/src/syntax/span.rs
+++ b/src/syntax/span.rs
@@ -150,6 +150,7 @@ impl Span {
/// When set to `false` comparisons with `PartialEq` ignore spans.
#[cfg(test)]
+ #[allow(unused)]
pub(crate) fn set_cmp(cmp: bool) {
CMP_SPANS.with(|cell| cell.set(cmp));
}
diff --git a/tests/ref/lang/blocks.png b/tests/ref/lang/blocks.png
new file mode 100644
index 00000000..ca826c1b
--- /dev/null
+++ b/tests/ref/lang/blocks.png
Binary files differ
diff --git a/tests/ref/lang/bracket-call.png b/tests/ref/lang/bracket-call.png
index e7ba46e3..16afb187 100644
--- a/tests/ref/lang/bracket-call.png
+++ b/tests/ref/lang/bracket-call.png
Binary files differ
diff --git a/tests/ref/lang/expressions.png b/tests/ref/lang/expressions.png
new file mode 100644
index 00000000..309c32f1
--- /dev/null
+++ b/tests/ref/lang/expressions.png
Binary files differ
diff --git a/tests/ref/lang/raw.png b/tests/ref/lang/raw.png
new file mode 100644
index 00000000..f88194c0
--- /dev/null
+++ b/tests/ref/lang/raw.png
Binary files differ
diff --git a/tests/ref/lang/values.png b/tests/ref/lang/values.png
index 4205221b..762ad64e 100644
--- a/tests/ref/lang/values.png
+++ b/tests/ref/lang/values.png
Binary files differ
diff --git a/tests/typ/lang/blocks.typ b/tests/typ/lang/blocks.typ
new file mode 100644
index 00000000..cadd30dd
--- /dev/null
+++ b/tests/typ/lang/blocks.typ
@@ -0,0 +1,21 @@
+{1}
+
+// Function calls.
+{f(1)}
+{[[f 1]]}
+
+// Error: 1:2-1:2 expected expression
+{}
+
+// Error: 1:2-1:4 expected expression, found invalid token
+{1u}
+
+// Error: 1:5-1:5 expected closing brace
+{({1) + 2}
+
+// Error: 1:12-1:12 expected closing bracket
+{[*] + [ok*}
+
+// Error: 2:4-2:5 unexpected hex value
+// Error: 1:5-1:6 unexpected opening brace
+{1 #{} _end_
diff --git a/tests/typ/lang/bracket-call.typ b/tests/typ/lang/bracket-call.typ
index 642d6426..79667e61 100644
--- a/tests/typ/lang/bracket-call.typ
+++ b/tests/typ/lang/bracket-call.typ
@@ -41,6 +41,10 @@
// Error: 1:6-1:6 expected function name
[f 1|]
+// Error: 2:5-2:5 expected closing paren
+// Error: 1:8-1:9 expected expression, found closing paren
+[f (|f )]
+
// With actual functions.
[box width: 1cm | image "res/rhino.png"]
@@ -65,6 +69,7 @@
[f (x):1]
---
+// Ref: false
// Error: 2:2-2:3 a value of type string is not callable
#let x = "string";
[x]
@@ -77,6 +82,16 @@
[
---
+// Ref: false
+// Error: 2:2-2:3 expected function name, found closing paren
+// Error: 3:1-3:1 expected closing bracket
+[)
+
+---
+// Error: 3:1-3:1 expected closing bracket
+[f [*]
+
+---
// Error: 3:1-3:1 expected closing bracket
[f][`a]`
diff --git a/tests/typ/lang/expressions.typ b/tests/typ/lang/expressions.typ
new file mode 100644
index 00000000..01725289
--- /dev/null
+++ b/tests/typ/lang/expressions.typ
@@ -0,0 +1,37 @@
+#let a = 2;
+#let b = 4;
+
+// Unary operations.
+{+1}
+{-1}
+{--1}
+
+// Binary operations.
+{"a"+"b"}
+{1-2}
+{a * b}
+{12pt/.4}
+
+// Associativity.
+{1+2+3}
+{1/2*3}
+
+// Precedence.
+{1+2*-3}
+
+// Parentheses.
+{(a)}
+{(2)}
+{(1+2)*3}
+
+// Confusion with floating-point literal.
+{1e+2-1e-2}
+
+// Error: 1:3-1:3 expected expression
+{-}
+
+// Error: 1:4-1:4 expected expression
+{1+}
+
+// Error: 1:4-1:4 expected expression
+{2*}
diff --git a/tests/typ/lang/raw.typ b/tests/typ/lang/raw.typ
new file mode 100644
index 00000000..22eda139
--- /dev/null
+++ b/tests/typ/lang/raw.typ
@@ -0,0 +1,23 @@
+The keyword ``rust let``.
+
+`#let x = 1`
+`[f 1]`
+
+---
+[font 6pt]
+
+``py
+import this
+
+def say_hi():
+ print("Hello World!")
+``
+
+---
+````
+```backticks```
+````
+
+---
+// Error: 2:1-2:1 expected backtick(s)
+`endless