diff --git a/src/parse/tests.rs b/src/parse/tests.rs
index bb102476d..c87d43f74 100644
--- a/src/parse/tests.rs
+++ b/src/parse/tests.rs
@@ -261,128 +261,6 @@ fn test_parse_blocks() {
S(4..5, "unexpected opening brace")]);
}
-#[test]
-fn test_parse_bracket_funcs() {
- // Basic.
- t!("[function]" Call!("function"));
- t!("[ v ]" Call!("v"));
-
- // Body and no body.
- t!("[v][[f]]" Call!("v", Args![Template![Call!("f")]]));
- t!("[v][v][v]" Call!("v", Args![Template![Text("v")]]), Call!("v"));
- t!("[v] [f]" Call!("v"), Space, Call!("f"));
-
- // Spans.
- t!("[v 1][📐]"
- nodes: [S(0..11, Call!(S(1..2, "v"), S(3..4, Args![
- S(3..4, Int(1)),
- S(5..11, Template![S(6..10, Text("📐"))]),
- ])))],
- spans: true);
-
- // No name and no closing bracket.
- t!("["
- nodes: [Call!("")],
- errors: [S(1..1, "expected function name"),
- S(1..1, "expected closing bracket")]);
-
- // No name.
- t!("[]"
- nodes: [Call!("")],
- errors: [S(1..1, "expected function name")]);
-
- // Bad name.
- t!("[# 1]"
- nodes: [Call!("", Args![Int(1)])],
- errors: [S(1..2, "expected function name, found hex value")]);
-
- // String in header eats closing bracket.
- t!(r#"[v "]"#
- nodes: [Call!("v", Args![Str("]")])],
- errors: [S(5..5, "expected quote"),
- S(5..5, "expected closing bracket")]);
-
- // Raw in body eats closing bracket.
- t!("[v][`a]`"
- nodes: [Call!("v", Args![Template![Raw(None, &["a]"], true)]])],
- errors: [S(8..8, "expected closing bracket")]);
-}
-
-#[test]
-fn test_parse_chaining() {
- // Basic.
- t!("[a | b]" Call!("a", Args![Template![Call!("b")]]));
- t!("[a|b|c]" Call!("a", Args![Template![
- Call!("b", Args![Template![Call!("c")]])
- ]]));
-
- // With body and spans.
- t!("[a|b][💕]"
- nodes: [S(0..11, Call!(S(1..2, "a"), S(2..2, Args![
- S(3..11, Template![S(3..11, Call!(S(3..4, "b"), S(4..4, Args![
- S(5..11, Template![S(6..10, Text("💕"))])
- ])))])
- ])))],
- spans: true);
-
- // No name in second subheader.
- t!("[a 1|]"
- nodes: [Call!("a", Args![Int(1), Template![Call!("")]])],
- errors: [S(5..5, "expected function name")]);
-
- // No name in first subheader.
- t!("[|a true]"
- nodes: [Call!("", Args![Template![Call!("a", Args![Bool(true)])]])],
- errors: [S(1..1, "expected function name")]);
-}
-
-#[test]
-fn test_parse_arguments() {
- // Bracket functions.
- t!("[v a]" Call!("v", Args![Id("a")]));
- t!("[v 1,]" Call!("v", Args![Int(1)]));
- t!("[v a:2]" Call!("v", Args!["a" => Int(2)]));
-
- // Parenthesized function with nested array literal.
- t!(r#"{f(1, a: (2, 3), #004, b: "five")}"# Block!(Call!(@"f", Args![
- Int(1),
- "a" => Array![Int(2), Int(3)],
- Color(RgbaColor::new(0, 0, 0x44, 0xff)),
- "b" => Str("five"),
- ])));
-
- // Bad expression.
- t!("[v */]"
- nodes: [Call!("v", Args![])],
- errors: [S(3..5, "expected expression, found end of block comment")]);
-
- // Bad expression.
- t!("[v a:1:]"
- nodes: [Call!("v", Args!["a" => Int(1)])],
- errors: [S(6..7, "expected expression, found colon")]);
-
- // Missing comma between arguments.
- t!("[v 1 2]"
- nodes: [Call!("v", Args![Int(1), Int(2)])],
- errors: [S(4..4, "expected comma")]);
-
- // Name has to be identifier.
- t!("[v 1:]"
- nodes: [Call!("v", Args![])],
- errors: [S(3..4, "expected identifier"),
- S(5..5, "expected expression")]);
-
- // Name has to be identifier.
- t!("[v 1:2]"
- nodes: [Call!("v", Args![])],
- errors: [S(3..4, "expected identifier")]);
-
- // Name has to be identifier.
- t!("[v (x):1]"
- nodes: [Call!("v", Args![])],
- errors: [S(3..6, "expected identifier")]);
-}
-
#[test]
fn test_parse_expressions() {
// Parentheses.
diff --git a/tests/README.md b/tests/README.md
index 429207a5e..91bf8f49e 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -1,10 +1,9 @@
# Tests
+Directory structure:
- `typ`: Input files.
- `ref`: Reference images which the output is compared with to determine whether
- a test passed or failed. To keep things small, please run
- `oxipng -o max tests/ref/
` when creating or updating reference
- images (note that `
` can be `*` to optimize all images).
+ a test passed or failed.
- `res`: Resource files used by tests.
- `png`: PNG files produced by tests.
- `pdf`: PDF files produced by tests.
@@ -13,3 +12,12 @@ The test files are split into three categories:
- `full`: Tests of full documents.
- `lang`: Tests for specific language features.
- `library`: Tests for specific library functions.
+
+To keep things small, please optimize the reference images:
+```bash
+# One image
+oxipng -o max tests/ref/image.png
+
+# All images
+oxipng -r -o max tests/ref/*
+```
diff --git a/tests/ref/lang/bracket-call.png b/tests/ref/lang/bracket-call.png
new file mode 100644
index 000000000..e7ba46e31
Binary files /dev/null and b/tests/ref/lang/bracket-call.png differ
diff --git a/tests/ref/lang/comments.png b/tests/ref/lang/comments.png
index e3e42d231..df5e5b9cb 100644
Binary files a/tests/ref/lang/comments.png and b/tests/ref/lang/comments.png differ
diff --git a/tests/typ/lang/bracket-call.typ b/tests/typ/lang/bracket-call.typ
new file mode 100644
index 000000000..642d6426a
--- /dev/null
+++ b/tests/typ/lang/bracket-call.typ
@@ -0,0 +1,86 @@
+// Basic call, whitespace insignificant.
+[f], [ f ], [
+ f
+]
+
+[f bold]
+
+[f 1,]
+
+[f a:2]
+
+[f 1, a: (3, 4), 2, b: "5"]
+
+---
+// Body and no body.
+[f][[f]]
+
+// Lots of potential bodies.
+[f][f][f]
+
+// Multi-paragraph body.
+[box][
+ First
+
+ Second
+]
+
+---
+// Chained.
+[f | f]
+
+// Multi-chain.
+[f|f|f]
+
+// With body.
+[f | box][💕]
+
+// Error: 1:2-1:2 expected function name
+[|f true]
+
+// Error: 1:6-1:6 expected function name
+[f 1|]
+
+// With actual functions.
+[box width: 1cm | image "res/rhino.png"]
+
+---
+// Error: 1:4-1:6 expected expression, found end of block comment
+[f */]
+
+// Error: 1:7-1:8 expected expression, found colon
+[f a:1:]
+
+// Error: 1:5-1:5 expected comma
+[f 1 2]
+
+// Error: 2:4-2:5 expected identifier
+// Error: 1:6-1:6 expected expression
+[f 1:]
+
+// Error: 1:4-1:5 expected identifier
+[f 1:2]
+
+// Error: 1:4-1:7 expected identifier
+[f (x):1]
+
+---
+// Error: 2:2-2:3 a value of type string is not callable
+#let x = "string";
+[x]
+
+// Error: 1:2-1:3 expected function name, found hex value
+[# 1]
+
+// Error: 4:1-4:1 expected function name
+// Error: 3:1-3:1 expected closing bracket
+[
+
+---
+// Error: 3:1-3:1 expected closing bracket
+[f][`a]`
+
+---
+// Error: 3:1-3:1 expected quote
+// Error: 2:1-2:1 expected closing bracket
+[f "]
diff --git a/tests/typ/lang/comments.typ b/tests/typ/lang/comments.typ
index 56906d0ca..c5b04967b 100644
--- a/tests/typ/lang/comments.typ
+++ b/tests/typ/lang/comments.typ
@@ -8,7 +8,7 @@ C/*
*/D
// Test in expressions.
-[dump /*1*/ a: "b" //
+[f /*1*/ a: "b" //
, 1]
// Error: 1:7-1:9 unexpected end of block comment
diff --git a/tests/typeset.rs b/tests/typeset.rs
index 79a884ebf..3eaca6edf 100644
--- a/tests/typeset.rs
+++ b/tests/typeset.rs
@@ -16,12 +16,13 @@ use walkdir::WalkDir;
use typst::diag::{Diag, Feedback, Level, Pass};
use typst::env::{Env, ImageResource, ResourceLoader, SharedEnv};
-use typst::eval::{Args, EvalContext, State, Value, ValueFunc};
+use typst::eval::{Args, EvalContext, Scope, State, Value, ValueFunc};
use typst::export::pdf;
use typst::font::FontLoader;
use typst::geom::{Length, Point, Sides, Size, Spec};
use typst::layout::{Element, Expansion, Frame, Image};
use typst::parse::{LineMap, Scanner};
+use typst::pretty::{Pretty, Printer};
use typst::shaping::Shaped;
use typst::syntax::{Location, Pos, SpanVec, Spanned, WithSpan};
use typst::typeset;
@@ -183,13 +184,7 @@ fn test_part(i: usize, src: &str, env: &SharedEnv) -> (bool, Vec) {
state.page.size = Size::new(Length::pt(120.0), Length::raw(f64::INFINITY));
state.page.expand = Spec::new(Expansion::Fill, Expansion::Fit);
state.page.margins = Sides::uniform(Some(Length::pt(10.0).into()));
-
- pub fn dump(_: &mut EvalContext, args: &mut Args) -> Value {
- let (array, dict) = args.drain();
- Value::Array(vec![Value::Array(array), Value::Dict(dict)])
- }
-
- Rc::make_mut(&mut state.scope).set("dump", ValueFunc::new("dump", dump));
+ register_helpers(Rc::make_mut(&mut state.scope));
let Pass {
output: mut frames,
@@ -261,6 +256,31 @@ fn parse_metadata(src: &str, map: &LineMap) -> (bool, SpanVec) {
(compare_ref, diags)
}
+fn register_helpers(scope: &mut Scope) {
+ pub fn f(_: &mut EvalContext, args: &mut Args) -> Value {
+ let (array, dict) = args.drain();
+ let iter = array
+ .into_iter()
+ .map(|v| (None, v))
+ .chain(dict.into_iter().map(|(k, v)| (Some(k), v)));
+
+ let mut p = Printer::new();
+ p.push_str("f(");
+ p.join(iter, ", ", |(key, value), p| {
+ if let Some(key) = key {
+ p.push_str(&key);
+ p.push_str(": ");
+ }
+ value.pretty(p);
+ });
+ p.push_str(")");
+
+ Value::Str(p.finish())
+ }
+
+ scope.set("f", ValueFunc::new("f", f));
+}
+
fn print_diag(diag: &Spanned, map: &LineMap) {
let start = map.location(diag.span.start).unwrap();
let end = map.location(diag.span.end).unwrap();