Fix error handling after hashtag

This commit is contained in:
Laurenz 2023-02-17 16:32:48 +01:00
parent dd5f07eb91
commit 028632a3a1
26 changed files with 180 additions and 169 deletions

View File

@ -390,8 +390,8 @@ pub fn label(args: &mut Args) -> SourceResult<Value> {
/// The numbers 1 to 10.
///
/// // Works with string methods.
/// #{ "a,b;c"
/// .split(regex("[,;]")) }
/// #("a,b;c"
/// .split(regex("[,;]")))
/// ```
///
/// ## Parameters

View File

@ -517,16 +517,16 @@ mod tests {
fn test_captures() {
// Let binding and function definition.
test("#let x = x", &["x"]);
test("#let x; #{x + y}", &["y"]);
test("#let x; #(x + y)", &["y"]);
test("#let f(x, y) = x + y", &[]);
test("#let f(x, y) = f", &[]);
test("#let f = (x, y) => f", &["f"]);
// Closure with different kinds of params.
test("#{(x, y) => x + z}", &["z"]);
test("#{(x: y, z) => x + z}", &["y"]);
test("#{(..x) => x + y}", &["y"]);
test("#{(x, y: x + z) => x + y}", &["x", "z"]);
test("#((x, y) => x + z)", &["z"]);
test("#((x: y, z) => x + z)", &["y"]);
test("#((..x) => x + y)", &["y"]);
test("#((x, y: x + z) => x + y)", &["x", "z"]);
test("#{x => x; x}", &["x"]);
// Show rule.

View File

@ -133,7 +133,7 @@ impl Value {
format_str!("{:?}", self)
}
/// Attach a span to the value, if possibly.
/// Attach a span to the value, if possible.
pub fn spanned(self, span: Span) -> Self {
match self {
Value::Content(v) => Value::Content(v.spanned(span)),

View File

@ -521,7 +521,14 @@ fn embedded_code_expr(p: &mut Parser) {
| SyntaxKind::Include
);
let prev = p.prev_end();
code_expr_prec(p, true, 0);
// Consume error for things like `#12p` or `#"abc\"`.
if !p.progress(prev) {
p.unexpected();
}
let semi = p.eat_if(SyntaxKind::Semicolon);
if stmt && !semi && !p.eof() && !p.at(SyntaxKind::RightBracket) {
p.expected("semicolon or line break");

View File

@ -7,21 +7,21 @@
#set page(width: 150pt)
// Empty.
#{()}
#()
// Not an array, just a parenthesized expression.
#{(1)}
#(1)
// One item and trailing comma.
#{(-1,)}
#(-1,)
// No trailing comma.
#{(true, false)}
#(true, false)
// Multiple lines and items and trailing comma.
#{("1"
#("1"
, rgb("002")
,)}
,)
---
// Test the `len` method.
@ -47,8 +47,8 @@
---
// Test rvalue out of bounds.
// Error: 3-18 array index out of bounds (index: 5, len: 3)
#{(1, 2, 3).at(5)}
// Error: 2-17 array index out of bounds (index: 5, len: 3)
#(1, 2, 3).at(5)
---
// Test lvalue out of bounds.
@ -60,15 +60,15 @@
---
// Test bad lvalue.
// Error: 2:4-2:15 cannot mutate a temporary value
// Error: 2:3-2:14 cannot mutate a temporary value
#let array = (1, 2, 3)
#{ array.len() = 4 }
#(array.len() = 4)
---
// Test bad lvalue.
// Error: 2:4-2:16 type array has no method `yolo`
// Error: 2:3-2:15 type array has no method `yolo`
#let array = (1, 2, 3)
#{ array.yolo() = 4 }
#(array.yolo() = 4)
---
// Test negative indices.
@ -89,12 +89,12 @@
#test((1, 2, 3).last(), 3)
---
// Error: 4-14 array is empty
#{ ().first() }
// Error: 2-12 array is empty
#().first()
---
// Error: 4-13 array is empty
#{ ().last() }
// Error: 2-11 array is empty
#().last()
---
// Test the `push` and `pop` methods.
@ -117,9 +117,9 @@
}
---
// Error: 2:18-2:20 missing argument: index
// Error: 2:16-2:18 missing argument: index
#let numbers = ()
#{ numbers.insert() }
#numbers.insert()
---
// Test the `slice` method.
@ -133,12 +133,12 @@
#test("ABCD".split("").slice(1, -1).join("-"), "A-B-C-D")
---
// Error: 4-32 array index out of bounds (index: 12, len: 10)
#{ range(10).slice(9, count: 3) }
// Error: 2-30 array index out of bounds (index: 12, len: 10)
#range(10).slice(9, count: 3)
---
// Error: 4-26 array index out of bounds (index: -4, len: 3)
#{ (1, 2, 3).slice(0, -4) }
// Error: 2-24 array index out of bounds (index: -4, len: 3)
#(1, 2, 3).slice(0, -4)
---
// Test the `position` method.
@ -163,8 +163,8 @@
#test((1, 2, 3, 4).fold(0, (s, x) => s + x), 10)
---
// Error: 22-32 function must have exactly two parameters
#{ (1, 2, 3).fold(0, () => none) }
// Error: 20-30 function must have exactly two parameters
#(1, 2, 3).fold(0, () => none)
---
// Test the `rev` method.
@ -178,17 +178,17 @@
#test("(" + ("a", "b", "c").join(", ") + ")", "(a, b, c)")
---
// Error: 3-23 cannot join boolean with boolean
#{(true, false).join()}
// Error: 2-22 cannot join boolean with boolean
#(true, false).join()
---
// Error: 3-21 cannot join string with integer
#{("a", "b").join(1)}
// Error: 2-20 cannot join string with integer
#("a", "b").join(1)
---
// Test joining content.
// Ref: true
#{([One], [Two], [Three]).join([, ], last: [ and ])}.
#([One], [Two], [Three]).join([, ], last: [ and ]).
---
// Test the `sorted` method.
@ -198,12 +198,12 @@
#test((2, 1, 3, 10, 5, 8, 6, -7, 2).sorted(), (-7, 1, 2, 2, 3, 5, 6, 8, 10))
---
// Error: 3-27 cannot order content and content
#{([Hi], [There]).sorted()}
// Error: 2-26 cannot order content and content
#([Hi], [There]).sorted()
---
// Error: 3-19 array index out of bounds (index: -4, len: 3)
#{(1, 2, 3).at(-4)}
// Error: 2-18 array index out of bounds (index: -4, len: 3)
#(1, 2, 3).at(-4)
---
// Error: 4 expected closing paren
@ -212,23 +212,23 @@
// Error: 3-4 unexpected closing paren
#{)}
// Error: 5-7 unexpected end of block comment
#{(1*/2)}
// Error: 4-6 unexpected end of block comment
#(1*/2)
// Error: 7-9 invalid number suffix
#{(1, 1u 2)}
// Error: 6-8 invalid number suffix
#(1, 1u 2)
// Error: 4-5 unexpected comma
#{(,1)}
// Error: 3-4 unexpected comma
#(,1)
// Missing expression makes named pair incomplete, making this an empty array.
// Error: 6 expected expression
#{(a:)}
// Error: 5 expected expression
#(a:)
// Named pair after this is already identified as an array.
// Error: 7-11 expected expression, found named pair
#{(1, b: 2)}
// Error: 6-10 expected expression, found named pair
#(1, b: 2)
// Keyed pair after this is already identified as an array.
// Error: 7-15 expected expression, found keyed pair
#{(1, "key": 2)}
// Error: 6-14 expected expression, found keyed pair
#(1, "key": 2)

View File

@ -7,7 +7,7 @@
// ... but also "content" values. While these contain markup,
// they are also values and can be summed, stored in arrays etc.
// There are also more standard control flow structures, like #if and #for.
#let university = [*Technische Universität #{city}*]
#let university = [*Technische Universität #city*]
#let faculty = [*Fakultät II, Institut for Mathematik*]
// The `box` function just places content into a rectangular container. When

View File

@ -83,8 +83,8 @@
test(b, 1)
}}
// Error: 3-4 unknown variable
#{b}
// Error: 2-3 unknown variable
#b
---
// Multiple nested scopes.
@ -106,14 +106,14 @@
// Content blocks also create a scope.
#[#let x = 1]
// Error: 3-4 unknown variable
#{x}
// Error: 2-3 unknown variable
#x
---
// Multiple unseparated expressions in one line.
// Error: 3-5 invalid number suffix
#{1u}
// Error: 2-4 invalid number suffix
#1u
// Should output `1`.
// Error: 4 expected semicolon or line break
@ -142,5 +142,5 @@
#{
---
// Error: 2 expected expression
// Error: 2-3 unexpected closing brace
#}

