From 8b58171d7ca036d71b32749286c251cc91bdd10e Mon Sep 17 00:00:00 2001 From: Laurenz Date: Tue, 18 May 2021 00:36:11 +0200 Subject: Reorganize test cases --- tests/typ/code/array.typ | 43 ++++++++++++ tests/typ/code/assoc.typ | 18 +++++ tests/typ/code/block-invalid.typ | 37 ++++++++++ tests/typ/code/block-scoping.typ | 35 ++++++++++ tests/typ/code/block.typ | 38 ++++++++++ tests/typ/code/call-invalid.typ | 44 ++++++++++++ tests/typ/code/call.typ | 70 +++++++++++++++++++ tests/typ/code/closure.typ | 64 +++++++++++++++++ tests/typ/code/comment.typ | 23 ++++++ tests/typ/code/dict.typ | 20 ++++++ tests/typ/code/for-pattern.typ | 35 ++++++++++ tests/typ/code/for.typ | 71 +++++++++++++++++++ tests/typ/code/if.typ | 71 +++++++++++++++++++ tests/typ/code/invalid.typ | 100 ++++++++++++++++++++++++++ tests/typ/code/let.typ | 63 +++++++++++++++++ tests/typ/code/ops-invalid.typ | 59 ++++++++++++++++ tests/typ/code/ops.typ | 147 +++++++++++++++++++++++++++++++++++++++ tests/typ/code/prec.typ | 30 ++++++++ tests/typ/code/repr.typ | 57 +++++++++++++++ tests/typ/code/while.typ | 43 ++++++++++++ 20 files changed, 1068 insertions(+) create mode 100644 tests/typ/code/array.typ create mode 100644 tests/typ/code/assoc.typ create mode 100644 tests/typ/code/block-invalid.typ create mode 100644 tests/typ/code/block-scoping.typ create mode 100644 tests/typ/code/block.typ create mode 100644 tests/typ/code/call-invalid.typ create mode 100644 tests/typ/code/call.typ create mode 100644 tests/typ/code/closure.typ create mode 100644 tests/typ/code/comment.typ create mode 100644 tests/typ/code/dict.typ create mode 100644 tests/typ/code/for-pattern.typ create mode 100644 tests/typ/code/for.typ create mode 100644 tests/typ/code/if.typ create mode 100644 tests/typ/code/invalid.typ create mode 100644 tests/typ/code/let.typ create mode 100644 tests/typ/code/ops-invalid.typ create mode 100644 tests/typ/code/ops.typ create mode 100644 tests/typ/code/prec.typ create mode 100644 tests/typ/code/repr.typ create mode 100644 tests/typ/code/while.typ (limited to 'tests/typ/code') diff --git a/tests/typ/code/array.typ b/tests/typ/code/array.typ new file mode 100644 index 00000000..c9383501 --- /dev/null +++ b/tests/typ/code/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/code/assoc.typ b/tests/typ/code/assoc.typ new file mode 100644 index 00000000..19c56951 --- /dev/null +++ b/tests/typ/code/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/code/block-invalid.typ b/tests/typ/code/block-invalid.typ new file mode 100644 index 00000000..d98bf06b --- /dev/null +++ b/tests/typ/code/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/code/block-scoping.typ b/tests/typ/code/block-scoping.typ new file mode 100644 index 00000000..7bb98969 --- /dev/null +++ b/tests/typ/code/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/code/block.typ b/tests/typ/code/block.typ new file mode 100644 index 00000000..196e6c14 --- /dev/null +++ b/tests/typ/code/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/code/call-invalid.typ b/tests/typ/code/call-invalid.typ new file mode 100644 index 00000000..0ed5246f --- /dev/null +++ b/tests/typ/code/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/code/call.typ b/tests/typ/code/call.typ new file mode 100644 index 00000000..dcf11806 --- /dev/null +++ b/tests/typ/code/call.typ @@ -0,0 +1,70 @@ +// 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)} + +// Should output `() + 2`. +#args() + 2 + +--- +// Ref: false + +// Call function assigned to variable. +#let alias = type +#test(alias(alias), "function") + +// Library function `font` returns template. +#test(type(font(12pt)), "template") + +--- +// Callee expressions. +{ + // Error: 5-9 expected function, found boolean + true() + + // Wrapped in parens. + test((type)("hi"), "string") + + // Call the return value of a function. + let adder(dx) = x => x + dx + test(adder(2)(5), 7) +} + +#let f(x, body) = (y) => { + [{x}] + body + [{y}] +} + +// Call return value of function with body. +#f(1)[2](3) + +// Don't allow this to be a closure. +// Should output `x => "hi"`. +#let x = "x" +#x => "hi" + +--- +// Different forms of template arguments. + +#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 ` (Okay.)`. +#args (Okay.) diff --git a/tests/typ/code/closure.typ b/tests/typ/code/closure.typ new file mode 100644 index 00000000..86a6f632 --- /dev/null +++ b/tests/typ/code/closure.typ @@ -0,0 +1,64 @@ +// Test closures. +// Ref: false + +--- + +// Basic closure without captures. +{ + let adder = (x, y) => x + y + test(adder(2, 3), 5) +} + +// Pass closure as argument and return closure. +// Also uses shorthand syntax for a single argument. +{ + let chain = (f, g) => (x) => f(g(x)) + let f = x => x + 1 + let g = x => 2 * x + let h = chain(f, g) + test(h(2), 5) +} + +// Capture environment. +{ + let mark = "?" + let greet = { + let hi = "Hi" + name => { + hi + ", " + name + mark + } + } + + test(greet("Typst"), "Hi, Typst?") + + mark = "!" + test(greet("Typst"), "Hi, Typst!") +} + +// Don't leak environment. +{ + // Error: 18-19 unknown variable + let func() = x + let x = "hi" + + test(func(), error) +} + +--- +// Too few arguments. +{ + let types(x, y) = "[" + type(x) + ", " + type(y) + "]" + test(types(14%, 12pt), "[relative, length]") + + // Error: 16-22 missing argument: y + test(types("nope"), "[string, none]") +} + +// Too many arguments. +{ + let f(x) = x + 1 + + // Error: 2:10-2:15 unexpected argument + // Error: 1:17-1:24 unexpected argument + f(1, "two", () => x) +} diff --git a/tests/typ/code/comment.typ b/tests/typ/code/comment.typ new file mode 100644 index 00000000..25180211 --- /dev/null +++ b/tests/typ/code/comment.typ @@ -0,0 +1,23 @@ +// Test line and block comments. + +--- +// Line comment acts as spacing. +A// you +B + +// Block comment does not act as spacing. +C/* + /* */ +*/D + +// Works in code. +#test(type(/*1*/ 1) // +, "integer") + +--- +// End should not appear without start. +// Error: 1:7-1:9 unexpected end of block comment +/* */ */ + +// Unterminated is okay. +/* diff --git a/tests/typ/code/dict.typ b/tests/typ/code/dict.typ new file mode 100644 index 00000000..655a3299 --- /dev/null +++ b/tests/typ/code/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/code/for-pattern.typ b/tests/typ/code/for-pattern.typ new file mode 100644 index 00000000..a6a7c16a --- /dev/null +++ b/tests/typ/code/for-pattern.typ @@ -0,0 +1,35 @@ +// Test for loop patterns. +// Ref: false + +--- +#let out = () + +// Values of array. +#for v in (1, 2, 3) { + out += (v,) +} + +// Indices and values of array. +#for i, v in ("1", "2", "3") { + test(repr(i + 1), v) +} + +// Values of dictionary. +#for v in (a: 4, b: 5) { + out += (v,) +} + +// Keys and values of dictionary. +#for k, v in (a: 6, b: 7) { + out += (k,) + out += (v,) +} + +#test(out, (1, 2, 3, 4, 5, "a", 6, "b", 7)) + +--- +// Keys and values of strings. +// Error: 6-10 mismatched pattern +#for k, v in "hi" { + dont-care +} diff --git a/tests/typ/code/for.typ b/tests/typ/code/for.typ new file mode 100644 index 00000000..bca1af46 --- /dev/null +++ b/tests/typ/code/for.typ @@ -0,0 +1,71 @@ +// Test for loops. + +--- +// Empty array. +#for x in () [Nope] + +// Array. +#let sum = 0 +#for x in (1, 2, 3, 4, 5) { + sum += x +} + +#test(sum, 15) + +// Dictionary is not traversed in insertion order. +// Should output `age: 1, name: Typst,`. +#for k, v in (Name: "Typst", Age: 2) [ + {k}: {v}. +] + +// String. +{ + let out = "" + let first = true + for c in "abc" { + if not first { + out += ", " + } + first = false + out += c + } + test(out, "a, b, c") +} + +--- +// Block body. +// Should output `[1st, 2nd, 3rd, 4th, 5th, 6th]`. +{ + "[" + for v in (1, 2, 3, 4, 5, 6) { + (if v > 1 [, ] + + [{v}] + + if v == 1 [st] + + if v == 2 [nd] + + if v == 3 [rd] + + if v >= 4 [th]) + } + "]" +} + +// Template body. +// Should output `234`. +#for v in (1, 2, 3, 4, 5, 6, 7) [#if v >= 2 and v <= 5 { repr(v) }] + +--- +// Value of for loops. +// Ref: false +#test(type(for v in () {}), "template") +#test(type(for v in () []), "template") + +--- +// Uniterable expression. +// Error: 11-15 cannot loop over boolean +#for v in true {} + +// Make sure that we don't complain twice. +// Error: 11-18 cannot add integer and string +#for v in 1 + "2" {} + +// A single error stops iteration. +#test(error, for v in (1, 2, 3) { + if v < 2 [Ok] else {error} +}) diff --git a/tests/typ/code/if.typ b/tests/typ/code/if.typ new file mode 100644 index 00000000..8d07e9b8 --- /dev/null +++ b/tests/typ/code/if.typ @@ -0,0 +1,71 @@ +// Test if-else expressions. + +--- +// Test condition evaluation. +#if 1 < 2 [ + One. +] + +#if true == false [ + {Bad}, but we {dont-care}! +] + +--- +// Braced condition. +#if {true} [ + One. +] + +// Template in condition. +#if [] != none [ + Two. +] + +// Multi-line condition with parens. +#if ( + 1 + 1 + == 1 +) [ + Nope. +] #else { + "Three." +} + +// Multiline. +#if false [ + Bad. +] #else { + let point = "." + "Four" + point +} + +--- +// Value of if expressions. +// Ref: false +{ + let x = 1 + let y = 2 + let z + + // Returns if branch. + z = if x < y { "ok" } + test(z, "ok") + + // Returns else branch. + z = if x > y { "bad" } else { "ok" } + test(z, "ok") + + // Missing else evaluates to none. + z = if x > y { "bad" } + test(z, none) +} + +--- +// Condition must be boolean. +// If it isn't, neither branch is evaluated. +// Error: 5-14 expected boolean, found string +#if "a" + "b" { nope } #else { nope } + +// Make sure that we don't complain twice. +// Error: 5-12 cannot add integer and string +#if 1 + "2" {} diff --git a/tests/typ/code/invalid.typ b/tests/typ/code/invalid.typ new file mode 100644 index 00000000..49158a68 --- /dev/null +++ b/tests/typ/code/invalid.typ @@ -0,0 +1,100 @@ +// Test invalid control syntax. + +--- +// Error: 5 expected identifier +#let + +// Error: 5 expected identifier +{let} + +// Error: 6-9 expected identifier, found string +#let "v" + +// Should output `1`. +// Error: 7 expected semicolon or line break +#let v 1 + +// Error: 9 expected expression +#let v = + +// Should output `= 1`. +// Error: 6-9 expected identifier, found string +#let "v" = 1 + +--- +// Error: 4 expected expression +#if + +// Error: 4 expected expression +{if} + +// Error: 6 expected body +#if x + +// Error: 1-6 unexpected keyword `else` +#else {} + +// Should output `x`. +// Error: 4 expected expression +#if +x {} + +// Should output `something`. +// Error: 6 expected body +#if x something + +// Should output `A thing.` +// Error: 20 expected body +A#if false {} #else thing + +--- +// Error: 7 expected expression +#while + +// Error: 7 expected expression +{while} + +// Error: 9 expected body +#while x + +// Should output `x`. +// Error: 7 expected expression +#while +x {} + +// Should output `something`. +// Error: 9 expected body +#while x something + +--- +// Error: 5 expected identifier +#for + +// Error: 5 expected identifier +{for} + +// Error: 7 expected keyword `in` +#for v + +// Error: 10 expected expression +#for v in + +// Error: 15 expected body +#for v in iter + +// Should output `v in iter`. +// Error: 5 expected identifier +#for +v in iter {} + +// Should output `A thing`. +// Error: 7-10 expected identifier, found string +A#for "v" thing + +// Should output `in iter`. +// Error: 6-9 expected identifier, found string +#for "v" in iter {} + +// Should output `+ b in iter`. +// Error: 7 expected keyword `in` +#for a + b in iter {} diff --git a/tests/typ/code/let.typ b/tests/typ/code/let.typ new file mode 100644 index 00000000..4f84aa67 --- /dev/null +++ b/tests/typ/code/let.typ @@ -0,0 +1,63 @@ +// Test let bindings. + +--- +// Ref: false + +// Automatically initialized with none. +#let x +#test(x, none) + +// Error: 9 expected expression +#let y = +#test(y, none) + +// Manually initialized with one. +#let z = 1 +#test(z, 1) + +--- +// Syntax sugar for function definitions. +#let background = #9feb52 +#let rect(body) = rect(width: 2cm, fill: background, pad(5pt, body)) +#rect[Hi!] + +// Error: 13 expected body +#let func(x) + +// Error: 2-6 unknown variable +{func} + +// Error: 15 expected expression +#let func(x) = + +// Error: 2-6 unknown variable +{func} + +--- +// Termination. + +// Terminated by line break. +#let v1 = 1 +One + +// Terminated by semicolon. +#let v2 = 2; Two + +// Terminated by semicolon and line break. +#let v3 = 3; +Three + +// Terminated because expression ends. +// Error: 12 expected semicolon or line break +#let v4 = 4 Four + +// Terminated by semicolon even though we are in a paren group. +// Error: 2:19 expected expression +// Error: 1:19 expected closing paren +#let v5 = (1, 2 + ; Five + +#test(v1, 1) +#test(v2, 2) +#test(v3, 3) +#test(v4, 4) +#test(v5, (1, 2)) diff --git a/tests/typ/code/ops-invalid.typ b/tests/typ/code/ops-invalid.typ new file mode 100644 index 00000000..12d2a2c3 --- /dev/null +++ b/tests/typ/code/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-7 cannot assign to a constant +{ rect = "hi" } + +// Works if we define rect beforehand +// (since then it doesn't resolve to the standard library version anymore). +#let rect = "" +{ rect = "hi" } diff --git a/tests/typ/code/ops.typ b/tests/typ/code/ops.typ new file mode 100644 index 00000000..ef249c43 --- /dev/null +++ b/tests/typ/code/ops.typ @@ -0,0 +1,147 @@ +// 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("a" != "a", false) + +--- +// 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/code/prec.typ b/tests/typ/code/prec.typ new file mode 100644 index 00000000..e64e583c --- /dev/null +++ b/tests/typ/code/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} diff --git a/tests/typ/code/repr.typ b/tests/typ/code/repr.typ new file mode 100644 index 00000000..f2404510 --- /dev/null +++ b/tests/typ/code/repr.typ @@ -0,0 +1,57 @@ +// Test representation of values in the document. + +--- +// Variables. + +#let name = "Typst" +#let ke-bab = "Kebab!" +#let α = "Alpha" + +{name} \ +{ke-bab} \ +{α} + +// Error: 2-3 unknown variable +{_} + +--- +// Literal values. +{none} (empty) \ +{true} \ +{false} + +--- +// Numerical values. +{1} \ +{1.0e-4} \ +{3.15} \ +{1e-10} \ +{50.368%} \ +{0.0000012345pt} \ +{4.5cm} \ +{12e1pt} \ +{2.5rad} \ +{45deg} \ +// Not in monospace via repr. +#repr(45deg) + +--- +// Colors. +{#f7a20500} + +--- +// Strings and escaping. +{"hi"} \ +{"a\n[]\"\u{1F680}string"} + +--- +// Templates. +{[*{"H" + "i"} there*]} + +--- +// Functions +#let f(x) = x + +{rect} \ +{f} \ +{() => none} diff --git a/tests/typ/code/while.typ b/tests/typ/code/while.typ new file mode 100644 index 00000000..acf7951e --- /dev/null +++ b/tests/typ/code/while.typ @@ -0,0 +1,43 @@ +// Test while expressions. + +--- +// Should output `2 4 6 8 10`. +#let i = 0 +#while i < 10 [ + { i += 2 } + #i +] + +// Should output `Hi`. +#let iter = true +#while iter { + iter = false + "Hi." +} + +#while false { + dont-care +} + +--- +// Value of while loops. +// Ref: false +#test(type(while false {}), "template") +#test(type(while false []), "template") + +--- +// Condition must be boolean. +// Error: 8-14 expected boolean, found template +#while [nope] [nope] + +// Make sure that we don't complain twice. +// Error: 8-15 unknown variable +#while nothing {} + +// A single error stops iteration. +#let i = 0 +#test(error, while i < 10 { + i += 1 + if i < 5 [nope] else { error } +}) +#test(i, 5) -- cgit v1.2.3