Parse break
, continue
and return
expression
This commit is contained in:
parent
3a07603b66
commit
9c906f92c5
@ -390,6 +390,9 @@ impl Eval for Expr {
|
||||
Self::For(v) => v.eval(ctx),
|
||||
Self::Import(v) => v.eval(ctx),
|
||||
Self::Include(v) => v.eval(ctx),
|
||||
Self::Break(v) => v.eval(ctx),
|
||||
Self::Continue(v) => v.eval(ctx),
|
||||
Self::Return(v) => v.eval(ctx),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -905,6 +908,30 @@ impl Eval for IncludeExpr {
|
||||
}
|
||||
}
|
||||
|
||||
impl Eval for BreakExpr {
|
||||
type Output = Value;
|
||||
|
||||
fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> {
|
||||
Err("break is not yet implemented").at(self.span())
|
||||
}
|
||||
}
|
||||
|
||||
impl Eval for ContinueExpr {
|
||||
type Output = Value;
|
||||
|
||||
fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> {
|
||||
Err("continue is not yet implemented").at(self.span())
|
||||
}
|
||||
}
|
||||
|
||||
impl Eval for ReturnExpr {
|
||||
type Output = Value;
|
||||
|
||||
fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> {
|
||||
Err("return is not yet implemented").at(self.span())
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to mutably access the value an expression points to.
|
||||
///
|
||||
/// This only works if the expression is a valid lvalue.
|
||||
|
@ -548,7 +548,10 @@ impl NodeKind {
|
||||
| Self::ShowExpr
|
||||
| Self::WrapExpr
|
||||
| Self::ImportExpr
|
||||
| Self::IncludeExpr => SuccessionRule::AtomicPrimary,
|
||||
| Self::IncludeExpr
|
||||
| Self::BreakExpr
|
||||
| Self::ContinueExpr
|
||||
| Self::ReturnExpr => SuccessionRule::AtomicPrimary,
|
||||
|
||||
// This element always has to remain in the same column so better
|
||||
// reparse the whole parent.
|
||||
|
@ -405,6 +405,9 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult {
|
||||
Some(NodeKind::For) => for_expr(p),
|
||||
Some(NodeKind::Import) => import_expr(p),
|
||||
Some(NodeKind::Include) => include_expr(p),
|
||||
Some(NodeKind::Break) => break_expr(p),
|
||||
Some(NodeKind::Continue) => continue_expr(p),
|
||||
Some(NodeKind::Return) => return_expr(p),
|
||||
|
||||
Some(NodeKind::Error(_, _)) => {
|
||||
p.eat();
|
||||
@ -833,6 +836,33 @@ fn include_expr(p: &mut Parser) -> ParseResult {
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse a break expression.
|
||||
fn break_expr(p: &mut Parser) -> ParseResult {
|
||||
p.perform(NodeKind::BreakExpr, |p| {
|
||||
p.eat_assert(&NodeKind::Break);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse a continue expression.
|
||||
fn continue_expr(p: &mut Parser) -> ParseResult {
|
||||
p.perform(NodeKind::ContinueExpr, |p| {
|
||||
p.eat_assert(&NodeKind::Continue);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse a return expression.
|
||||
fn return_expr(p: &mut Parser) -> ParseResult {
|
||||
p.perform(NodeKind::ReturnExpr, |p| {
|
||||
p.eat_assert(&NodeKind::Return);
|
||||
if !p.eof() {
|
||||
expr(p)?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse an identifier.
|
||||
fn ident(p: &mut Parser) -> ParseResult {
|
||||
match p.peek() {
|
||||
|
@ -231,6 +231,12 @@ pub enum Expr {
|
||||
Import(ImportExpr),
|
||||
/// An include expression: `include "chapter1.typ"`.
|
||||
Include(IncludeExpr),
|
||||
/// A break expression: `break`.
|
||||
Break(BreakExpr),
|
||||
/// A continue expression: `continue`.
|
||||
Continue(ContinueExpr),
|
||||
/// A return expression: `return`.
|
||||
Return(ReturnExpr),
|
||||
}
|
||||
|
||||
impl TypedNode for Expr {
|
||||
@ -256,6 +262,9 @@ impl TypedNode for Expr {
|
||||
NodeKind::ForExpr => node.cast().map(Self::For),
|
||||
NodeKind::ImportExpr => node.cast().map(Self::Import),
|
||||
NodeKind::IncludeExpr => node.cast().map(Self::Include),
|
||||
NodeKind::BreakExpr => node.cast().map(Self::Break),
|
||||
NodeKind::ContinueExpr => node.cast().map(Self::Continue),
|
||||
NodeKind::ReturnExpr => node.cast().map(Self::Return),
|
||||
_ => node.cast().map(Self::Lit),
|
||||
}
|
||||
}
|
||||
@ -283,6 +292,9 @@ impl TypedNode for Expr {
|
||||
Self::For(v) => v.as_red(),
|
||||
Self::Import(v) => v.as_red(),
|
||||
Self::Include(v) => v.as_red(),
|
||||
Self::Break(v) => v.as_red(),
|
||||
Self::Continue(v) => v.as_red(),
|
||||
Self::Return(v) => v.as_red(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1041,6 +1053,28 @@ impl IncludeExpr {
|
||||
}
|
||||
}
|
||||
|
||||
node! {
|
||||
/// A break expression: `break`.
|
||||
BreakExpr
|
||||
}
|
||||
|
||||
node! {
|
||||
/// A continue expression: `continue`.
|
||||
ContinueExpr
|
||||
}
|
||||
|
||||
node! {
|
||||
/// A return expression: `return x + 1`.
|
||||
ReturnExpr
|
||||
}
|
||||
|
||||
impl ReturnExpr {
|
||||
/// The expression to return.
|
||||
pub fn body(&self) -> Option<Expr> {
|
||||
self.0.cast_last_child()
|
||||
}
|
||||
}
|
||||
|
||||
node! {
|
||||
/// An identifier.
|
||||
Ident: NodeKind::Ident(_)
|
||||
|
@ -223,6 +223,9 @@ impl Category {
|
||||
NodeKind::ImportExpr => None,
|
||||
NodeKind::ImportItems => None,
|
||||
NodeKind::IncludeExpr => None,
|
||||
NodeKind::BreakExpr => None,
|
||||
NodeKind::ContinueExpr => None,
|
||||
NodeKind::ReturnExpr => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -689,6 +689,12 @@ pub enum NodeKind {
|
||||
ImportItems,
|
||||
/// An include expression: `include "chapter1.typ"`.
|
||||
IncludeExpr,
|
||||
/// A break expression: `break`.
|
||||
BreakExpr,
|
||||
/// A continue expression: `continue`.
|
||||
ContinueExpr,
|
||||
/// A return expression: `return x + 1`.
|
||||
ReturnExpr,
|
||||
/// A line comment, two slashes followed by inner contents, terminated with
|
||||
/// a newline: `//<str>\n`.
|
||||
LineComment,
|
||||
@ -755,7 +761,7 @@ impl NodeKind {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this token appears in Markup.
|
||||
/// Which mode this token can appear in, in both if `None`.
|
||||
pub fn mode(&self) -> Option<TokenMode> {
|
||||
match self {
|
||||
Self::Markup(_)
|
||||
@ -780,6 +786,9 @@ impl NodeKind {
|
||||
| Self::Block
|
||||
| Self::Ident(_)
|
||||
| Self::LetExpr
|
||||
| Self::SetExpr
|
||||
| Self::ShowExpr
|
||||
| Self::WrapExpr
|
||||
| Self::IfExpr
|
||||
| Self::WhileExpr
|
||||
| Self::ForExpr
|
||||
@ -897,6 +906,9 @@ impl NodeKind {
|
||||
Self::ImportExpr => "`import` expression",
|
||||
Self::ImportItems => "import items",
|
||||
Self::IncludeExpr => "`include` expression",
|
||||
Self::BreakExpr => "`break` expression",
|
||||
Self::ContinueExpr => "`continue` expression",
|
||||
Self::ReturnExpr => "`return` expression",
|
||||
Self::LineComment => "line comment",
|
||||
Self::BlockComment => "block comment",
|
||||
Self::Error(_, _) => "parse error",
|
||||
|
@ -234,6 +234,9 @@ impl Pretty for Expr {
|
||||
Self::For(v) => v.pretty(p),
|
||||
Self::Import(v) => v.pretty(p),
|
||||
Self::Include(v) => v.pretty(p),
|
||||
Self::Break(v) => v.pretty(p),
|
||||
Self::Continue(v) => v.pretty(p),
|
||||
Self::Return(v) => v.pretty(p),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -547,6 +550,28 @@ impl Pretty for IncludeExpr {
|
||||
}
|
||||
}
|
||||
|
||||
impl Pretty for BreakExpr {
|
||||
fn pretty(&self, p: &mut Printer) {
|
||||
p.push_str("break");
|
||||
}
|
||||
}
|
||||
|
||||
impl Pretty for ContinueExpr {
|
||||
fn pretty(&self, p: &mut Printer) {
|
||||
p.push_str("continue");
|
||||
}
|
||||
}
|
||||
|
||||
impl Pretty for ReturnExpr {
|
||||
fn pretty(&self, p: &mut Printer) {
|
||||
p.push_str("return");
|
||||
if let Some(body) = self.body() {
|
||||
p.push(' ');
|
||||
body.pretty(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Pretty for Ident {
|
||||
fn pretty(&self, p: &mut Printer) {
|
||||
p.push_str(self);
|
||||
@ -681,5 +706,9 @@ mod tests {
|
||||
roundtrip("#for k, x in y {z}");
|
||||
roundtrip("#import * from \"file.typ\"");
|
||||
roundtrip("#include \"chapter1.typ\"");
|
||||
roundtrip("{break}");
|
||||
roundtrip("{continue}");
|
||||
roundtrip("{return}");
|
||||
roundtrip("{return x + 1}");
|
||||
}
|
||||
}
|
||||
|
14
tests/typ/code/break-continue.typ
Normal file
14
tests/typ/code/break-continue.typ
Normal file
@ -0,0 +1,14 @@
|
||||
// Test break and continue in loops.
|
||||
// Ref: false
|
||||
|
||||
---
|
||||
#for i in range(10) {
|
||||
if i > 5 {
|
||||
// Error: 5-10 break is not yet implemented
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
---
|
||||
// Error: 1-10 unexpected keyword `continue`
|
||||
#continue
|
10
tests/typ/code/return.typ
Normal file
10
tests/typ/code/return.typ
Normal file
@ -0,0 +1,10 @@
|
||||
// Test return out of functions.
|
||||
// Ref: false
|
||||
|
||||
---
|
||||
#let f(x) = {
|
||||
// Error: 3-15 return is not yet implemented
|
||||
return x + 1
|
||||
}
|
||||
|
||||
#f(1)
|
Loading…
Reference in New Issue
Block a user