View File

@ -48,8 +48,8 @@
#set text(family: "Arial", family: "Helvetica")
---
// Error: 3-7 expected function, found boolean
#{true()}
// Error: 2-6 expected function, found boolean
#true()
---
#let x = "x"
@ -90,8 +90,8 @@
// Error: 7-12 expected identifier, found string
#func("abc": 2)
// Error: 8-11 expected identifier, found group
#{func((x):1)}
// Error: 7-10 expected identifier, found group
#func((x):1)
---
// Error: 2:1 expected closing bracket

View File

@ -157,7 +157,7 @@
---
// Error: 7-17 expected identifier, named pair or argument sink, found keyed pair
#{(a, "named": b) => none}
#((a, "named": b) => none)
---
// Error: 10-15 expected identifier, found string

View File

@ -5,7 +5,7 @@
// Ref: true
// Empty
#{(:)}
#(:)
// Two pairs and string key.
#let dict = (normal: 1, "spacy key": 2)
@ -51,36 +51,36 @@
#test(dict.values(), (3, 1, 2))
#test(dict.pairs().map(p => p.first() + str(p.last())).join(), "a3b1c2")
#{ dict.remove("c") }
#dict.remove("c")
#test("c" in dict, false)
#test(dict, (a: 3, b: 1))
---
// Error: 25-30 duplicate key
#{(first: 1, second: 2, first: 3)}
// Error: 24-29 duplicate key
#(first: 1, second: 2, first: 3)
---
// Error: 18-21 duplicate key
#{(a: 1, "b": 2, "a": 3)}
// Error: 17-20 duplicate key
#(a: 1, "b": 2, "a": 3)
---
// Simple expression after already being identified as a dictionary.
// Error: 10-11 expected named or keyed pair, found identifier
#{(a: 1, b)}
// Error: 9-10 expected named or keyed pair, found identifier
#(a: 1, b)
// Identified as dictionary due to initial colon.
// Error: 5-6 expected named or keyed pair, found integer
// Error: 6 expected comma
// Error: 13-17 expected identifier or string, found boolean
// Error: 18 expected expression
#{(:1 b:"", true:)}
// Error: 4-5 expected named or keyed pair, found integer
// Error: 5 expected comma
// Error: 12-16 expected identifier or string, found boolean
// Error: 17 expected expression
#(:1 b:"", true:)
// Error: 4-9 expected identifier or string, found binary expression
#{(a + b: "hey")}
// Error: 3-8 expected identifier or string, found binary expression
#(a + b: "hey")
---
// Error: 4-16 cannot mutate a temporary value
#{ (key: "val").other = "some" }
// Error: 3-15 cannot mutate a temporary value
#((key: "val").other = "some")
---
#{

