summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-01-28 21:01:05 +0100
committerLaurenz <laurmaedje@gmail.com>2022-01-28 21:01:36 +0100
commit9c906f92c50d453822b12896d29b7883802ea567 (patch)
tree78e2465a4fa805bbddc80407b7eea585b5ebb60c /src
parent3a07603b66fab6b343b34156f4a3a6015e2d69e1 (diff)
Parse `break`, `continue` and `return` expression
Diffstat (limited to 'src')
-rw-r--r--src/eval/mod.rs27
-rw-r--r--src/parse/incremental.rs5
-rw-r--r--src/parse/mod.rs30
-rw-r--r--src/syntax/ast.rs34
-rw-r--r--src/syntax/highlight.rs3
-rw-r--r--src/syntax/mod.rs14
-rw-r--r--src/syntax/pretty.rs29
7 files changed, 140 insertions, 2 deletions
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index 2023004f..a8c6c688 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -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.
diff --git a/src/parse/incremental.rs b/src/parse/incremental.rs
index 2edb84ba..9dd5bec1 100644
--- a/src/parse/incremental.rs
+++ b/src/parse/incremental.rs
@@ -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.
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index 67e35a5a..a9839ed6 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -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() {
diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs
index 6732aa40..13c639f9 100644
--- a/src/syntax/ast.rs
+++ b/src/syntax/ast.rs
@@ -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(),
}
}
}
@@ -1042,6 +1054,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(_)
}
diff --git a/src/syntax/highlight.rs b/src/syntax/highlight.rs
index c399b487..315e8f17 100644
--- a/src/syntax/highlight.rs
+++ b/src/syntax/highlight.rs
@@ -223,6 +223,9 @@ impl Category {
NodeKind::ImportExpr => None,
NodeKind::ImportItems => None,
NodeKind::IncludeExpr => None,
+ NodeKind::BreakExpr => None,
+ NodeKind::ContinueExpr => None,
+ NodeKind::ReturnExpr => None,
}
}
diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs
index 74a642ca..9b606e0e 100644
--- a/src/syntax/mod.rs
+++ b/src/syntax/mod.rs
@@ -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",
diff --git a/src/syntax/pretty.rs b/src/syntax/pretty.rs
index f8285f0c..e8110262 100644
--- a/src/syntax/pretty.rs
+++ b/src/syntax/pretty.rs
@@ -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}");
}
}