summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-02-02 22:22:16 +0100
committerLaurenz <laurmaedje@gmail.com>2023-02-02 22:33:12 +0100
commit2bb0135d2ad45b2a7228dbb61a04a703b1942798 (patch)
treee10c45114943dac088e53e3a1133523fbfd5e057
parent255044e04e8b3ad7941a7dadcfd36c07669326aa (diff)
Fix inconsistency between text and idents in math
-rw-r--r--src/ide/highlight.rs1
-rw-r--r--src/syntax/parser.rs51
-rw-r--r--tests/ref/compiler/highlight.pngbin137139 -> 142118 bytes
-rw-r--r--tests/ref/math/attach.pngbin9990 -> 11105 bytes
-rw-r--r--tests/ref/math/frac.pngbin5030 -> 22213 bytes
-rw-r--r--tests/typ/compiler/highlight.typ3
-rw-r--r--tests/typ/math/attach.typ5
-rw-r--r--tests/typ/math/frac.typ15
8 files changed, 55 insertions, 20 deletions
diff --git a/src/ide/highlight.rs b/src/ide/highlight.rs
index e00007f3..0ce6bf8a 100644
--- a/src/ide/highlight.rs
+++ b/src/ide/highlight.rs
@@ -260,6 +260,7 @@ fn highlight_ident(node: &LinkedNode) -> Option<Category> {
if let Some(next) = &next_leaf {
if node.range().end == next.offset()
&& matches!(next.kind(), SyntaxKind::LeftParen | SyntaxKind::LeftBracket)
+ && matches!(next.parent_kind(), Some(SyntaxKind::Args | SyntaxKind::Params))
{
return Some(Category::Function);
}
diff --git a/src/syntax/parser.rs b/src/syntax/parser.rs
index 5933d481..9f951389 100644
--- a/src/syntax/parser.rs
+++ b/src/syntax/parser.rs
@@ -230,9 +230,11 @@ fn math_expr(p: &mut Parser) {
fn math_expr_prec(p: &mut Parser, min_prec: usize, stop: SyntaxKind) {
let m = p.marker();
+ let mut continuable = false;
match p.current() {
SyntaxKind::Hashtag => embedded_code_expr(p),
SyntaxKind::MathIdent => {
+ continuable = true;
p.eat();
while p.directly_at(SyntaxKind::Text)
&& p.current_text() == "."
@@ -245,30 +247,41 @@ fn math_expr_prec(p: &mut Parser, min_prec: usize, stop: SyntaxKind) {
p.convert(SyntaxKind::Ident);
p.wrap(m, SyntaxKind::FieldAccess);
}
- if p.directly_at(SyntaxKind::Text) && p.current_text() == "(" {
+ if min_prec < 3 && p.directly_at(SyntaxKind::Text) && p.current_text() == "("
+ {
math_args(p);
p.wrap(m, SyntaxKind::FuncCall);
+ continuable = false;
}
}
SyntaxKind::Text | SyntaxKind::Shorthand => {
- if math_class(p.current_text()) == Some(MathClass::Fence) {
- math_delimited(p, MathClass::Fence)
- } else if math_class(p.current_text()) == Some(MathClass::Opening) {
- math_delimited(p, MathClass::Closing)
- } else {
- p.eat()
+ continuable = matches!(
+ math_class(p.current_text()),
+ None | Some(MathClass::Alphabetic)
+ );
+ if !maybe_delimited(p, true) {
+ p.eat();
}
}
- SyntaxKind::Linebreak
- | SyntaxKind::Escape
- | SyntaxKind::MathAlignPoint
- | SyntaxKind::Str => p.eat(),
+ SyntaxKind::Linebreak | SyntaxKind::MathAlignPoint => p.eat(),
+ SyntaxKind::Escape | SyntaxKind::Str => {
+ continuable = true;
+ p.eat();
+ }
_ => p.expected("expression"),
}
+ if continuable
+ && min_prec < 3
+ && p.prev_end() == p.current_start()
+ && maybe_delimited(p, false)
+ {
+ p.wrap(m, SyntaxKind::Math);
+ }
+
while !p.eof() && !p.at(stop) {
let Some((kind, stop, assoc, mut prec)) = math_op(p.current()) else {
break;
@@ -302,6 +315,18 @@ fn math_expr_prec(p: &mut Parser, min_prec: usize, stop: SyntaxKind) {
}
}
+fn maybe_delimited(p: &mut Parser, allow_fence: bool) -> bool {
+ if allow_fence && math_class(p.current_text()) == Some(MathClass::Fence) {
+ math_delimited(p, MathClass::Fence);
+ true
+ } else if math_class(p.current_text()) == Some(MathClass::Opening) {
+ math_delimited(p, MathClass::Closing);
+ true
+ } else {
+ false
+ }
+}
+
fn math_delimited(p: &mut Parser, stop: MathClass) {
let m = p.marker();
p.eat();
@@ -361,10 +386,10 @@ fn math_class(text: &str) -> Option<MathClass> {
fn math_op(kind: SyntaxKind) -> Option<(SyntaxKind, SyntaxKind, ast::Assoc, usize)> {
match kind {
SyntaxKind::Underscore => {
- Some((SyntaxKind::MathAttach, SyntaxKind::Hat, ast::Assoc::Right, 2))
+ Some((SyntaxKind::MathAttach, SyntaxKind::Hat, ast::Assoc::Right, 3))
}
SyntaxKind::Hat => {
- Some((SyntaxKind::MathAttach, SyntaxKind::Underscore, ast::Assoc::Right, 2))
+ Some((SyntaxKind::MathAttach, SyntaxKind::Underscore, ast::Assoc::Right, 3))
}
SyntaxKind::Slash => {
Some((SyntaxKind::MathFrac, SyntaxKind::Eof, ast::Assoc::Left, 1))
diff --git a/tests/ref/compiler/highlight.png b/tests/ref/compiler/highlight.png
index 317a2128..dba5591e 100644
--- a/tests/ref/compiler/highlight.png
+++ b/tests/ref/compiler/highlight.png
Binary files differ
diff --git a/tests/ref/math/attach.png b/tests/ref/math/attach.png
index 27843eb4..9c92a93d 100644
--- a/tests/ref/math/attach.png
+++ b/tests/ref/math/attach.png
Binary files differ
diff --git a/tests/ref/math/frac.png b/tests/ref/math/frac.png
index a3a9a3ae..d0ac9c1a 100644
--- a/tests/ref/math/frac.png
+++ b/tests/ref/math/frac.png
Binary files differ
diff --git a/tests/typ/compiler/highlight.typ b/tests/typ/compiler/highlight.typ
index 6c6ec802..2dc2474a 100644
--- a/tests/typ/compiler/highlight.typ
+++ b/tests/typ/compiler/highlight.typ
@@ -5,7 +5,7 @@
#set hello()
#set hello.world()
#set hello.my.world()
-
+#let foo(x) = x * 2
#show heading: func
#show module.func: func
#show module.func: it => {}
@@ -30,6 +30,7 @@ $ hello.my.world $
$ hello.my.world() $
$ hello.my().world $
$ hello.my().world() $
+$ f_zeta(x), f_zeta(x)/1 $
$ emph(hello) $
$ emph(hello()) $
diff --git a/tests/typ/math/attach.typ b/tests/typ/math/attach.typ
index cf3e9521..89ecfc48 100644
--- a/tests/typ/math/attach.typ
+++ b/tests/typ/math/attach.typ
@@ -6,8 +6,9 @@ $f_x + t^b + V_1^2
+ attach(A, top: alpha, bottom: beta)$
---
-// Test text vs ident parsing.
-$pi_1(Y), a_f(x) != a_zeta(x)$
+// Test function call after subscript.
+$pi_1(Y), a_f(x), a^zeta(x) \
+ a^subset.eq(x), a_(zeta(x)), pi_(1(Y))$
---
// Test associativity and scaling.
diff --git a/tests/typ/math/frac.typ b/tests/typ/math/frac.typ
index 27c2ae45..db37e28c 100644
--- a/tests/typ/math/frac.typ
+++ b/tests/typ/math/frac.typ
@@ -9,10 +9,6 @@ $ x = 1/2 = a/(a h) = a/a = a/(1/2) $
$ (|x| + |y|)/2 < [1+2]/3 $
---
-// Test associativity.
-$ 1/2/3 = (1/2)/3 = 1/(2/3) $
-
----
// Test large fraction.
$ x = (-b plus.minus sqrt(b^2 - 4a c))/(2a) $
@@ -23,3 +19,14 @@ $ binom(circle, square) $
---
// Error: 8-13 missing argument: lower index
$ binom(x^2) $
+
+---
+// Test associativity.
+$ 1/2/3 = (1/2)/3 = 1/(2/3) $
+
+---
+// Test precedence.
+$ a_1/b_2, 1/f(x), zeta(x)/2, "foo"[|x|]/2 \
+ 🏳️‍🌈[x]/2, f [x]/2, phi [x]/2, 🏳️‍🌈 [x]/2 \
+ +[x]/2, 1(x)/2, 2[x]/2 \
+ (a)b/2, b(a)[b]/2 $