summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-09-30 18:28:25 +0200
committerLaurenz <laurmaedje@gmail.com>2021-09-30 18:28:25 +0200
commit9e9550262232158328ed7ccb2b620674e5015efc (patch)
tree810a8898d218452855969be74456a1fdefdb27b2
parent989d344d3dc2e08ec2ed5025b202e464a5b29d2c (diff)
No hashtag before else anymore
-rw-r--r--src/parse/mod.rs7
-rw-r--r--src/parse/parser.rs34
-rw-r--r--src/syntax/pretty.rs3
-rw-r--r--tests/typ/code/if.typ14
-rw-r--r--tests/typ/text/whitespace.typ4
-rw-r--r--tools/support/typst.tmLanguage.json4
6 files changed, 28 insertions, 38 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index ee18e697..9cd17604 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -654,12 +654,7 @@ fn if_expr(p: &mut Parser) -> Option<Expr> {
if let Some(condition) = expr(p) {
if let Some(if_body) = body(p) {
let mut else_body = None;
-
- // We are in code mode but still want to react to `#else` if the
- // outer mode is markup.
- if (p.outer_mode() == TokenMode::Code || p.eat_if(Token::Invalid("#")))
- && p.eat_if(Token::Else)
- {
+ if p.eat_if(Token::Else) {
else_body = body(p);
}
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index c035319d..347d6f71 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -28,15 +28,16 @@ pub struct Parser<'s> {
/// A logical group of tokens, e.g. `[...]`.
struct GroupEntry {
- /// The start index of the group. Used by `Parser::end_group` to return the
- /// group's full span.
- pub start: usize,
/// The kind of group this is. This decides which tokens will end the group.
/// For example, a [`Group::Paren`] will be ended by
/// [`Token::RightParen`].
pub kind: Group,
- /// The mode the parser was in _before_ the group started.
- pub outer_mode: TokenMode,
+ /// The start index of the group. Used by `Parser::end_group` to return the
+ /// group's full span.
+ pub start: usize,
+ /// The mode the parser was in _before_ the group started (to which we go
+ /// back once the group ends).
+ pub prev_mode: TokenMode,
}
/// A group, confined by optional start and end delimiters.
@@ -232,9 +233,9 @@ impl<'s> Parser<'s> {
/// This panics if the next token does not start the given group.
pub fn start_group(&mut self, kind: Group, mode: TokenMode) {
self.groups.push(GroupEntry {
- start: self.next_start(),
kind,
- outer_mode: self.tokens.mode(),
+ start: self.next_start(),
+ prev_mode: self.tokens.mode(),
});
self.tokens.set_mode(mode);
@@ -256,7 +257,7 @@ impl<'s> Parser<'s> {
pub fn end_group(&mut self) -> Span {
let prev_mode = self.tokens.mode();
let group = self.groups.pop().expect("no started group");
- self.tokens.set_mode(group.outer_mode);
+ self.tokens.set_mode(group.prev_mode);
self.repeek();
let mut rescan = self.tokens.mode() != prev_mode;
@@ -291,17 +292,6 @@ impl<'s> Parser<'s> {
Span::new(self.id(), group.start, self.prev_end())
}
- /// The tokenization mode outside of the current group.
- ///
- /// For example, this would be [`Markup`] if we are in a [`Code`] group that
- /// is embedded in a [`Markup`] group.
- ///
- /// [`Markup`]: TokenMode::Markup
- /// [`Code`]: TokenMode::Code
- pub fn outer_mode(&mut self) -> TokenMode {
- self.groups.last().map_or(TokenMode::Markup, |group| group.outer_mode)
- }
-
/// Add an error with location and message.
pub fn error(&mut self, span: impl IntoSpan, message: impl Into<String>) {
self.errors.push(Error::new(span.into_span(self.id()), message));
@@ -380,8 +370,10 @@ impl<'s> Parser<'s> {
/// Whether the active group ends at a newline.
fn stop_at_newline(&self) -> bool {
- let active = self.groups.last().map(|group| group.kind);
- matches!(active, Some(Group::Stmt | Group::Expr | Group::Imports))
+ matches!(
+ self.groups.last().map(|group| group.kind),
+ Some(Group::Stmt | Group::Expr | Group::Imports)
+ )
}
/// Whether we are inside the given group.
diff --git a/src/syntax/pretty.rs b/src/syntax/pretty.rs
index 5e4d3ad2..d186eaf6 100644
--- a/src/syntax/pretty.rs
+++ b/src/syntax/pretty.rs
@@ -419,7 +419,6 @@ impl Pretty for IfExpr {
p.push(' ');
self.if_body.pretty(p);
if let Some(expr) = &self.else_body {
- // FIXME: Hashtag in markup.
p.push_str(" else ");
expr.pretty(p);
}
@@ -603,7 +602,7 @@ mod tests {
// Control flow.
roundtrip("#let x = 1 + 2");
test_parse("#let f(x) = y", "#let f = (x) => y");
- test_parse("#if x [y] #else [z]", "#if x [y] else [z]");
+ roundtrip("#if x [y] else [z]");
roundtrip("#while x {y}");
roundtrip("#for x in y {z}");
roundtrip("#for k, x in y {z}");
diff --git a/tests/typ/code/if.typ b/tests/typ/code/if.typ
index 174e6978..36fd3d0f 100644
--- a/tests/typ/code/if.typ
+++ b/tests/typ/code/if.typ
@@ -27,14 +27,14 @@
== 1
) [
Nope.
-] #else {
+] else {
"Three."
}
// Multiline.
#if false [
Bad.
-] #else {
+] else {
let point = "."
"Four" + point
}
@@ -71,7 +71,7 @@
// 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 }
+#if "a" + "b" { nope } else { nope }
---
// Make sure that we don't complain twice.
@@ -101,5 +101,9 @@ x {}
#if x something
// Should output `A thing.`
-// Error: 20 expected body
-A#if false {} #else thing
+// Error: 19 expected body
+A#if false {} else thing
+
+#if a []else [b]
+#if a [] else [b]
+#if a {} else [b]
diff --git a/tests/typ/text/whitespace.typ b/tests/typ/text/whitespace.typ
index 7d5b1a68..aefdab34 100644
--- a/tests/typ/text/whitespace.typ
+++ b/tests/typ/text/whitespace.typ
@@ -12,8 +12,8 @@ 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
+A#if false [] else [B]C \
+A#if true [B] else [] C
---
// Spacing around while loop.
diff --git a/tools/support/typst.tmLanguage.json b/tools/support/typst.tmLanguage.json
index 1c357da6..1677da83 100644
--- a/tools/support/typst.tmLanguage.json
+++ b/tools/support/typst.tmLanguage.json
@@ -133,11 +133,11 @@
"patterns": [{ "include": "#code" }]
},
{
- "begin": "(#)(if|else)\\b",
+ "begin": "((#)if|(?<=(}|])\\s*)else)\\b",
"end": "\n|(?=])|(?<=}|])",
"beginCaptures": {
"0": { "name": "keyword.control.conditional.typst" },
- "1": { "name": "punctuation.definition.keyword.typst" }
+ "2": { "name": "punctuation.definition.keyword.typst" }
},
"patterns": [{ "include": "#code" }]
},