summaryrefslogtreecommitdiff
path: root/tests/typ/expr
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-02-20 17:53:40 +0100
committerLaurenz <laurmaedje@gmail.com>2021-02-20 23:34:33 +0100
commit05727bfc3a9cfd45a8e2028dfd0806f7a8f88015 (patch)
tree6c0b66eb2a9dff224cb39eb6ccb478656a706c04 /tests/typ/expr
parent927341d93ae29678095e3b874bd68bfc57d4bc05 (diff)
Reorganize tests 🔀
Diffstat (limited to 'tests/typ/expr')
-rw-r--r--tests/typ/expr/array.typ43
-rw-r--r--tests/typ/expr/assoc.typ18
-rw-r--r--tests/typ/expr/block-invalid.typ37
-rw-r--r--tests/typ/expr/block-scoping.typ35
-rw-r--r--tests/typ/expr/block.typ38
-rw-r--r--tests/typ/expr/call-invalid.typ44
-rw-r--r--tests/typ/expr/call.typ40
-rw-r--r--tests/typ/expr/dict.typ20
-rw-r--r--tests/typ/expr/ops-invalid.typ59
-rw-r--r--tests/typ/expr/ops.typ150
-rw-r--r--tests/typ/expr/prec.typ30
11 files changed, 514 insertions, 0 deletions
diff --git a/tests/typ/expr/array.typ b/tests/typ/expr/array.typ
new file mode 100644
index 00000000..c9383501
--- /dev/null
+++ b/tests/typ/expr/array.typ
@@ -0,0 +1,43 @@
+// Test arrays.
+
+---
+// Empty.
+{()}
+
+// Not an array, just a parenthesized expression.
+{(1)}
+
+// One item and trailing comma.
+{(-1,)}
+
+// No trailing comma.
+{(true, false)}
+
+// Multiple lines and items and trailing comma.
+{("1"
+ , #002
+ ,)}
+
+// Error: 3 expected closing paren
+{(}
+
+// Error: 2-3 expected expression, found closing paren
+{)}
+
+// Error: 2:4 expected comma
+// Error: 1:4-1:6 expected expression, found end of block comment
+{(1*/2)}
+
+// Error: 6-8 expected expression, found invalid token
+{(1, 1u 2)}
+
+// Error: 3-4 expected expression, found comma
+{(,1)}
+
+// Missing expression makes named pair incomplete, making this an empty array.
+// Error: 5 expected expression
+{(a:)}
+
+// Named pair after this is already identified as an array.
+// Error: 6-10 expected expression, found named pair
+{(1, b: 2)}
diff --git a/tests/typ/expr/assoc.typ b/tests/typ/expr/assoc.typ
new file mode 100644
index 00000000..19c56951
--- /dev/null
+++ b/tests/typ/expr/assoc.typ
@@ -0,0 +1,18 @@
+// Test operator associativity.
+// Ref: false
+
+---
+// Math operators are left-associative.
+#test(10 / 2 / 2 == (10 / 2) / 2, true)
+#test(10 / 2 / 2 == 10 / (2 / 2), false)
+#test(1 / 2 * 3, 1.5)
+
+---
+// Assignment is right-associative.
+{
+ let x = 1
+ let y = 2
+ x = y = "ok"
+ test(x, none)
+ test(y, "ok")
+}
diff --git a/tests/typ/expr/block-invalid.typ b/tests/typ/expr/block-invalid.typ
new file mode 100644
index 00000000..d98bf06b
--- /dev/null
+++ b/tests/typ/expr/block-invalid.typ
@@ -0,0 +1,37 @@
+// Test invalid code block syntax.
+
+---
+// Multiple unseparated expressions in one line.
+
+// Error: 2-4 expected expression, found invalid token
+{1u}
+
+// Should output `1`.
+// Error: 3 expected semicolon or line break
+{0 1}
+
+// Should output `2`.
+// Error: 2:12 expected semicolon or line break
+// Error: 1:22 expected semicolon or line break
+{let x = -1 let y = 3 x + y}
+
+// Should output `3`.
+{
+ // Error: 9-12 expected identifier, found string
+ for "v"
+
+ // Error: 10 expected keyword `in`
+ for v let z = 1 + 2
+
+ z
+}
+
+---
+// Ref: false
+// Error: 3:1 expected closing brace
+{
+
+---
+// Ref: false
+// Error: 1-2 unexpected closing brace
+}
diff --git a/tests/typ/expr/block-scoping.typ b/tests/typ/expr/block-scoping.typ
new file mode 100644
index 00000000..7bb98969
--- /dev/null
+++ b/tests/typ/expr/block-scoping.typ
@@ -0,0 +1,35 @@
+// Test scoping with blocks.
+// Ref: false
+
+---
+// Block in template does not create a scope.
+{ let x = 1 }
+#test(x, 1)
+
+---
+// Block in expression does create a scope.
+#let a = {
+ let b = 1
+ b
+}
+
+#test(a, 1)
+
+// Error: 2-3 unknown variable
+{b}
+
+---
+// Multiple nested scopes.
+{
+ let a = "a1"
+ {
+ let a = "a2"
+ {
+ test(a, "a2")
+ let a = "a3"
+ test(a, "a3")
+ }
+ test(a, "a2")
+ }
+ test(a, "a1")
+}
diff --git a/tests/typ/expr/block.typ b/tests/typ/expr/block.typ
new file mode 100644
index 00000000..196e6c14
--- /dev/null
+++ b/tests/typ/expr/block.typ
@@ -0,0 +1,38 @@
+// Test code blocks.
+
+---
+All none
+
+// Nothing evaluates to none.
+{}
+
+// Let evaluates to none.
+{ let v = 0 }
+
+// Trailing none evaluates to none.
+{
+ type("")
+ none
+}
+
+---
+// Evaluates to single expression.
+{ "Hello" }
+
+// Evaluates to trailing expression.
+{ let x = "Hel"; x + "lo" }
+
+// Evaluates to concatenation of for loop bodies.
+{
+ let parts = ("Hel", "lo")
+ for s in parts [{s}]
+}
+
+---
+// Works the same way in code environment.
+// Ref: false
+#test(3, {
+ let x = 1
+ let y = 2
+ x + y
+})
diff --git a/tests/typ/expr/call-invalid.typ b/tests/typ/expr/call-invalid.typ
new file mode 100644
index 00000000..0ed5246f
--- /dev/null
+++ b/tests/typ/expr/call-invalid.typ
@@ -0,0 +1,44 @@
+// Test invalid function calls.
+
+---
+// Error: 1-2 unexpected invalid token
+#
+
+---
+// Error: 7-8 expected expression, found colon
+#args(:)
+
+// Error: 10-12 expected expression, found end of block comment
+#args(a:1*/)
+
+// Error: 8 expected comma
+#args(1 2)
+
+// Error: 2:7-2:8 expected identifier
+// Error: 1:9 expected expression
+#args(1:)
+
+// Error: 7-8 expected identifier
+#args(1:2)
+
+// Error: 7-10 expected identifier
+{args((x):1)}
+
+---
+#let x = "string"
+
+// Error: 1-3 expected function, found string
+#x()
+
+---
+// Error: 3:1 expected closing bracket
+#args[`a]`
+
+---
+// Error: 7 expected closing paren
+{args(}
+
+---
+// Error: 3:1 expected quote
+// Error: 2:1 expected closing paren
+#args("]
diff --git a/tests/typ/expr/call.typ b/tests/typ/expr/call.typ
new file mode 100644
index 00000000..213d5554
--- /dev/null
+++ b/tests/typ/expr/call.typ
@@ -0,0 +1,40 @@
+// Test function calls.
+
+---
+// One argument.
+#args(bold)
+
+// One argument and trailing comma.
+#args(1,)
+
+// One named argument.
+#args(a:2)
+
+// Mixed arguments.
+{args(1, b: "2", 3)}
+
+---
+// Different forms of template arguments.
+// Ref: true
+
+#let a = "a"
+
+#args[a] \
+#args(a) \
+#args(a, [b]) \
+#args(a)[b] \
+
+// Template can be argument or body depending on whitespace.
+#if "template" == type[b] [Sure ]
+#if "template" == type [Nope.] #else [thing.]
+
+// Should output `<function args> (Okay.)`.
+#args (Okay.)
+
+---
+// Call function assigned to variable.
+#let alias = type
+#test(alias(alias), "function")
+
+// Library function `font` returns template.
+#test(type(font(12pt)), "template")
diff --git a/tests/typ/expr/dict.typ b/tests/typ/expr/dict.typ
new file mode 100644
index 00000000..655a3299
--- /dev/null
+++ b/tests/typ/expr/dict.typ
@@ -0,0 +1,20 @@
+// Test dictionaries.
+
+---
+// Empty
+{(:)}
+
+// Two pairs.
+{(a1: 1, a2: 2)}
+
+---
+// Simple expression after already being identified as a dictionary.
+// Error: 9-10 expected named pair, found expression
+{(a: 1, b)}
+
+// Identified as dictionary due to initial colon.
+// Error: 4:4-4:5 expected named pair, found expression
+// Error: 3:5 expected comma
+// Error: 2:12-2:16 expected identifier
+// Error: 1:17-1:18 expected expression, found colon
+{(:1 b:[], true::)}
diff --git a/tests/typ/expr/ops-invalid.typ b/tests/typ/expr/ops-invalid.typ
new file mode 100644
index 00000000..f760ae31
--- /dev/null
+++ b/tests/typ/expr/ops-invalid.typ
@@ -0,0 +1,59 @@
+// Test invalid expressions.
+// Ref: false
+
+---
+// Missing expressions.
+
+// Error: 3 expected expression
+{-}
+
+// Error: 10 expected expression
+#test({1+}, 1)
+
+// Error: 10 expected expression
+#test({2*}, 2)
+
+---
+// Mismatched types.
+
+// Error: 2-12 cannot apply '+' to template
+{+([] + [])}
+
+// Error: 2-5 cannot apply '-' to string
+{-""}
+
+// Error: 2-8 cannot apply 'not' to array
+{not ()}
+
+// Error: 1:2-1:12 cannot apply '<=' to relative and relative
+{30% <= 40%}
+
+// Special messages for +, -, * and /.
+// Error: 4:03-4:10 cannot add integer and string
+// Error: 3:12-3:19 cannot subtract integer from relative
+// Error: 2:21-2:29 cannot multiply integer with boolean
+// Error: 1:31-1:39 cannot divide integer by length
+{(1 + "2", 40% - 1, 2 * true, 3 / 12pt)}
+
+// Error: 14-22 cannot apply '+=' to integer and string
+{ let x = 1; x += "2" }
+
+---
+// Bad left-hand sides of assignment.
+
+// Error: 3-6 cannot assign to this expression
+{ (x) = "" }
+
+// Error: 3-8 cannot assign to this expression
+{ 1 + 2 += 3 }
+
+// Error: 3-4 unknown variable
+{ z = 1 }
+
+// Error: 3-6 cannot assign to a constant
+{ box = "hi" }
+
+// Works if we define box beforehand
+// (since then it doesn't resolve to the standard library version anymore).
+#let box = ""
+{ box = "hi" }
diff --git a/tests/typ/expr/ops.typ b/tests/typ/expr/ops.typ
new file mode 100644
index 00000000..2390b7b4
--- /dev/null
+++ b/tests/typ/expr/ops.typ
@@ -0,0 +1,150 @@
+// Test binary expressions.
+// Ref: false
+
+---
+// Test template addition.
+// Ref: true
+{[*Hello ] + [world!*]}
+
+---
+// Test math operators.
+
+// Test plus and minus.
+#for v in (1, 3.14, 12pt, 45deg, 90%, 13% + 10pt) {
+ // Test plus.
+ test(+v, v)
+
+ // Test minus.
+ test(-v, -1 * v)
+ test(--v, v)
+
+ // Test combination.
+ test(-++ --v, -v)
+}
+
+#test(-(4 + 2), 6-12)
+
+// Addition.
+#test(2 + 4, 6)
+#test("a" + "b", "ab")
+#test((1, 2) + (3, 4), (1, 2, 3, 4))
+#test((a: 1) + (b: 2, c: 3), (a: 1, b: 2, c: 3))
+
+// Subtraction.
+#test(1-4, 3*-1)
+#test(4cm - 2cm, 2cm)
+#test(1e+2-1e-2, 99.99)
+
+// Multiplication.
+#test(2 * 4, 8)
+
+// Division.
+#test(12pt/.4, 30pt)
+#test(7 / 2, 3.5)
+
+// Combination.
+#test(3-4 * 5 < -10, true)
+#test({ let x; x = 1 + 4*5 >= 21 and { x = "a"; x + "b" == "ab" }; x }, true)
+
+// Mathematical identities.
+#let nums = (1, 3.14, 12pt, 45deg, 90%, 13% + 10pt)
+#for v in nums {
+ // Test plus and minus.
+ test(v + v - v, v)
+ test(v - v - v, -v)
+
+ // Test plus/minus and multiplication.
+ test(v - v, 0 * v)
+ test(v + v, 2 * v)
+
+ // Integer addition does not give a float.
+ if type(v) != "integer" {
+ test(v + v, 2.0 * v)
+ }
+
+ // Linears cannot be divided by themselves.
+ if type(v) != "linear" {
+ test(v / v, 1.0)
+ test(v / v == 1, true)
+ }
+}
+
+// Make sure length, relative and linear
+// - can all be added to / subtracted from each other,
+// - multiplied with integers and floats,
+// - divided by floats.
+#let dims = (10pt, 30%, 50% + 3cm)
+#for a in dims {
+ for b in dims {
+ test(type(a + b), type(a - b))
+ }
+
+ for b in (7, 3.14) {
+ test(type(a * b), type(a))
+ test(type(b * a), type(a))
+ test(type(a / b), type(a))
+ }
+}
+
+---
+// Test boolean operators.
+
+// Test not.
+#test(not true, false)
+#test(not false, true)
+
+// And.
+#test(false and false, false)
+#test(false and true, false)
+#test(true and false, false)
+#test(true and true, true)
+
+// Or.
+#test(false or false, false)
+#test(false or true, true)
+#test(true or false, true)
+#test(true or true, true)
+
+// Short-circuiting.
+#test(false and dont-care, false)
+#test(true or dont-care, true)
+
+---
+// Test equality operators.
+
+#test(1 == "hi", false)
+#test(1 == 1.0, true)
+#test(30% == 30% + 0cm, true)
+#test(1in == 0% + 72pt, true)
+#test(30% == 30% + 1cm, false)
+#test("ab" == "a" + "b", true)
+#test(() == (1,), false)
+#test((1, 2, 3) == (1, 2.0) + (3,), true)
+#test((:) == (a: 1), false)
+#test((a: 2 - 1.0, b: 2) == (b: 2, a: 1), true)
+#test([*Hi*] == [*Hi*], true)
+
+#test("a" != "a", false)
+#test([*] != [_], true)
+
+---
+// Test comparison operators.
+
+#test(13 * 3 < 14 * 4, true)
+#test(5 < 10, true)
+#test(5 > 5, false)
+#test(5 <= 5, true)
+#test(5 <= 4, false)
+#test(45deg < 1rad, true)
+
+---
+// Test assignment operators.
+
+#let x = 0
+{ x = 10 } #test(x, 10)
+{ x -= 5 } #test(x, 5)
+{ x += 1 } #test(x, 6)
+{ x *= x } #test(x, 36)
+{ x /= 2.0 } #test(x, 18.0)
+{ x = "some" } #test(x, "some")
+{ x += "thing" } #test(x, "something")
diff --git a/tests/typ/expr/prec.typ b/tests/typ/expr/prec.typ
new file mode 100644
index 00000000..e64e583c
--- /dev/null
+++ b/tests/typ/expr/prec.typ
@@ -0,0 +1,30 @@
+// Test operator precedence.
+// Ref: false
+
+---
+// Multiplication binds stronger than addition.
+#test(1+2*-3, -5)
+
+// Subtraction binds stronger than comparison.
+#test(3 == 5 - 2, true)
+
+// Boolean operations bind stronger than '=='.
+#test("a" == "a" and 2 < 3, true)
+#test(not "b" == "b", false)
+
+// Assignment binds stronger than boolean operations.
+// Error: 2-7 cannot assign to this expression
+{not x = "a"}
+
+---
+// Parentheses override precedence.
+#test((1), 1)
+#test((1+2)*-3, -9)
+
+// Error: 14 expected closing paren
+#test({(1 + 1}, 2)
+
+---
+// Precedence doesn't matter for chained unary operators.
+// Error: 2-11 cannot apply '-' to boolean
+{-not true}