View File

@ -23,12 +23,12 @@
- C
---
// Error: 7-14 dictionary does not contain key "invalid"
#{(:).invalid}
// Error: 6-13 dictionary does not contain key "invalid"
#(:).invalid
---
// Error: 9-11 cannot access fields on type boolean
#{false.ok}
// Error: 8-10 cannot access fields on type boolean
#false.ok
---
// Error: 29-32 unknown field `fun`

View File

@ -115,7 +115,7 @@
// Error: 6 expected block
#if x
// Error: 2 expected expression
// Error: 2-6 unexpected keyword `else`
#else {}
// Should output `x`.

View File

@ -49,8 +49,8 @@
#test((module,).at(0).item(1, 2), 3)
// Doesn't work because of mutating name.
// Error: 3-12 cannot mutate a temporary value
#{(module,).at(0).push()}
// Error: 2-11 cannot mutate a temporary value
#(module,).at(0).push()
---
// Who needs whitespace anyways?

View File

@ -27,20 +27,20 @@
}
---
// Error: 2:4-2:17 type array has no method `fun`
// Error: 2:2-2:15 type array has no method `fun`
#let numbers = ()
#{ numbers.fun() }
#numbers.fun()
---
// Error: 2:4-2:45 cannot mutate a temporary value
// Error: 2:2-2:43 cannot mutate a temporary value
#let numbers = (1, 2, 3)
#{ numbers.map(v => v / 2).sorted().map(str).remove(4) }
#numbers.map(v => v / 2).sorted().map(str).remove(4)
---
// Error: 2:4-2:20 cannot mutate a temporary value
// Error: 2:3-2:19 cannot mutate a temporary value
#let numbers = (1, 2, 3)
#{ numbers.sorted() = 1 }
#(numbers.sorted() = 1)
---
// Error: 4-7 cannot mutate a constant
#{ box.push(1) }
// Error: 2-5 cannot mutate a constant
#box.push(1)

