mirror of
https://github.com/typst/typst
synced 2025-06-28 08:12:53 +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::hash::{Hash, Hasher};
|
||||||
use std::sync::Arc;
|
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::diag::{At, TypResult};
|
||||||
use crate::syntax::ast::Expr;
|
use crate::syntax::ast::Expr;
|
||||||
use crate::syntax::{Span, Spanned};
|
use crate::syntax::{Span, Spanned};
|
||||||
@ -138,7 +138,11 @@ impl Closure {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate the body.
|
// 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)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
@ -633,7 +633,12 @@ impl Eval for WhileExpr {
|
|||||||
let condition = self.condition();
|
let condition = self.condition();
|
||||||
while condition.eval(ctx, scp)?.cast::<bool>().at(condition.span())? {
|
while condition.eval(ctx, scp)?.cast::<bool>().at(condition.span())? {
|
||||||
let body = self.body();
|
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())?;
|
output = ops::join(output, value).at(body.span())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -654,7 +659,14 @@ impl Eval for ForExpr {
|
|||||||
for ($($value),*) in $iter {
|
for ($($value),*) in $iter {
|
||||||
$(scp.top.def_mut(&$binding, $value);)*
|
$(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)
|
output = ops::join(output, value)
|
||||||
.at(self.body().span())?;
|
.at(self.body().span())?;
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,55 @@
|
|||||||
// Ref: false
|
// Ref: false
|
||||||
|
|
||||||
---
|
---
|
||||||
|
// Test break.
|
||||||
|
|
||||||
|
#let error = false
|
||||||
|
#let var = 0
|
||||||
|
|
||||||
#for i in range(10) {
|
#for i in range(10) {
|
||||||
|
var += i
|
||||||
if i > 5 {
|
if i > 5 {
|
||||||
// Error: 5-10 break is not yet implemented
|
|
||||||
break
|
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`
|
// Error: 1-10 unexpected keyword `continue`
|
||||||
#continue
|
#continue
|
||||||
|
@ -3,8 +3,15 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
#let f(x) = {
|
#let f(x) = {
|
||||||
// Error: 3-15 return is not yet implemented
|
|
||||||
return x + 1
|
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