Refresh tests 🔄
@ -317,17 +317,11 @@ impl Spanned<&ExprBinary> {
|
|||||||
return Value::Error;
|
return Value::Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
let lhty = lhs.type_name();
|
let (l, r) = (lhs.type_name(), rhs.type_name());
|
||||||
let rhty = rhs.type_name();
|
|
||||||
let out = op(lhs, rhs);
|
let out = op(lhs, rhs);
|
||||||
if out == Value::Error {
|
if out == Value::Error {
|
||||||
ctx.diag(error!(
|
self.error(ctx, l, r);
|
||||||
self.span,
|
|
||||||
"cannot apply '{}' to {} and {}",
|
|
||||||
self.v.op.v.as_str(),
|
|
||||||
lhty,
|
|
||||||
rhty,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out
|
out
|
||||||
@ -358,13 +352,41 @@ impl Spanned<&ExprBinary> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(mut slot) = slot.try_borrow_mut() {
|
let (constant, err, value) = if let Ok(mut inner) = slot.try_borrow_mut() {
|
||||||
*slot = op(std::mem::take(&mut slot), rhs);
|
let lhs = std::mem::take(&mut *inner);
|
||||||
return Value::None;
|
let types = (lhs.type_name(), rhs.type_name());
|
||||||
|
|
||||||
|
*inner = op(lhs, rhs);
|
||||||
|
if *inner == Value::Error {
|
||||||
|
(false, Some(types), Value::Error)
|
||||||
|
} else {
|
||||||
|
(false, None, Value::None)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(true, None, Value::Error)
|
||||||
|
};
|
||||||
|
|
||||||
|
if constant {
|
||||||
|
ctx.diag(error!(span, "cannot assign to a constant"));
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.diag(error!(span, "cannot assign to a constant"));
|
if let Some((l, r)) = err {
|
||||||
Value::Error
|
self.error(ctx, l, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
fn error(&self, ctx: &mut EvalContext, l: &str, r: &str) {
|
||||||
|
let op = self.v.op.v.as_str();
|
||||||
|
let message = match self.v.op.v {
|
||||||
|
BinOp::Add => format!("cannot add {} and {}", l, r),
|
||||||
|
BinOp::Sub => format!("cannot subtract {1} from {0}", l, r),
|
||||||
|
BinOp::Mul => format!("cannot multiply {} with {}", l, r),
|
||||||
|
BinOp::Div => format!("cannot divide {} by {}", l, r),
|
||||||
|
_ => format!("cannot apply '{}' to {} and {}", op, l, r),
|
||||||
|
};
|
||||||
|
ctx.diag(error!(self.span, "{}", message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,10 +44,16 @@ pub fn add(lhs: Value, rhs: Value) -> Value {
|
|||||||
(Linear(a), Length(b)) => Linear(a + b),
|
(Linear(a), Length(b)) => Linear(a + b),
|
||||||
(Linear(a), Relative(b)) => Linear(a + b),
|
(Linear(a), Relative(b)) => Linear(a + b),
|
||||||
(Linear(a), Linear(b)) => Linear(a + b),
|
(Linear(a), Linear(b)) => Linear(a + b),
|
||||||
|
|
||||||
(Str(a), Str(b)) => Str(a + &b),
|
(Str(a), Str(b)) => Str(a + &b),
|
||||||
(Array(a), Array(b)) => Array(concat(a, b)),
|
(Array(a), Array(b)) => Array(concat(a, b)),
|
||||||
(Dict(a), Dict(b)) => Dict(concat(a, b)),
|
(Dict(a), Dict(b)) => Dict(concat(a, b)),
|
||||||
|
|
||||||
|
// TODO: Add string and template.
|
||||||
(Template(a), Template(b)) => Template(concat(a, b)),
|
(Template(a), Template(b)) => Template(concat(a, b)),
|
||||||
|
(Template(a), None) => Template(a),
|
||||||
|
(None, Template(b)) => Template(b),
|
||||||
|
|
||||||
_ => Error,
|
_ => Error,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,7 +205,7 @@ impl<'s> Parser<'s> {
|
|||||||
pub fn expect(&mut self, t: Token) -> bool {
|
pub fn expect(&mut self, t: Token) -> bool {
|
||||||
let eaten = self.eat_if(t);
|
let eaten = self.eat_if(t);
|
||||||
if !eaten {
|
if !eaten {
|
||||||
self.expected(t.name());
|
self.expected_at(t.name(), self.last_end);
|
||||||
}
|
}
|
||||||
eaten
|
eaten
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
BIN
tests/lang/ref/block-invalid.png
Normal file
After Width: | Height: | Size: 507 B |
BIN
tests/lang/ref/block-value.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 515 B |
Before Width: | Height: | Size: 22 KiB |
BIN
tests/lang/ref/call-args.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
tests/lang/ref/call-bracket.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
tests/lang/ref/call-chain.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
tests/lang/ref/call-invalid.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
tests/lang/ref/comment.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.1 KiB |
BIN
tests/lang/ref/dict.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 4.0 KiB |
BIN
tests/lang/ref/emph.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
tests/lang/ref/escape.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 4.1 KiB |
BIN
tests/lang/ref/expr-binary.png
Normal file
After Width: | Height: | Size: 756 B |
BIN
tests/lang/ref/for-invalid.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
tests/lang/ref/for-loop.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
tests/lang/ref/for-value.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
tests/lang/ref/heading.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 7.2 KiB |
BIN
tests/lang/ref/if-branch.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
tests/lang/ref/if-invalid.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 3.8 KiB |
BIN
tests/lang/ref/let-invalid.png
Normal file
After Width: | Height: | Size: 364 B |
BIN
tests/lang/ref/let-terminated.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 3.5 KiB |
BIN
tests/lang/ref/linebreak.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 6.2 KiB |
BIN
tests/lang/ref/repr.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
tests/lang/ref/spacing.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
tests/lang/ref/strong.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 731 B After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 8.0 KiB |
@ -1,3 +1,6 @@
|
|||||||
|
// Test arrays.
|
||||||
|
|
||||||
|
---
|
||||||
// Empty.
|
// Empty.
|
||||||
{()}
|
{()}
|
||||||
|
|
||||||
@ -16,24 +19,19 @@
|
|||||||
, #003
|
, #003
|
||||||
,)}
|
,)}
|
||||||
|
|
||||||
// Missing closing paren.
|
|
||||||
// Error: 3-3 expected closing paren
|
// Error: 3-3 expected closing paren
|
||||||
{(}
|
{(}
|
||||||
|
|
||||||
// Not an array.
|
|
||||||
// Error: 2-3 expected expression, found closing paren
|
// Error: 2-3 expected expression, found closing paren
|
||||||
{)}
|
{)}
|
||||||
|
|
||||||
// Missing comma and bad expression.
|
|
||||||
// Error: 2:4-2:4 expected comma
|
// Error: 2:4-2:4 expected comma
|
||||||
// Error: 1:4-1:6 expected expression, found end of block comment
|
// Error: 1:4-1:6 expected expression, found end of block comment
|
||||||
{(1*/2)}
|
{(1*/2)}
|
||||||
|
|
||||||
// Bad expression.
|
|
||||||
// Error: 6-8 expected expression, found invalid token
|
// Error: 6-8 expected expression, found invalid token
|
||||||
{(1, 1u 2)}
|
{(1, 1u 2)}
|
||||||
|
|
||||||
// Leading comma is not an expression.
|
|
||||||
// Error: 3-4 expected expression, found comma
|
// Error: 3-4 expected expression, found comma
|
||||||
{(,1)}
|
{(,1)}
|
||||||
|
|
37
tests/lang/typ/block-invalid.typ
Normal file
@ -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-3 expected semicolon or line break
|
||||||
|
{0 1}
|
||||||
|
|
||||||
|
// Should output `2`.
|
||||||
|
// Error: 2:13-2:13 expected semicolon or line break
|
||||||
|
// Error: 1:24-1:24 expected semicolon or line break
|
||||||
|
{#let x = -1 #let y = 3 x + y}
|
||||||
|
|
||||||
|
// Should output `3`.
|
||||||
|
{
|
||||||
|
// Error: 10-13 expected identifier, found string
|
||||||
|
#for "v"
|
||||||
|
|
||||||
|
// Error: 11-11 expected keyword `#in`
|
||||||
|
#for v #let z = 1 + 2
|
||||||
|
|
||||||
|
z
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
// Ref: false
|
||||||
|
// Error: 3:1-3:1 expected closing brace
|
||||||
|
{
|
||||||
|
|
||||||
|
---
|
||||||
|
// Ref: false
|
||||||
|
// Error: 1-2 unexpected closing brace
|
||||||
|
}
|
35
tests/lang/typ/block-scoping.typ
Normal file
@ -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")
|
||||||
|
}
|
38
tests/lang/typ/block-value.typ
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Test return value of 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 {
|
||||||
|
#let x = 1
|
||||||
|
#let y = 2
|
||||||
|
x + y
|
||||||
|
}, 3]
|
@ -1,17 +0,0 @@
|
|||||||
// Empty.
|
|
||||||
{}
|
|
||||||
|
|
||||||
// Basic expression.
|
|
||||||
{1}
|
|
||||||
|
|
||||||
// Bad expression.
|
|
||||||
// Error: 2-4 expected expression, found invalid token
|
|
||||||
{1u}
|
|
||||||
|
|
||||||
// Missing closing brace in nested block.
|
|
||||||
// Error: 5-5 expected closing brace
|
|
||||||
{({1) + 1}
|
|
||||||
|
|
||||||
// Missing closing bracket in template expression.
|
|
||||||
// Error: 11-11 expected closing bracket
|
|
||||||
{[_] + [3_}
|
|
@ -1,107 +0,0 @@
|
|||||||
// 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.
|
|
||||||
// Error: 7-8 expected identifier, found integer
|
|
||||||
#[f | 1 | box][💕]
|
|
||||||
|
|
||||||
// Error: 2:3-2:3 expected identifier
|
|
||||||
// Error: 1:4-1:4 expected identifier
|
|
||||||
#[||f true]
|
|
||||||
|
|
||||||
// Error: 7-7 expected identifier
|
|
||||||
#[f 1|]
|
|
||||||
|
|
||||||
// Error: 2:3-2:3 expected identifier
|
|
||||||
// Error: 1:4-1:4 expected identifier
|
|
||||||
#[|][Nope]
|
|
||||||
|
|
||||||
// Error: 2:6-2:6 expected closing paren
|
|
||||||
// Error: 1:9-1:10 expected expression, found closing paren
|
|
||||||
#[f (|f )]
|
|
||||||
|
|
||||||
// With actual functions.
|
|
||||||
#[box width: 1cm | image "res/rhino.png"]
|
|
||||||
|
|
||||||
---
|
|
||||||
// Error: 5-7 expected expression, found end of block comment
|
|
||||||
#[f */]
|
|
||||||
|
|
||||||
// Error: 8-9 expected expression, found colon
|
|
||||||
#[f a:1:]
|
|
||||||
|
|
||||||
// Error: 6-6 expected comma
|
|
||||||
#[f 1 2]
|
|
||||||
|
|
||||||
// Error: 2:5-2:6 expected identifier
|
|
||||||
// Error: 1:7-1:7 expected expression
|
|
||||||
#[f 1:]
|
|
||||||
|
|
||||||
// Error: 5-6 expected identifier
|
|
||||||
#[f 1:2]
|
|
||||||
|
|
||||||
// Error: 5-8 expected identifier
|
|
||||||
#[f (x):1]
|
|
||||||
|
|
||||||
---
|
|
||||||
// Ref: false
|
|
||||||
// Error: 2:3-2:4 expected function, found string
|
|
||||||
#let x = "string"
|
|
||||||
#[x]
|
|
||||||
|
|
||||||
// Error: 3-4 expected identifier, found invalid token
|
|
||||||
#[# 1]
|
|
||||||
|
|
||||||
// Error: 4:1-4:1 expected identifier
|
|
||||||
// Error: 3:1-3:1 expected closing bracket
|
|
||||||
#[
|
|
||||||
|
|
||||||
---
|
|
||||||
// Ref: false
|
|
||||||
// Error: 2:3-2:4 expected identifier, 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]`
|
|
||||||
|
|
||||||
---
|
|
||||||
// Error: 3:1-3:1 expected quote
|
|
||||||
// Error: 2:1-2:1 expected closing bracket
|
|
||||||
#[f "]
|
|
34
tests/lang/typ/call-args.typ
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Test function call arguments.
|
||||||
|
|
||||||
|
---
|
||||||
|
// One argument.
|
||||||
|
#[f bold]
|
||||||
|
|
||||||
|
// One argument and trailing comma.
|
||||||
|
#[f 1,]
|
||||||
|
|
||||||
|
// One named argument.
|
||||||
|
#[f a:2]
|
||||||
|
|
||||||
|
// Mixed arguments.
|
||||||
|
{f(1, a: (3, 4), 2, b: "5")}
|
||||||
|
|
||||||
|
---
|
||||||
|
// Error: 5-6 expected expression, found colon
|
||||||
|
#[f :]
|
||||||
|
|
||||||
|
// Error: 8-10 expected expression, found end of block comment
|
||||||
|
#[f a:1*/]
|
||||||
|
|
||||||
|
// Error: 6-6 expected comma
|
||||||
|
#[f 1 2]
|
||||||
|
|
||||||
|
// Error: 2:5-2:6 expected identifier
|
||||||
|
// Error: 1:7-1:7 expected expression
|
||||||
|
#[f 1:]
|
||||||
|
|
||||||
|
// Error: 5-6 expected identifier
|
||||||
|
#[f 1:2]
|
||||||
|
|
||||||
|
// Error: 4-7 expected identifier
|
||||||
|
{f((x):1)}
|
18
tests/lang/typ/call-bracket.typ
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Test bracketed function calls.
|
||||||
|
|
||||||
|
---
|
||||||
|
// Whitespace insignificant.
|
||||||
|
#[f], #[ f ]
|
||||||
|
|
||||||
|
// Body and no body.
|
||||||
|
#[f][#[f]]
|
||||||
|
|
||||||
|
// Tight functions.
|
||||||
|
#[f]#[f]
|
||||||
|
|
||||||
|
// Multi-paragraph body.
|
||||||
|
#[align right][
|
||||||
|
First
|
||||||
|
|
||||||
|
Second
|
||||||
|
]
|
31
tests/lang/typ/call-chain.typ
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// Test bracket call chaining.
|
||||||
|
|
||||||
|
---
|
||||||
|
// Chained once.
|
||||||
|
#[f | f]
|
||||||
|
|
||||||
|
// Chained twice.
|
||||||
|
#[f|f|f]
|
||||||
|
|
||||||
|
// With body.
|
||||||
|
// Error: 7-8 expected identifier, found integer
|
||||||
|
#[f | 1 | box][💕]
|
||||||
|
|
||||||
|
// With actual functions.
|
||||||
|
#[box width: 1cm | image "res/rhino.png"]
|
||||||
|
|
||||||
|
---
|
||||||
|
// Error: 8-8 expected identifier
|
||||||
|
#[f 1 |]
|
||||||
|
|
||||||
|
// Error: 4-4 expected identifier
|
||||||
|
#[ | f true]
|
||||||
|
|
||||||
|
// Error: 2:3-2:3 expected identifier
|
||||||
|
// Error: 1:4-1:4 expected identifier
|
||||||
|
#[|][Nope]
|
||||||
|
|
||||||
|
// Pipe wins over parens.
|
||||||
|
// Error: 2:6-2:6 expected closing paren
|
||||||
|
// Error: 1:9-1:10 expected expression, found closing paren
|
||||||
|
#[f (|f )]
|
36
tests/lang/typ/call-invalid.typ
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Test invalid function calls.
|
||||||
|
|
||||||
|
---
|
||||||
|
// Error: 4-4 expected closing paren
|
||||||
|
{f(}
|
||||||
|
|
||||||
|
---
|
||||||
|
// Error: 4:1-4:1 expected identifier
|
||||||
|
// Error: 3:1-3:1 expected closing bracket
|
||||||
|
#[
|
||||||
|
|
||||||
|
---
|
||||||
|
// Error: 3-3 expected identifier
|
||||||
|
#[]
|
||||||
|
|
||||||
|
// Error: 3-6 expected identifier, found string
|
||||||
|
#["f"]
|
||||||
|
|
||||||
|
// Error: 2:3-2:4 expected identifier, found opening paren
|
||||||
|
// Error: 1:5-1:6 expected expression, found closing paren
|
||||||
|
#[(f)]
|
||||||
|
|
||||||
|
---
|
||||||
|
#let x = "string"
|
||||||
|
|
||||||
|
// Error: 3-4 expected function, found string
|
||||||
|
#[x]
|
||||||
|
|
||||||
|
---
|
||||||
|
// 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 "]
|
11
tests/lang/typ/call-paren.typ
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Test parenthesized function calls.
|
||||||
|
// Ref: false
|
||||||
|
|
||||||
|
---
|
||||||
|
// Whitespace insignificant.
|
||||||
|
#[test type(1), "integer"]
|
||||||
|
#[test type (1), "integer"]
|
||||||
|
|
||||||
|
// From variable.
|
||||||
|
#let alias = type
|
||||||
|
#[test alias(alias), "function"]
|
@ -1,3 +1,6 @@
|
|||||||
|
// Test line and block comments.
|
||||||
|
|
||||||
|
---
|
||||||
// Line comment acts as spacing.
|
// Line comment acts as spacing.
|
||||||
A// you
|
A// you
|
||||||
B
|
B
|
||||||
@ -7,12 +10,13 @@ C/*
|
|||||||
/* */
|
/* */
|
||||||
*/D
|
*/D
|
||||||
|
|
||||||
// Works in headers.
|
// Works in code.
|
||||||
#[f /*1*/ a: "b" //
|
#[f /*1*/ a: "b" //
|
||||||
, 1]
|
, 1]
|
||||||
|
|
||||||
|
---
|
||||||
// End should not appear without start.
|
// End should not appear without start.
|
||||||
// Error: 7-9 unexpected end of block comment
|
// Error: 1:7-1:9 unexpected end of block comment
|
||||||
/* */ */
|
/* */ */
|
||||||
|
|
||||||
// Unterminated is okay.
|
// Unterminated is okay.
|
@ -1,14 +1,18 @@
|
|||||||
|
// Test dictionaries.
|
||||||
|
|
||||||
|
---
|
||||||
// Empty
|
// Empty
|
||||||
{(:)}
|
{(:)}
|
||||||
|
|
||||||
// Two pairs.
|
// Two pairs.
|
||||||
{(one: 1, two: 2)}
|
{(one: 1, two: 2)}
|
||||||
|
|
||||||
// Simple expression after this is already identified as a dictionary.
|
---
|
||||||
|
// Simple expression after already being identified as a dictionary.
|
||||||
// Error: 9-10 expected named pair, found expression
|
// Error: 9-10 expected named pair, found expression
|
||||||
{(a: 1, b)}
|
{(a: 1, b)}
|
||||||
|
|
||||||
// Identified as dictionary by initial colon.
|
// Identified as dictionary due to initial colon.
|
||||||
// Error: 4:4-4:5 expected named pair, found expression
|
// Error: 4:4-4:5 expected named pair, found expression
|
||||||
// Error: 3:5-3:5 expected comma
|
// Error: 3:5-3:5 expected comma
|
||||||
// Error: 2:12-2:16 expected identifier
|
// Error: 2:12-2:16 expected identifier
|
@ -1,11 +0,0 @@
|
|||||||
// Basic.
|
|
||||||
_Emph_ and *strong*!
|
|
||||||
|
|
||||||
// Inside of words.
|
|
||||||
Pa_rtl_y emphasized or str*ength*ened.
|
|
||||||
|
|
||||||
// Scoped to body.
|
|
||||||
#[box][*Sco_ped] to body.
|
|
||||||
|
|
||||||
// Unterminated is fine.
|
|
||||||
_The End
|
|
14
tests/lang/typ/emph.typ
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Test emphasis toggle.
|
||||||
|
|
||||||
|
---
|
||||||
|
// Basic.
|
||||||
|
_Emphasized!_
|
||||||
|
|
||||||
|
// Inside of words.
|
||||||
|
Partly em_phas_ized.
|
||||||
|
|
||||||
|
// Scoped to body.
|
||||||
|
#[box][_Scoped] to body.
|
||||||
|
|
||||||
|
// Unterminated is fine.
|
||||||
|
_The End
|
@ -1,8 +1,11 @@
|
|||||||
|
// Test escape sequences.
|
||||||
|
|
||||||
|
---
|
||||||
// Escapable symbols.
|
// Escapable symbols.
|
||||||
\\ \/ \[ \] \{ \} \* \_ \# \~ \` \$
|
\\ \/ \[ \] \{ \} \# \* \_ \= \~ \` \$
|
||||||
|
|
||||||
// No need to escape.
|
// No need to escape.
|
||||||
( ) = ;
|
( ) ; < >
|
||||||
|
|
||||||
// Unescapable.
|
// Unescapable.
|
||||||
\a \: \; \( \)
|
\a \: \; \( \)
|
||||||
@ -12,7 +15,7 @@
|
|||||||
\/\* \*\/
|
\/\* \*\/
|
||||||
\/* \*/ *
|
\/* \*/ *
|
||||||
|
|
||||||
// Test unicode escape sequence.
|
// Unicode escape sequence.
|
||||||
\u{1F3D5} == 🏕
|
\u{1F3D5} == 🏕
|
||||||
|
|
||||||
// Escaped escape sequence.
|
// Escaped escape sequence.
|
18
tests/lang/typ/expr-assoc.typ
Normal file
@ -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")
|
||||||
|
}
|
132
tests/lang/typ/expr-binary.typ
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
// Test binary expressions.
|
||||||
|
// Ref: false
|
||||||
|
|
||||||
|
---
|
||||||
|
// Test template addition.
|
||||||
|
// Ref: true
|
||||||
|
{[*Hello ] + [world!*]}
|
||||||
|
|
||||||
|
---
|
||||||
|
// Test math operators.
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// 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"]
|
59
tests/lang/typ/expr-invalid.typ
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// Test invalid expressions.
|
||||||
|
// Ref: false
|
||||||
|
|
||||||
|
---
|
||||||
|
// Missing expressions.
|
||||||
|
|
||||||
|
// Error: 3-3 expected expression
|
||||||
|
{-}
|
||||||
|
|
||||||
|
// Error: 11-11 expected expression
|
||||||
|
#[test {1+}, 1]
|
||||||
|
|
||||||
|
// Error: 11-11 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: 15-23 cannot apply '+=' to integer and string
|
||||||
|
{ #let x = 1; x += "2" }
|
||||||
|
|
||||||
|
---
|
||||||
|
// Bad left-hand sides of assignment.
|
||||||
|
|
||||||
|
// Error: 1:3-1:6 cannot assign to this expression
|
||||||
|
{ (x) = "" }
|
||||||
|
|
||||||
|
// Error: 1:3-1:8 cannot assign to this expression
|
||||||
|
{ 1 + 2 += 3 }
|
||||||
|
|
||||||
|
// Error: 1:3-1:4 unknown variable
|
||||||
|
{ z = 1 }
|
||||||
|
|
||||||
|
// Error: 1:3-1: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" }
|
30
tests/lang/typ/expr-prec.typ
Normal file
@ -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: 15-15 expected closing paren
|
||||||
|
#[test {(1 + 1}, 2]
|
||||||
|
|
||||||
|
---
|
||||||
|
// Precedence doesn't matter for chained unary operators.
|
||||||
|
// Error: 2-11 cannot apply '-' to boolean
|
||||||
|
{-not true}
|
23
tests/lang/typ/expr-unary.typ
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Test unary expressions.
|
||||||
|
// Ref: false
|
||||||
|
|
||||||
|
---
|
||||||
|
// 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]
|
||||||
|
|
||||||
|
---
|
||||||
|
// Test not.
|
||||||
|
#[test not true, false]
|
||||||
|
#[test not false, true]
|
@ -1,120 +0,0 @@
|
|||||||
// Ref: false
|
|
||||||
|
|
||||||
#let a = 2
|
|
||||||
#let b = 4
|
|
||||||
|
|
||||||
// Error: 14-17 cannot apply '+' to string
|
|
||||||
#let error = +""
|
|
||||||
|
|
||||||
// Paren call.
|
|
||||||
#[test f(1), "f(1)"]
|
|
||||||
#[test type(1), "integer"]
|
|
||||||
|
|
||||||
// Unary operations.
|
|
||||||
#[test +1, 1]
|
|
||||||
#[test -1, 1-2]
|
|
||||||
#[test --1, 1]
|
|
||||||
|
|
||||||
// Math operations.
|
|
||||||
#[test "a" + "b", "ab"]
|
|
||||||
#[test 1-4, 3*-1]
|
|
||||||
#[test a * b, 8]
|
|
||||||
#[test 12pt/.4, 30pt]
|
|
||||||
#[test 1e+2-1e-2, 99.99]
|
|
||||||
|
|
||||||
// Associativity.
|
|
||||||
#[test 1+2+3, 6]
|
|
||||||
#[test 1/2*3, 1.5]
|
|
||||||
|
|
||||||
// Precedence.
|
|
||||||
#[test 1+2*-3, -5]
|
|
||||||
|
|
||||||
// Short-circuiting logical operators.
|
|
||||||
#[test not "a" == "b", true]
|
|
||||||
#[test not 7 < 4 and 10 == 10, true]
|
|
||||||
#[test 3 < 2 or 4 < 5, true]
|
|
||||||
#[test false and false or true, true]
|
|
||||||
|
|
||||||
// Right-hand side not even evaluated.
|
|
||||||
#[test false and dont-care, false]
|
|
||||||
#[test true or dont-care, true]
|
|
||||||
|
|
||||||
// Equality and inequality.
|
|
||||||
#[test "ab" == "a" + "b", true]
|
|
||||||
#[test [*Hi*] == [*Hi*], true]
|
|
||||||
#[test "a" != "a", false]
|
|
||||||
#[test [*] != [_], true]
|
|
||||||
#[test (1, 2, 3) == (1, 2) + (3,), true]
|
|
||||||
#[test () == (1,), false]
|
|
||||||
#[test (a: 1, b: 2) == (b: 2, a: 1), true]
|
|
||||||
#[test (:) == (a: 1), false]
|
|
||||||
#[test 1 == "hi", false]
|
|
||||||
#[test 1 == 1.0, true]
|
|
||||||
#[test 30% == 30% + 0cm, true]
|
|
||||||
#[test 1in == 0% + 72pt, true]
|
|
||||||
#[test 30% == 30% + 1cm, false]
|
|
||||||
|
|
||||||
// Comparisons.
|
|
||||||
#[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]
|
|
||||||
|
|
||||||
// Assignment.
|
|
||||||
#let x = "some"
|
|
||||||
#let y = "some"
|
|
||||||
#[test (x = y = "") == none and x == none and y == "", true]
|
|
||||||
|
|
||||||
// Modify-assign 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"]
|
|
||||||
|
|
||||||
// Error: 3-4 unknown variable
|
|
||||||
{ z = 1 }
|
|
||||||
|
|
||||||
// Error: 3-6 cannot assign to this expression
|
|
||||||
{ (x) = "" }
|
|
||||||
|
|
||||||
// Error: 3-8 cannot assign to this expression
|
|
||||||
{ 1 + 2 = 3}
|
|
||||||
|
|
||||||
// Error: 3-6 cannot assign to a constant
|
|
||||||
{ box = "hi" }
|
|
||||||
|
|
||||||
// Works if we define box before (since then it doesn't resolve to the standard
|
|
||||||
// library version anymore).
|
|
||||||
#let box = ""; { box = "hi" }
|
|
||||||
|
|
||||||
// Parentheses.
|
|
||||||
#[test (a), 2]
|
|
||||||
#[test (2), 2]
|
|
||||||
#[test (1+2)*3, 9]
|
|
||||||
|
|
||||||
// Error: 3-3 expected expression
|
|
||||||
{-}
|
|
||||||
|
|
||||||
// Error: 11-11 expected expression
|
|
||||||
#[test {1+}, 1]
|
|
||||||
|
|
||||||
// Error: 11-11 expected expression
|
|
||||||
#[test {2*}, 2]
|
|
||||||
|
|
||||||
// Error: 8-17 cannot apply '-' to boolean
|
|
||||||
#[test -not true, error]
|
|
||||||
|
|
||||||
// Error: 2-8 cannot apply 'not' to array
|
|
||||||
{not ()}
|
|
||||||
|
|
||||||
// Error: 3-10 cannot apply '+' to integer and string
|
|
||||||
{(1 + "2")}
|
|
||||||
|
|
||||||
// Error: 2-12 cannot apply '<=' to relative and relative
|
|
||||||
{30% <= 40%}
|
|
35
tests/lang/typ/for-invalid.typ
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Test invalid for loop syntax.
|
||||||
|
|
||||||
|
---
|
||||||
|
// Error: 5-5 expected identifier
|
||||||
|
#for
|
||||||
|
|
||||||
|
// Error: 7-7 expected keyword `#in`
|
||||||
|
#for v
|
||||||
|
|
||||||
|
// Error: 11-11 expected expression
|
||||||
|
#for v #in
|
||||||
|
|
||||||
|
// Error: 16-16 expected body
|
||||||
|
#for v #in iter
|
||||||
|
|
||||||
|
---
|
||||||
|
// Should output `v iter`.
|
||||||
|
// Error: 2:5-2:5 expected identifier
|
||||||
|
// Error: 2:3-2:6 unexpected keyword `#in`
|
||||||
|
#for
|
||||||
|
v #in iter {}
|
||||||
|
|
||||||
|
// Should output `A thing`.
|
||||||
|
// Error: 7-10 expected identifier, found string
|
||||||
|
A#for "v" thing.
|
||||||
|
|
||||||
|
// Should output `iter`.
|
||||||
|
// Error: 2:6-2:9 expected identifier, found string
|
||||||
|
// Error: 1:10-1:13 unexpected keyword `#in`
|
||||||
|
#for "v" #in iter {}
|
||||||
|
|
||||||
|
// Should output `+ b iter`.
|
||||||
|
// Error: 2:7-2:7 expected keyword `#in`
|
||||||
|
// Error: 1:12-1:15 unexpected keyword `#in`
|
||||||
|
#for a + b #in iter {}
|
44
tests/lang/typ/for-loop.typ
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// Test which things are iterable.
|
||||||
|
// Ref: false
|
||||||
|
|
||||||
|
---
|
||||||
|
// Array.
|
||||||
|
|
||||||
|
#for x #in () {}
|
||||||
|
|
||||||
|
#let sum = 0
|
||||||
|
#for x #in (1, 2, 3, 4, 5) {
|
||||||
|
sum += x
|
||||||
|
}
|
||||||
|
#[test sum, 15]
|
||||||
|
|
||||||
|
---
|
||||||
|
// Dictionary.
|
||||||
|
// Ref: true
|
||||||
|
(\ #for k, v #in (name: "Typst", age: 2) [
|
||||||
|
#[h 0.5cm] {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")
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
// Uniterable expression.
|
||||||
|
// Error: 12-16 cannot loop over boolean
|
||||||
|
#for v #in true {}
|
||||||
|
|
||||||
|
// Make sure that we don't complain twice.
|
||||||
|
// Error: 12-19 cannot add integer and string
|
||||||
|
#for v #in 1 + "2" {}
|
30
tests/lang/typ/for-pattern.typ
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Test for loop patterns.
|
||||||
|
// Ref: false
|
||||||
|
|
||||||
|
---
|
||||||
|
#let out = ()
|
||||||
|
|
||||||
|
// Values of array.
|
||||||
|
#for v #in (1, 2, 3) {
|
||||||
|
out += (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 array.
|
||||||
|
// Error: 6-10 mismatched pattern
|
||||||
|
#for k, v #in (-1, -2, -3) {
|
||||||
|
dont-care
|
||||||
|
}
|
20
tests/lang/typ/for-value.typ
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Test return value of for loops.
|
||||||
|
|
||||||
|
---
|
||||||
|
// Template body yields template.
|
||||||
|
// Should output `234`.
|
||||||
|
#for v #in (1, 2, 3, 4) [#if v >= 2 [{v}]]
|
||||||
|
|
||||||
|
---
|
||||||
|
// Block body yields template.
|
||||||
|
// 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])
|
||||||
|
} + [\]]
|
||||||
|
}
|
@ -1,41 +1,44 @@
|
|||||||
// Test different numbers of hashtags.
|
// Test headings.
|
||||||
|
|
||||||
// Valid levels.
|
|
||||||
= One
|
|
||||||
=== Three
|
|
||||||
====== Six
|
|
||||||
|
|
||||||
// Too many hashtags.
|
|
||||||
// Warning: 1-8 should not exceed depth 6
|
|
||||||
======= Seven
|
|
||||||
|
|
||||||
---
|
---
|
||||||
// Test heading vs. no heading.
|
// Different number of hashtags.
|
||||||
|
|
||||||
// Parsed as headings if at start of the context.
|
// Valid levels.
|
||||||
/**/ = Heading
|
=1
|
||||||
{[== Heading]}
|
===2
|
||||||
#[box][=== Heading]
|
======6
|
||||||
|
|
||||||
// Not at the start of the context.
|
// Too many hashtags.
|
||||||
Text = with=sign
|
// Warning: 1:1-1:8 should not exceed depth 6
|
||||||
|
=======7
|
||||||
// Escaped.
|
|
||||||
\= No heading
|
|
||||||
|
|
||||||
---
|
---
|
||||||
// Heading continuation over linebreak.
|
// Heading continuation over linebreak.
|
||||||
|
|
||||||
// Code blocks continue heading.
|
// Code blocks continue heading.
|
||||||
= This {
|
= A{
|
||||||
"continues"
|
"B"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function call continues heading.
|
// Function call continues heading.
|
||||||
= #[box][
|
= #[box][
|
||||||
This,
|
A
|
||||||
] too
|
] B
|
||||||
|
|
||||||
// Without some kind of block, headings end at a line break.
|
// Without some kind of block, headings end at a line break.
|
||||||
= This
|
= A
|
||||||
not
|
B
|
||||||
|
|
||||||
|
---
|
||||||
|
// Heading vs. no heading.
|
||||||
|
|
||||||
|
// Parsed as headings if at start of the context.
|
||||||
|
/**/ = Ok
|
||||||
|
{[== Ok]}
|
||||||
|
#[box][=== Ok]
|
||||||
|
|
||||||
|
// Not at the start of the context.
|
||||||
|
No = heading
|
||||||
|
|
||||||
|
// Escaped.
|
||||||
|
\= No heading
|
45
tests/lang/typ/if-branch.typ
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// Test conditions of if-else expressions.
|
||||||
|
|
||||||
|
---
|
||||||
|
// Test condition evaluation.
|
||||||
|
#if 1 < 2 [
|
||||||
|
Ok.
|
||||||
|
]
|
||||||
|
|
||||||
|
#if true == false [
|
||||||
|
Bad, but we {dont-care}!
|
||||||
|
]
|
||||||
|
|
||||||
|
---
|
||||||
|
// Brace in condition.
|
||||||
|
#if {true} [
|
||||||
|
Ok.
|
||||||
|
]
|
||||||
|
|
||||||
|
// Multi-line condition with parens.
|
||||||
|
#if (
|
||||||
|
1 + 1
|
||||||
|
== 1
|
||||||
|
) {
|
||||||
|
nope
|
||||||
|
} #else {
|
||||||
|
"Ok."
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiline.
|
||||||
|
#if false [
|
||||||
|
Bad.
|
||||||
|
] #else {
|
||||||
|
#let pt = "."
|
||||||
|
"Ok" + pt
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
// 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" {}
|
28
tests/lang/typ/if-invalid.typ
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Test invalid if syntax.
|
||||||
|
|
||||||
|
---
|
||||||
|
// Error: 4-4 expected expression
|
||||||
|
#if
|
||||||
|
|
||||||
|
// Error: 5-5 expected expression
|
||||||
|
{#if}
|
||||||
|
|
||||||
|
// Error: 6-6 expected body
|
||||||
|
#if x
|
||||||
|
|
||||||
|
// Error: 1-6 unexpected keyword `#else`
|
||||||
|
#else {}
|
||||||
|
|
||||||
|
---
|
||||||
|
// Should output `x`.
|
||||||
|
// Error: 4-4 expected expression
|
||||||
|
#if
|
||||||
|
x {}
|
||||||
|
|
||||||
|
// Should output `something`.
|
||||||
|
// Error: 6-6 expected body
|
||||||
|
#if x something
|
||||||
|
|
||||||
|
// Should output `A thing.`
|
||||||
|
// Error: 20-20 expected body
|
||||||
|
A#if false {} #else thing
|
21
tests/lang/typ/if-value.typ
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Test return 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)
|
||||||
|
}
|
@ -1,64 +0,0 @@
|
|||||||
#let x = true
|
|
||||||
|
|
||||||
// The two different bodies.
|
|
||||||
#if true [_1_,] #if x {"2"}
|
|
||||||
|
|
||||||
// Braced condition is fine.
|
|
||||||
#if {true} {"3"}
|
|
||||||
|
|
||||||
// Newlines.
|
|
||||||
#if false [
|
|
||||||
|
|
||||||
] #else [
|
|
||||||
4
|
|
||||||
]
|
|
||||||
|
|
||||||
// Multiline (condition needs parens because it's terminated by the line break,
|
|
||||||
// just like the right-hand side of a let-binding).
|
|
||||||
#if (
|
|
||||||
x
|
|
||||||
) {
|
|
||||||
"Fi" + "ve"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spacing is somewhat delicate. We only want to have spacing in the output if
|
|
||||||
// there was whitespace before/after the full if-else statement. In particular,
|
|
||||||
// spacing after a simple if should be retained, but spacing between the first
|
|
||||||
// body and the else should be ignored.
|
|
||||||
a#if true[b]c \
|
|
||||||
a#if true[b] c \
|
|
||||||
a #if true{"b"}c \
|
|
||||||
a #if true{"b"} c \
|
|
||||||
a#if false [?] #else [b]c \
|
|
||||||
a#if true {"b"} #else {"?"} c \
|
|
||||||
|
|
||||||
// Body not evaluated at all if condition is false.
|
|
||||||
#if false { dont-care-about-undefined-variables }
|
|
||||||
|
|
||||||
---
|
|
||||||
#let x = true
|
|
||||||
|
|
||||||
// Needs condition.
|
|
||||||
// Error: 6-7 expected expression, found closing brace
|
|
||||||
a#if }
|
|
||||||
|
|
||||||
// Needs if-body.
|
|
||||||
// Error: 2:7-2:7 expected body
|
|
||||||
// Error: 1:16-1:16 expected body
|
|
||||||
a#if x b#if (x)c
|
|
||||||
|
|
||||||
// Needs else-body.
|
|
||||||
// Error: 20-20 expected body
|
|
||||||
a#if true [b] #else c
|
|
||||||
|
|
||||||
// Lone else.
|
|
||||||
// Error: 1-6 unexpected keyword `#else`
|
|
||||||
#else []
|
|
||||||
|
|
||||||
// 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" }
|
|
||||||
|
|
||||||
// No coercing from empty array or or stuff like that.
|
|
||||||
// Error: 5-7 expected boolean, found array
|
|
||||||
#if () { "nope" } #else { "nope" }
|
|
20
tests/lang/typ/let-invalid.typ
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Test invalid let binding syntax.
|
||||||
|
|
||||||
|
---
|
||||||
|
// Error: 5-5 expected identifier
|
||||||
|
#let
|
||||||
|
|
||||||
|
// Error: 6-9 expected identifier, found string
|
||||||
|
#let "v"
|
||||||
|
|
||||||
|
// Should output `1`.
|
||||||
|
// Error: 7-7 expected semicolon or line break
|
||||||
|
#let v 1
|
||||||
|
|
||||||
|
// Error: 9-9 expected expression
|
||||||
|
#let v =
|
||||||
|
|
||||||
|
---
|
||||||
|
// Should output `= 1`.
|
||||||
|
// Error: 6-9 expected identifier, found string
|
||||||
|
#let "v" = 1
|
28
tests/lang/typ/let-terminated.typ
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Test termination of let statements.
|
||||||
|
|
||||||
|
---
|
||||||
|
// 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-12 expected semicolon or line break
|
||||||
|
#let v4 = 4 Four
|
||||||
|
|
||||||
|
// Terminated by semicolon even though we are in a paren group.
|
||||||
|
// Error: 2:19-2:19 expected expression
|
||||||
|
// Error: 1:19-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)]
|
11
tests/lang/typ/let-value.typ
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Test value of let binding.
|
||||||
|
// Ref: false
|
||||||
|
|
||||||
|
---
|
||||||
|
// Automatically initialized with none.
|
||||||
|
#let x
|
||||||
|
#[test x, none]
|
||||||
|
|
||||||
|
// Manually initialized with one.
|
||||||
|
#let x = 1
|
||||||
|
#[test x, 1]
|
@ -1,66 +0,0 @@
|
|||||||
// Automatically initialized with `none`.
|
|
||||||
#let x
|
|
||||||
#[test x, none]
|
|
||||||
|
|
||||||
// Initialized with `1`.
|
|
||||||
#let y = 1
|
|
||||||
#[test y, 1]
|
|
||||||
|
|
||||||
// Initialize with template, not terminated by semicolon in template.
|
|
||||||
#let v = [Hello; there]
|
|
||||||
|
|
||||||
// Not terminated by line break due to parens.
|
|
||||||
#let x = (
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
3,
|
|
||||||
)
|
|
||||||
#[test x, (1, 2, 3)]
|
|
||||||
|
|
||||||
// Multiple bindings in one line.
|
|
||||||
#let x = "a"; #let y = "b"; #[test x + y, "ab"]
|
|
||||||
|
|
||||||
// Invalid name.
|
|
||||||
// Error: 6-7 expected identifier, found integer
|
|
||||||
#let 1
|
|
||||||
|
|
||||||
// Invalid name.
|
|
||||||
// Error: 6-7 expected identifier, found integer
|
|
||||||
#let 1 = 2
|
|
||||||
|
|
||||||
// Missing binding name.
|
|
||||||
// Error: 5-5 expected identifier
|
|
||||||
#let
|
|
||||||
x = 5
|
|
||||||
|
|
||||||
// Missing right-hand side.
|
|
||||||
// Error: 9-9 expected expression
|
|
||||||
#let a =
|
|
||||||
|
|
||||||
// No name at all.
|
|
||||||
// Error: 11-11 expected identifier
|
|
||||||
The Fi#let;rst
|
|
||||||
|
|
||||||
// Terminated with just a line break.
|
|
||||||
#let v = "a"
|
|
||||||
The Second #[test v, "a"]
|
|
||||||
|
|
||||||
// Terminated with semicolon + line break.
|
|
||||||
#let v = "a";
|
|
||||||
The Third #[test v, "a"]
|
|
||||||
|
|
||||||
// Terminated with just a semicolon.
|
|
||||||
The#let v = "a"; Fourth #[test v, "a"]
|
|
||||||
|
|
||||||
// Terminated by semicolon even though we are in a paren group.
|
|
||||||
// Error: 2:25-2:25 expected expression
|
|
||||||
// Error: 1:25-1:25 expected closing paren
|
|
||||||
The#let array = (1, 2 + ;Fifth #[test array, (1, 2)]
|
|
||||||
|
|
||||||
// Not terminated.
|
|
||||||
// Error: 16-16 expected semicolon or line break
|
|
||||||
The#let v = "a"Sixth #[test v, "a"]
|
|
||||||
|
|
||||||
// Not terminated.
|
|
||||||
// Error: 16-16 expected semicolon or line break
|
|
||||||
The#let v = "a" #[test v, "a"] Seventh
|
|
@ -1,6 +1,6 @@
|
|||||||
// Leading line break.
|
// Test forced line breaks.
|
||||||
\ Leading
|
|
||||||
|
|
||||||
|
---
|
||||||
// Directly after word.
|
// Directly after word.
|
||||||
Line\ Break
|
Line\ Break
|
||||||
|
|
||||||
@ -10,10 +10,14 @@ Line \ Break
|
|||||||
// Directly before word does not work.
|
// Directly before word does not work.
|
||||||
No \Break
|
No \Break
|
||||||
|
|
||||||
// Trailing before paragraph break.
|
---
|
||||||
Paragraph 1 \
|
// Leading line break.
|
||||||
|
\ Leading
|
||||||
|
|
||||||
Paragraph 2
|
// Trailing before paragraph break.
|
||||||
|
Trailing 1 \
|
||||||
|
|
||||||
|
Trailing 2
|
||||||
|
|
||||||
// Trailing before end of document.
|
// Trailing before end of document.
|
||||||
Paragraph 3 \
|
Trailing 3 \
|
@ -1,2 +1,5 @@
|
|||||||
|
// Test the non breaking space.
|
||||||
|
|
||||||
|
---
|
||||||
// Parsed correctly, but not actually doing anything at the moment.
|
// Parsed correctly, but not actually doing anything at the moment.
|
||||||
The non-breaking~space does not work.
|
The non-breaking~space does not work.
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
#[font 8pt]
|
// Test raw blocks.
|
||||||
|
|
||||||
|
---
|
||||||
// No extra space.
|
// No extra space.
|
||||||
`A``B`
|
`A``B`
|
||||||
|
|
||||||
|
---
|
||||||
// Typst syntax inside.
|
// Typst syntax inside.
|
||||||
`#let x = 1` \
|
`#let x = 1` \
|
||||||
`#[f 1]`
|
`#[f 1]`
|
||||||
|
|
||||||
|
---
|
||||||
|
// Trimming.
|
||||||
|
|
||||||
// Space between "rust" and "let" is trimmed.
|
// Space between "rust" and "let" is trimmed.
|
||||||
The keyword ```rust let```.
|
The keyword ```rust let```.
|
||||||
|
|
||||||
@ -19,15 +24,17 @@ The keyword ```rust let```.
|
|||||||
```py
|
```py
|
||||||
import this
|
import this
|
||||||
|
|
||||||
def say_hi():
|
def hi():
|
||||||
print("Hi!")
|
print("Hi!")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
// Lots of backticks inside.
|
// Lots of backticks inside.
|
||||||
````
|
````
|
||||||
```backticks```
|
```backticks```
|
||||||
````
|
````
|
||||||
|
|
||||||
|
---
|
||||||
// Unterminated.
|
// Unterminated.
|
||||||
// Error: 2:1-2:1 expected backtick(s)
|
// Error: 2:1-2:1 expected backtick(s)
|
||||||
`endless
|
`endless
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
// Test representation of values in the document.
|
// Test representation of values in the document.
|
||||||
|
|
||||||
|
---
|
||||||
|
// Variables.
|
||||||
|
|
||||||
#let name = "Typst"
|
#let name = "Typst"
|
||||||
#let ke-bab = "Kebab!"
|
#let ke-bab = "Kebab!"
|
||||||
#let α = "Alpha"
|
#let α = "Alpha"
|
||||||
|
|
||||||
// Variables.
|
|
||||||
{name} \
|
{name} \
|
||||||
{ke-bab} \
|
{ke-bab} \
|
||||||
{α} \
|
{α} \
|
||||||
@ -12,11 +14,13 @@
|
|||||||
// Error: 2-3 unknown variable
|
// Error: 2-3 unknown variable
|
||||||
{_}
|
{_}
|
||||||
|
|
||||||
|
---
|
||||||
// Literal values.
|
// Literal values.
|
||||||
{none} (empty) \
|
{none} (empty) \
|
||||||
{true} \
|
{true} \
|
||||||
{false} \
|
{false} \
|
||||||
|
|
||||||
|
---
|
||||||
// Numerical values.
|
// Numerical values.
|
||||||
{1} \
|
{1} \
|
||||||
{1.0e-4} \
|
{1.0e-4} \
|
||||||
@ -29,12 +33,15 @@
|
|||||||
{2.5rad} \
|
{2.5rad} \
|
||||||
{45deg} \
|
{45deg} \
|
||||||
|
|
||||||
|
---
|
||||||
// Colors.
|
// Colors.
|
||||||
{#f7a20500} \
|
{#f7a20500} \
|
||||||
|
|
||||||
|
---
|
||||||
// Strings and escaping.
|
// Strings and escaping.
|
||||||
{"hi"} \
|
{"hi"} \
|
||||||
{"a\n[]\"\u{1F680}string"} \
|
{"a\n[]\"\u{1F680}string"} \
|
||||||
|
|
||||||
|
---
|
||||||
// Templates.
|
// Templates.
|
||||||
{[*{"Hi"} #[f 1]*]}
|
{[*{"Hi"} #[f 1]*]}
|
27
tests/lang/typ/spacing.typ
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Test spacing around control flow structures.
|
||||||
|
|
||||||
|
---
|
||||||
|
// Spacing around let.
|
||||||
|
|
||||||
|
// Error: 6-6 expected identifier
|
||||||
|
A#let;B \
|
||||||
|
A#let x = 1;B #[test x, 1] \
|
||||||
|
A #let x = 2;B #[test x, 2] \
|
||||||
|
A#let x = 3; B #[test x, 3] \
|
||||||
|
|
||||||
|
---
|
||||||
|
// Spacing around if-else.
|
||||||
|
|
||||||
|
A#if true[B]C \
|
||||||
|
A#if true[B] C \
|
||||||
|
A #if true{"B"}C \
|
||||||
|
A #if true{"B"} C \
|
||||||
|
A#if false [] #else [B]C \
|
||||||
|
A#if true [B] #else [] C \
|
||||||
|
|
||||||
|
---
|
||||||
|
// Spacing around for loop.
|
||||||
|
|
||||||
|
A#for _ #in (none,) [B]C \
|
||||||
|
A#for _ #in (none,) [B] C \
|
||||||
|
A #for _ #in (none,) [B]C \
|
14
tests/lang/typ/strong.typ
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Test strong toggle.
|
||||||
|
|
||||||
|
---
|
||||||
|
// Basic.
|
||||||
|
*Strong!*
|
||||||
|
|
||||||
|
// Inside of words.
|
||||||
|
Partly str*ength*ened.
|
||||||
|
|
||||||
|
// Scoped to body.
|
||||||
|
#[box][*Scoped] to body.
|
||||||
|
|
||||||
|
// Unterminated is fine.
|
||||||
|
*The End
|
@ -1 +1,8 @@
|
|||||||
|
// Test simple text.
|
||||||
|
|
||||||
|
---
|
||||||
Hello 🌏!
|
Hello 🌏!
|
||||||
|
|
||||||
|
---
|
||||||
|
// Some code stuff in text.
|
||||||
|
let f() , ; : | + - /= == 12 "string"
|
||||||
|
@ -141,12 +141,29 @@ fn test(
|
|||||||
|
|
||||||
let mut ok = true;
|
let mut ok = true;
|
||||||
let mut frames = vec![];
|
let mut frames = vec![];
|
||||||
|
|
||||||
let mut lines = 0;
|
let mut lines = 0;
|
||||||
for (i, part) in src.split("---").enumerate() {
|
let mut compare_ref = true;
|
||||||
let (part_ok, part_frames) = test_part(part, i, lines, env);
|
|
||||||
ok &= part_ok;
|
let parts: Vec<_> = src.split("---").collect();
|
||||||
frames.extend(part_frames);
|
for (i, part) in parts.iter().enumerate() {
|
||||||
|
let is_header = i == 0
|
||||||
|
&& parts.len() > 1
|
||||||
|
&& part
|
||||||
|
.lines()
|
||||||
|
.all(|s| s.starts_with("//") || s.chars().all(|c| c.is_whitespace()));
|
||||||
|
|
||||||
|
if is_header {
|
||||||
|
for line in part.lines() {
|
||||||
|
if line.starts_with("// Ref: false") {
|
||||||
|
compare_ref = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let (part_ok, part_frames) = test_part(part, i, compare_ref, lines, env);
|
||||||
|
ok &= part_ok;
|
||||||
|
frames.extend(part_frames);
|
||||||
|
}
|
||||||
|
|
||||||
lines += part.lines().count() as u32;
|
lines += part.lines().count() as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,9 +196,16 @@ fn test(
|
|||||||
ok
|
ok
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_part(src: &str, i: usize, lines: u32, env: &mut Env) -> (bool, Vec<Frame>) {
|
fn test_part(
|
||||||
|
src: &str,
|
||||||
|
i: usize,
|
||||||
|
compare_ref: bool,
|
||||||
|
lines: u32,
|
||||||
|
env: &mut Env,
|
||||||
|
) -> (bool, Vec<Frame>) {
|
||||||
let map = LineMap::new(src);
|
let map = LineMap::new(src);
|
||||||
let (compare_ref, ref_diags) = parse_metadata(src, &map);
|
let (local_compare_ref, ref_diags) = parse_metadata(src, &map);
|
||||||
|
let compare_ref = local_compare_ref.unwrap_or(compare_ref);
|
||||||
|
|
||||||
let mut scope = library::new();
|
let mut scope = library::new();
|
||||||
|
|
||||||
@ -242,12 +266,20 @@ fn test_part(src: &str, i: usize, lines: u32, env: &mut Env) -> (bool, Vec<Frame
|
|||||||
(ok, frames)
|
(ok, frames)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_metadata(src: &str, map: &LineMap) -> (bool, SpanVec<Diag>) {
|
fn parse_metadata(src: &str, map: &LineMap) -> (Option<bool>, SpanVec<Diag>) {
|
||||||
let mut diags = vec![];
|
let mut diags = vec![];
|
||||||
let mut compare_ref = true;
|
let mut compare_ref = None;
|
||||||
|
|
||||||
for (i, line) in src.lines().enumerate() {
|
for (i, line) in src.lines().enumerate() {
|
||||||
compare_ref &= !line.starts_with("// Ref: false");
|
let line = line.trim();
|
||||||
|
|
||||||
|
if line.starts_with("// Ref: false") {
|
||||||
|
compare_ref = Some(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if line.starts_with("// Ref: true") {
|
||||||
|
compare_ref = Some(true);
|
||||||
|
}
|
||||||
|
|
||||||
let (level, rest) = if let Some(rest) = line.strip_prefix("// Warning: ") {
|
let (level, rest) = if let Some(rest) = line.strip_prefix("// Warning: ") {
|
||||||
(Level::Warning, rest)
|
(Level::Warning, rest)
|
||||||
|