View File

@ -3,7 +3,7 @@
---
// Error: 4 expected expression
#{-}
#(-)
---
// Error: 10 expected expression
@ -15,40 +15,40 @@
---
// Error: 3-13 cannot apply '+' to content
#{+([] + [])}
#(+([] + []))
---
// Error: 3-6 cannot apply '-' to string
#{-""}
#(-"")
---
// Error: 3-9 cannot apply 'not' to array
#{not ()}
#(not ())
---
// Error: 3-19 cannot apply '<=' to relative length and ratio
#{30% + 1pt <= 40%}
#(30% + 1pt <= 40%)
---
// Error: 3-14 cannot apply '<=' to length and length
#{1em <= 10pt}
#(1em <= 10pt)
---
// Error: 3-12 cannot divide by zero
#{1.2 / 0.0}
#(1.2 / 0.0)
---
// Error: 3-8 cannot divide by zero
#{1 / 0}
#(1 / 0)
---
// Error: 3-15 cannot divide by zero
#{15deg / 0deg}
#(15deg / 0deg)
---
// Special messages for +, -, * and /.
// Error: 4-11 cannot add integer and string
#{(1 + "2", 40% - 1)}
// Error: 3-10 cannot add integer and string
#(1 + "2", 40% - 1)
---
// Error: 15-23 cannot add integer and string
@ -56,35 +56,35 @@
---
// Error: 4-13 cannot divide ratio by length
#{ 10% / 5pt }
#( 10% / 5pt )
---
// Error: 4-13 cannot divide these two lengths
#{ 1em / 5pt }
// Error: 3-12 cannot divide these two lengths
#(1em / 5pt)
---
// Error: 4-20 cannot divide relative length by ratio
#{ (10% + 1pt) / 5% }
// Error: 3-19 cannot divide relative length by ratio
#((10% + 1pt) / 5%)
---
// Error: 4-29 cannot divide these two relative lengths
#{ (10% + 1pt) / (20% + 1pt) }
// Error: 3-28 cannot divide these two relative lengths
#((10% + 1pt) / (20% + 1pt))
---
// Error: 13-20 cannot subtract integer from ratio
#{(1234567, 40% - 1)}
#((1234567, 40% - 1))
---
// Error: 3-11 cannot multiply integer with boolean
#{2 * true}
#(2 * true)
---
// Error: 3-11 cannot divide integer by length
#{3 / 12pt}
#(3 / 12pt)
---
// Error: 3-10 cannot repeat this string -1 times
#{-1 * ""}
#(-1 * "")
---
#{
@ -97,32 +97,32 @@
}
---
// Error: 5-6 unknown variable
#{ (x) = "" }
// Error: 4-5 unknown variable
#((x) = "")
---
// Error: 4-9 cannot mutate a temporary value
#{ 1 + 2 += 3 }
// Error: 3-8 cannot mutate a temporary value
#(1 + 2 += 3)
---
// Error: 2:3-2:8 cannot apply 'not' to string
#let x = "Hey"
#{not x = "a"}
#(not x = "a")
---
// Error: 8-9 unknown variable
#{ 1 + x += 3 }
// Error: 7-8 unknown variable
#(1 + x += 3)
---
// Error: 4-5 unknown variable
#{ z = 1 }
// Error: 3-4 unknown variable
#(z = 1)
---
// Error: 4-8 cannot mutate a constant
#{ rect = "hi" }
// Error: 3-7 cannot mutate 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" }
#(rect = "hi")

View File

@ -16,12 +16,12 @@
// Assignment binds stronger than boolean operations.
// Error: 2:3-2:8 cannot mutate a temporary value
#let x = false
#{not x = "a"}
#(not x = "a")
---
// Precedence doesn't matter for chained unary operators.
// Error: 3-12 cannot apply '-' to boolean
#{-not true}
#(-not true)
---
// Not in handles precedence.

View File

