mirror of
https://github.com/typst/typst
synced 2025-06-28 00:03:17 +08:00
Make loops and functions react to control flow
This commit is contained in:
parent
d007788db8
commit
8e0f5993f1
@ -2,7 +2,7 @@ use std::fmt::{self, Debug, Formatter, Write};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::{Cast, Eval, Scope, Scopes, Value};
|
||||
use super::{Cast, Control, Eval, Scope, Scopes, Value};
|
||||
use crate::diag::{At, TypResult};
|
||||
use crate::syntax::ast::Expr;
|
||||
use crate::syntax::{Span, Spanned};
|
||||
@ -138,7 +138,11 @@ impl Closure {
|
||||
}
|
||||
|
||||
// Evaluate the body.
|
||||
let value = self.body.eval(ctx, &mut scp)?;
|
||||
let value = match self.body.eval(ctx, &mut scp) {
|
||||
Ok(value) => value,
|
||||
Err(Control::Return(value, _)) => return Ok(value.unwrap_or_default()),
|
||||
other => other?,
|
||||
};
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
|
@ -633,7 +633,12 @@ impl Eval for WhileExpr {
|
||||
let condition = self.condition();
|
||||
while condition.eval(ctx, scp)?.cast::<bool>().at(condition.span())? {
|
||||
let body = self.body();
|
||||
let value = body.eval(ctx, scp)?;
|
||||
let value = match body.eval(ctx, scp) {
|
||||
Ok(value) => value,
|
||||
Err(Control::Break(_)) => break,
|
||||
Err(Control::Continue(_)) => continue,
|
||||
other => other?,
|
||||
};
|
||||
output = ops::join(output, value).at(body.span())?;
|
||||
}
|
||||
|
||||
@ -654,7 +659,14 @@ impl Eval for ForExpr {
|
||||
for ($($value),*) in $iter {
|
||||
$(scp.top.def_mut(&$binding, $value);)*
|
||||
|
||||
let value = self.body().eval(ctx, scp)?;
|
||||
let body = self.body();
|
||||
let value = match body.eval(ctx, scp) {
|
||||
Ok(value) => value,
|
||||
Err(Control::Break(_)) => break,
|
||||
Err(Control::Continue(_)) => continue,
|
||||
other => other?,
|
||||
};
|
||||
|
||||
output = ops::join(output, value)
|
||||
.at(self.body().span())?;
|
||||
}
|
||||
|
@ -2,13 +2,55 @@
|
||||
// Ref: false
|
||||
|
||||
---
|
||||
// Test break.
|
||||
|
||||
#let error = false
|
||||
#let var = 0
|
||||
|
||||
#for i in range(10) {
|
||||
var += i
|
||||
if i > 5 {
|
||||
// Error: 5-10 break is not yet implemented
|
||||
break
|
||||
error = true
|
||||
}
|
||||
}
|
||||
|
||||
#test(error, false)
|
||||
#test(var, 21)
|
||||
|
||||
---
|
||||
// Test continue.
|
||||
|
||||
#let x = 0
|
||||
#let i = 0
|
||||
|
||||
#while x < 8 {
|
||||
i += 1
|
||||
|
||||
if mod(i, 3) == 0 {
|
||||
continue
|
||||
}
|
||||
x += i
|
||||
}
|
||||
|
||||
// If continue did not work, this would equal 10.
|
||||
#test(x, 12)
|
||||
|
||||
---
|
||||
// Test break outside of loop.
|
||||
|
||||
#let f() = {
|
||||
// Error: 3-8 cannot break outside of loop
|
||||
break
|
||||
}
|
||||
#f()
|
||||
|
||||
---
|
||||
// Test continue outside of loop.
|
||||
|
||||
// Error: 12-20 cannot continue outside of loop
|
||||
#let x = { continue }
|
||||
|
||||
---
|
||||
// Error: 1-10 unexpected keyword `continue`
|
||||
#continue
|
||||
|
@ -3,8 +3,15 @@
|
||||
|
||||
---
|
||||
#let f(x) = {
|
||||
// Error: 3-15 return is not yet implemented
|
||||
return x + 1
|
||||
}
|
||||
|
||||
#f(1)
|
||||
#test(f(1), 2)
|
||||
|
||||
---
|
||||
// Test return outside of function.
|
||||
|
||||
#for x in range(5) {
|
||||
// Error: 3-9 cannot return outside of function
|
||||
return
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user