summaryrefslogtreecommitdiff
path: root/src/syntax
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-01-28 15:35:56 +0100
committerLaurenz <laurmaedje@gmail.com>2023-01-28 15:36:32 +0100
commit4809e685a231a3ade2c78b75685ee859196c38c1 (patch)
treee3141236cca536c31c6ef4a6df6d218c16ba5a94 /src/syntax
parent28c554ec2185a15e22f0408ce485ed4afe035e03 (diff)
More capable math calls
Diffstat (limited to 'src/syntax')
-rw-r--r--src/syntax/ast.rs63
-rw-r--r--src/syntax/kind.rs3
-rw-r--r--src/syntax/lexer.rs19
-rw-r--r--src/syntax/node.rs8
-rw-r--r--src/syntax/parser.rs56
-rw-r--r--src/syntax/reparser.rs7
6 files changed, 105 insertions, 51 deletions
diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs
index 45f79685..5704f171 100644
--- a/src/syntax/ast.rs
+++ b/src/syntax/ast.rs
@@ -115,8 +115,6 @@ pub enum Expr {
Formula(Formula),
/// A math formula: `$x$`, `$ x^2 $`.
Math(Math),
- /// An atom in a math formula: `x`, `+`, `12`.
- MathAtom(MathAtom),
/// An identifier in a math formula: `pi`.
MathIdent(MathIdent),
/// An alignment point in a math formula: `&`.
@@ -219,7 +217,6 @@ impl AstNode for Expr {
SyntaxKind::TermItem => node.cast().map(Self::Term),
SyntaxKind::Formula => node.cast().map(Self::Formula),
SyntaxKind::Math => node.cast().map(Self::Math),
- SyntaxKind::MathAtom => node.cast().map(Self::MathAtom),
SyntaxKind::MathIdent => node.cast().map(Self::MathIdent),
SyntaxKind::MathAlignPoint => node.cast().map(Self::MathAlignPoint),
SyntaxKind::MathDelimited => node.cast().map(Self::MathDelimited),
@@ -280,7 +277,6 @@ impl AstNode for Expr {
Self::Term(v) => v.as_untyped(),
Self::Formula(v) => v.as_untyped(),
Self::Math(v) => v.as_untyped(),
- Self::MathAtom(v) => v.as_untyped(),
Self::MathIdent(v) => v.as_untyped(),
Self::MathAlignPoint(v) => v.as_untyped(),
Self::MathDelimited(v) => v.as_untyped(),
@@ -320,6 +316,42 @@ impl AstNode for Expr {
}
}
+impl Expr {
+ /// Can this expression be embedded into markup with a hashtag?
+ pub fn hashtag(&self) -> bool {
+ match self {
+ Self::Ident(_) => true,
+ Self::None(_) => true,
+ Self::Auto(_) => true,
+ Self::Bool(_) => true,
+ Self::Int(_) => true,
+ Self::Float(_) => true,
+ Self::Numeric(_) => true,
+ Self::Str(_) => true,
+ Self::Code(_) => true,
+ Self::Content(_) => true,
+ Self::Array(_) => true,
+ Self::Dict(_) => true,
+ Self::Parenthesized(_) => true,
+ Self::FieldAccess(_) => true,
+ Self::FuncCall(_) => true,
+ Self::MethodCall(_) => true,
+ Self::Let(_) => true,
+ Self::Set(_) => true,
+ Self::Show(_) => true,
+ Self::Conditional(_) => true,
+ Self::While(_) => true,
+ Self::For(_) => true,
+ Self::Import(_) => true,
+ Self::Include(_) => true,
+ Self::Break(_) => true,
+ Self::Continue(_) => true,
+ Self::Return(_) => true,
+ _ => false,
+ }
+ }
+}
+
impl Default for Expr {
fn default() -> Self {
Expr::Space(Space::default())
@@ -393,18 +425,23 @@ impl Shorthand {
"..." => '…',
"*" => '∗',
"!=" => '≠',
+ "<<" => '≪',
+ "<<<" => '⋘',
+ ">>" => '≫',
+ ">>>" => '⋙',
"<=" => '≤',
">=" => '≥',
"<-" => '←',
"->" => '→',
"=>" => '⇒',
+ "|->" => '↦',
+ "|=>" => '⤇',
+ "<->" => '↔',
+ "<=>" => '⇔',
":=" => '≔',
"[|" => '⟦',
"|]" => '⟧',
"||" => '‖',
- "|->" => '↦',
- "<->" => '↔',
- "<=>" => '⇔',
_ => char::default(),
}
}
@@ -661,18 +698,6 @@ impl Math {
}
node! {
- /// A atom in a formula: `x`, `+`, `12`.
- MathAtom
-}
-
-impl MathAtom {
- /// Get the atom's text.
- pub fn get(&self) -> &EcoString {
- self.0.text()
- }
-}
-
-node! {
/// An identifier in a math formula: `pi`.
MathIdent
}
diff --git a/src/syntax/kind.rs b/src/syntax/kind.rs
index aa4a5cfe..b2b65a62 100644
--- a/src/syntax/kind.rs
+++ b/src/syntax/kind.rs
@@ -59,8 +59,6 @@ pub enum SyntaxKind {
/// Mathematical markup.
Math,
- /// An atom in math: `x`, `+`, `12`.
- MathAtom,
/// An identifier in math: `pi`.
MathIdent,
/// An alignment point in math: `&`.
@@ -345,7 +343,6 @@ impl SyntaxKind {
Self::Formula => "math formula",
Self::Math => "math",
Self::MathIdent => "math identifier",
- Self::MathAtom => "math atom",
Self::MathAlignPoint => "math alignment point",
Self::MathDelimited => "delimited math",
Self::MathAttach => "math attachments",
diff --git a/src/syntax/lexer.rs b/src/syntax/lexer.rs
index d4548b8b..d267a05b 100644
--- a/src/syntax/lexer.rs
+++ b/src/syntax/lexer.rs
@@ -380,21 +380,28 @@ impl Lexer<'_> {
'\\' => self.backslash(),
'"' => self.string(),
+ '*' => SyntaxKind::Shorthand,
'.' if self.s.eat_if("..") => SyntaxKind::Shorthand,
'|' if self.s.eat_if("->") => SyntaxKind::Shorthand,
- '<' if self.s.eat_if("->") => SyntaxKind::Shorthand,
- '<' if self.s.eat_if("=>") => SyntaxKind::Shorthand,
+ '|' if self.s.eat_if("=>") => SyntaxKind::Shorthand,
'!' if self.s.eat_if('=') => SyntaxKind::Shorthand,
+ '<' if self.s.eat_if("<<") => SyntaxKind::Shorthand,
+ '<' if self.s.eat_if('<') => SyntaxKind::Shorthand,
+ '>' if self.s.eat_if(">>") => SyntaxKind::Shorthand,
+ '>' if self.s.eat_if('>') => SyntaxKind::Shorthand,
+
+ '<' if self.s.eat_if("=>") => SyntaxKind::Shorthand,
+ '<' if self.s.eat_if("->") => SyntaxKind::Shorthand,
'<' if self.s.eat_if('=') => SyntaxKind::Shorthand,
'>' if self.s.eat_if('=') => SyntaxKind::Shorthand,
'<' if self.s.eat_if('-') => SyntaxKind::Shorthand,
'-' if self.s.eat_if('>') => SyntaxKind::Shorthand,
'=' if self.s.eat_if('>') => SyntaxKind::Shorthand,
+
':' if self.s.eat_if('=') => SyntaxKind::Shorthand,
'[' if self.s.eat_if('|') => SyntaxKind::Shorthand,
'|' if self.s.eat_if(']') => SyntaxKind::Shorthand,
'|' if self.s.eat_if('|') => SyntaxKind::Shorthand,
- '*' => SyntaxKind::Shorthand,
'#' if !self.s.at(char::is_whitespace) => SyntaxKind::Hashtag,
'_' => SyntaxKind::Underscore,
@@ -410,11 +417,11 @@ impl Lexer<'_> {
}
// Other math atoms.
- _ => self.atom(start, c),
+ _ => self.math_text(start, c),
}
}
- fn atom(&mut self, start: usize, c: char) -> SyntaxKind {
+ fn math_text(&mut self, start: usize, c: char) -> SyntaxKind {
// Keep numbers and grapheme clusters together.
if c.is_numeric() {
self.s.eat_while(char::is_numeric);
@@ -427,7 +434,7 @@ impl Lexer<'_> {
.map_or(0, str::len);
self.s.jump(start + len);
}
- SyntaxKind::MathAtom
+ SyntaxKind::Text
}
}
diff --git a/src/syntax/node.rs b/src/syntax/node.rs
index a0fa5e1e..ed000788 100644
--- a/src/syntax/node.rs
+++ b/src/syntax/node.rs
@@ -713,14 +713,6 @@ impl<'a> LinkedNode<'a> {
Some(next)
}
}
-
- /// Whether an error follows directly after the node.
- pub fn before_error(&self) -> bool {
- let Some(parent) = self.parent() else { return false };
- let Some(index) = self.index.checked_add(1) else { return false };
- let Some(node) = parent.node.children().nth(index) else { return false };
- node.kind().is_error()
- }
}
/// Access to leafs.
diff --git a/src/syntax/parser.rs b/src/syntax/parser.rs
index 07730533..1b5c10a3 100644
--- a/src/syntax/parser.rs
+++ b/src/syntax/parser.rs
@@ -234,24 +234,24 @@ fn math_expr_prec(p: &mut Parser, min_prec: usize, stop: SyntaxKind) {
SyntaxKind::Hashtag => embedded_code_expr(p),
SyntaxKind::MathIdent => {
p.eat();
- while p.directly_at(SyntaxKind::MathAtom)
+ while p.directly_at(SyntaxKind::Text)
&& p.current_text() == "."
&& matches!(
p.lexer.clone().next(),
- SyntaxKind::MathIdent | SyntaxKind::MathAtom
+ SyntaxKind::MathIdent | SyntaxKind::Text
)
{
p.convert(SyntaxKind::Dot);
p.convert(SyntaxKind::Ident);
p.wrap(m, SyntaxKind::FieldAccess);
}
- if p.directly_at(SyntaxKind::MathAtom) && p.current_text() == "(" {
+ if p.directly_at(SyntaxKind::Text) && p.current_text() == "(" {
math_args(p);
p.wrap(m, SyntaxKind::FuncCall);
}
}
- SyntaxKind::MathAtom | SyntaxKind::Shorthand => {
+ 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) {
@@ -374,16 +374,32 @@ fn math_op(kind: SyntaxKind) -> Option<(SyntaxKind, SyntaxKind, ast::Assoc, usiz
}
fn math_args(p: &mut Parser) {
- p.assert(SyntaxKind::MathAtom);
+ p.assert(SyntaxKind::Text);
+
let m = p.marker();
- let mut m2 = p.marker();
+ let mut arg = p.marker();
+ let mut namable = true;
+ let mut named = None;
+
while !p.eof() && !p.at(SyntaxKind::Dollar) {
+ if namable
+ && (p.at(SyntaxKind::MathIdent) || p.at(SyntaxKind::Text))
+ && p.text[p.current_end()..].starts_with(':')
+ {
+ p.convert(SyntaxKind::Ident);
+ p.convert(SyntaxKind::Colon);
+ named = Some(arg);
+ arg = p.marker();
+ }
+
match p.current_text() {
")" => break,
"," => {
- p.wrap(m2, SyntaxKind::Math);
+ maybe_wrap_in_math(p, arg, named);
p.convert(SyntaxKind::Comma);
- m2 = p.marker();
+ arg = p.marker();
+ namable = true;
+ named = None;
continue;
}
_ => {}
@@ -394,12 +410,30 @@ fn math_args(p: &mut Parser) {
if !p.progress(prev) {
p.unexpected();
}
+
+ namable = false;
}
- if m2 != p.marker() {
- p.wrap(m2, SyntaxKind::Math);
+
+ if arg != p.marker() {
+ maybe_wrap_in_math(p, arg, named);
}
+
p.wrap(m, SyntaxKind::Args);
- p.expect(SyntaxKind::MathAtom);
+ if !p.eat_if(SyntaxKind::Text) {
+ p.expected("closing paren");
+ p.balanced = false;
+ }
+}
+
+fn maybe_wrap_in_math(p: &mut Parser, arg: Marker, named: Option<Marker>) {
+ let exprs = p.post_process(arg).filter(|node| node.is::<ast::Expr>()).count();
+ if exprs != 1 {
+ p.wrap(arg, SyntaxKind::Math);
+ }
+
+ if let Some(m) = named {
+ p.wrap(m, SyntaxKind::Named);
+ }
}
fn code(p: &mut Parser, mut stop: impl FnMut(SyntaxKind) -> bool) {
diff --git a/src/syntax/reparser.rs b/src/syntax/reparser.rs
index de845abf..a876e86b 100644
--- a/src/syntax/reparser.rs
+++ b/src/syntax/reparser.rs
@@ -99,9 +99,9 @@ fn try_reparse(
&& (parent_kind.is_none() || parent_kind == Some(SyntaxKind::ContentBlock))
&& !overlap.is_empty()
{
- // Add one node of slack in both directions.
+ // Add slack in both directions.
let children = node.children_mut();
- let mut start = overlap.start.saturating_sub(1);
+ let mut start = overlap.start.saturating_sub(2);
let mut end = (overlap.end + 1).min(children.len());
// Expand to the left.
@@ -242,7 +242,7 @@ mod tests {
#[test]
fn test_reparse_markup() {
- test("abc~def~ghi", 5..6, "+", true);
+ test("abc~def~gh~", 5..6, "+", true);
test("~~~~~~~", 3..4, "A", true);
test("abc~~", 1..2, "", true);
test("#var. hello", 5..6, " ", false);
@@ -264,7 +264,6 @@ mod tests {
test("#show f: a => b..", 16..16, "c", false);
test("#for", 4..4, "//", false);
test("a\n#let \nb", 7..7, "i", true);
- test("#let x = (1, 2 + ;~ Five\r\n\r", 20..23, "2.", true);
test(r"#{{let x = z}; a = 1} b", 7..7, "//", false);
test(r#"a ```typst hello```"#, 16..17, "", false);
}