diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-01-28 15:35:56 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-01-28 15:36:32 +0100 |
| commit | 4809e685a231a3ade2c78b75685ee859196c38c1 (patch) | |
| tree | e3141236cca536c31c6ef4a6df6d218c16ba5a94 /src/syntax | |
| parent | 28c554ec2185a15e22f0408ce485ed4afe035e03 (diff) | |
More capable math calls
Diffstat (limited to 'src/syntax')
| -rw-r--r-- | src/syntax/ast.rs | 63 | ||||
| -rw-r--r-- | src/syntax/kind.rs | 3 | ||||
| -rw-r--r-- | src/syntax/lexer.rs | 19 | ||||
| -rw-r--r-- | src/syntax/node.rs | 8 | ||||
| -rw-r--r-- | src/syntax/parser.rs | 56 | ||||
| -rw-r--r-- | src/syntax/reparser.rs | 7 |
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); } |