@ -4,7 +4,7 @@
---
// Test adding content.
// Ref: true
#{[*Hello* ] + [world!]}
#([*Hello* ] + [world!])
---
// Test math operators.
@ -176,17 +176,17 @@
// 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")
#(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")
---
// Error: 4-7 cannot mutate a constant
#{ box = 1 }
// Error: 3-6 cannot mutate a constant
#(box = 1)
---
// Test `in` operator.
@ -205,7 +205,7 @@
---
// Error: 10 expected keyword `in`
#{"a" not}
#("a" not)
---
// Test `with` method.

View File

@ -20,15 +20,15 @@
#2.5rad \
#45deg \
#1.7em \
#{1cm + 0em} \
#{2em + 10pt} \
#(1cm + 0em) \
#(2em + 10pt) \
#2.3fr
---
// Colors and strokes.
#set text(0.8em)
#rgb("f7a205") \
#{2pt + rgb("f7a205")}
#(2pt + rgb("f7a205"))
---
// Strings and escaping.
@ -45,4 +45,4 @@ Nothing
#let f(x) = x
#f
#rect
#{() => none}
#(() => none)

View File

@ -29,5 +29,5 @@ Forest
Ignored
---
// Error: 5-20 show is only allowed directly in code and content blocks
#{ (show: body => 2) * body }
// Error: 4-19 show is only allowed directly in code and content blocks
#((show: body => 2) * body)

View File

@ -100,5 +100,5 @@ Another text.
#show red: []
---
// Error: 8-26 show is only allowed directly in code and content blocks
#{ 1 + show heading: none }
// Error: 7-25 show is only allowed directly in code and content blocks
#(1 + show heading: none)

View File

@ -85,9 +85,9 @@
}
---
// Error: 12-18 cannot spread dictionary into array
#{(1, 2, ..(a: 1))}
// Error: 11-17 cannot spread dictionary into array
#(1, 2, ..(a: 1))
---
// Error: 6-12 cannot spread array into dictionary
#{(..(1, 2), a: 1)}
// Error: 5-11 cannot spread array into dictionary
#(..(1, 2), a: 1)

View File

@ -13,12 +13,12 @@
#test("🏳🌈A🏳".last(), "🏳️‍⚧️")
---
// Error: 4-14 string is empty
#{ "".first() }
// Error: 2-12 string is empty
#"".first()
---
// Error: 4-13 string is empty
#{ "".last() }
// Error: 2-11 string is empty
#"".last()
---
// Test the `at` method.
@ -150,8 +150,8 @@
#test("hello world".trim(regex(".")), "")
---
// Error: 18-22 expected either `start` or `end`
#{"abc".trim(at: left)}
// Error: 17-21 expected either `start` or `end`
#"abc".trim(at: left)
---
// Test the `split` method.
@ -159,3 +159,7 @@
#test("abc".split("b"), ("a", "c"))
#test("a123c".split(regex("\d")), ("a", "", "", "c"))
#test("a123c".split(regex("\d+")), ("a", "c"))
---
// Error: 2:1 expected quote
#"hello\"

View File

@ -4,7 +4,7 @@
// Should output `2 4 6 8 10`.
#let i = 0
#while i < 10 [
#{ i += 2 }
#(i += 2)
#i
]
@ -26,7 +26,7 @@
#test(while false {}, none)
#let i = 0
#test(type(while i < 1 [#{ i += 1 }]), "content")
#test(type(while i < 1 [#(i += 1)]), "content")
---
// Condition must be boolean.

View File

@ -15,7 +15,7 @@
// Parsed as headings if at start of the context.
/**/ = Level 1
#{[== Level 2]}
#[== Level 2]
#box[=== Level 3]
// Not at the start of the context.

View File

@ -7,7 +7,7 @@ C #let x = 2;D #test(x, 2) \
E#if true [F]G \
H #if true{"I"} J \
K #if true [L] else []M \
#let c = true; N#while c [#{c = false}O] P \
#let c = true; N#while c [#(c = false)O] P \
#let c = true; Q #while c { c = false; "R" } S \
T#for _ in (none,) {"U"}V

View File

@ -16,7 +16,7 @@
variant(fill: forest, stroke: black + 2pt),
variant(fill: forest, stroke: conifer + 2pt),
) {
(align(horizon)[#{i + 1}.], item, [])
(align(horizon)[#(i + 1).], item, [])
}
#grid(