diff --git a/src/model/eval.rs b/src/model/eval.rs index a32b0cd2..f3281dac 100644 --- a/src/model/eval.rs +++ b/src/model/eval.rs @@ -424,6 +424,7 @@ impl Eval for ast::MathNode { Self::Space(_) => (vm.items.space)(), Self::Linebreak(v) => v.eval(vm)?, Self::Escape(v) => (vm.items.math_atom)(v.get().into()), + Self::Shorthand(v) => (vm.items.math_atom)(v.get().into()), Self::Atom(v) => v.eval(vm)?, Self::Symbol(v) => (vm.items.symbol)(v.get().clone()), Self::Script(v) => v.eval(vm)?, diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs index 55586feb..3661c156 100644 --- a/src/syntax/ast.rs +++ b/src/syntax/ast.rs @@ -441,6 +441,9 @@ pub enum MathNode { Linebreak(Linebreak), /// An escape sequence: `\#`, `\u{1F5FA}`. Escape(Escape), + /// A shorthand for a unicode codepoint. For example, `->` for a right + /// arrow. + Shorthand(Shorthand), /// An atom: `x`, `+`, `12`. Atom(Atom), /// Symbol notation: `:arrow:l:` or `arrow:l`. Notations without any colons @@ -464,6 +467,7 @@ impl AstNode for MathNode { SyntaxKind::Space { .. } => node.cast().map(Self::Space), SyntaxKind::Linebreak => node.cast().map(Self::Linebreak), SyntaxKind::Escape(_) => node.cast().map(Self::Escape), + SyntaxKind::Shorthand(_) => node.cast().map(Self::Shorthand), SyntaxKind::Atom(_) => node.cast().map(Self::Atom), SyntaxKind::Symbol(_) => node.cast().map(Self::Symbol), SyntaxKind::Script => node.cast().map(Self::Script), @@ -479,6 +483,7 @@ impl AstNode for MathNode { Self::Space(v) => v.as_untyped(), Self::Linebreak(v) => v.as_untyped(), Self::Escape(v) => v.as_untyped(), + Self::Shorthand(v) => v.as_untyped(), Self::Atom(v) => v.as_untyped(), Self::Symbol(v) => v.as_untyped(), Self::Script(v) => v.as_untyped(), diff --git a/src/syntax/parsing.rs b/src/syntax/parsing.rs index 5bd5e63b..97570950 100644 --- a/src/syntax/parsing.rs +++ b/src/syntax/parsing.rs @@ -442,6 +442,7 @@ fn math_primary(p: &mut Parser) { | SyntaxKind::Linebreak | SyntaxKind::Escape(_) | SyntaxKind::Str(_) + | SyntaxKind::Shorthand(_) | SyntaxKind::Symbol(_) => p.eat(), // Atoms. diff --git a/src/syntax/tokens.rs b/src/syntax/tokens.rs index 57188096..ff6a1a96 100644 --- a/src/syntax/tokens.rs +++ b/src/syntax/tokens.rs @@ -439,6 +439,18 @@ impl Tokens<'_> { impl Tokens<'_> { fn math(&mut self, start: usize, c: char) -> SyntaxKind { match c { + // Symbol shorthands. + '|' if self.s.eat_if("->") => SyntaxKind::Shorthand('\u{21A6}'), + '<' if self.s.eat_if("->") => SyntaxKind::Shorthand('\u{2194}'), + '<' if self.s.eat_if("=>") => SyntaxKind::Shorthand('\u{21D4}'), + '!' if self.s.eat_if('=') => SyntaxKind::Shorthand('\u{2260}'), + '<' if self.s.eat_if('=') => SyntaxKind::Shorthand('\u{2264}'), + '>' if self.s.eat_if('=') => SyntaxKind::Shorthand('\u{2265}'), + '<' if self.s.eat_if('-') => SyntaxKind::Shorthand('\u{2190}'), + '-' if self.s.eat_if('>') => SyntaxKind::Shorthand('\u{2192}'), + '=' if self.s.eat_if('>') => SyntaxKind::Shorthand('\u{21D2}'), + ':' if self.s.eat_if('=') => SyntaxKind::Shorthand('\u{2254}'), + // Multi-char things. '#' => self.hash(start), diff --git a/tests/ref/math/shorthand.png b/tests/ref/math/shorthand.png new file mode 100644 index 00000000..4b14006b Binary files /dev/null and b/tests/ref/math/shorthand.png differ diff --git a/tests/typ/math/shorthand.typ b/tests/typ/math/shorthand.typ new file mode 100644 index 00000000..d37c938f --- /dev/null +++ b/tests/typ/math/shorthand.typ @@ -0,0 +1,4 @@ +// Test math shorthands. + +--- +$ f : NN <=> RR, n |-> sqrt(n) $