diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-01-27 11:54:30 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-01-27 11:54:30 +0100 |
| commit | a8fd64f9289b92614b9e6c16e909ec0c45429027 (patch) | |
| tree | 76ce8797a6fe9c8b8c0bb1783910ba4b9e22da8b /src/syntax/parser.rs | |
| parent | 33585d9a3fbab8a76d3fd8e9c2560f929202a518 (diff) | |
Hashtags everywhere!
Diffstat (limited to 'src/syntax/parser.rs')
| -rw-r--r-- | src/syntax/parser.rs | 222 |
1 files changed, 130 insertions, 92 deletions
diff --git a/src/syntax/parser.rs b/src/syntax/parser.rs index 07f53372..a046b685 100644 --- a/src/syntax/parser.rs +++ b/src/syntax/parser.rs @@ -18,9 +18,7 @@ pub fn parse(text: &str) -> SyntaxNode { /// This is only used for syntax highlighting. pub fn parse_code(text: &str) -> SyntaxNode { let mut p = Parser::new(text, 0, LexMode::Code); - let m = p.marker(); code(&mut p, |_| false); - p.wrap(m, SyntaxKind::CodeBlock); p.finish().into_iter().next().unwrap() } @@ -31,7 +29,15 @@ fn markup( mut stop: impl FnMut(SyntaxKind) -> bool, ) { let m = p.marker(); - while !p.eof() && !stop(p.current) { + let mut nesting: usize = 0; + while !p.eof() { + match p.current() { + SyntaxKind::LeftBracket => nesting += 1, + SyntaxKind::RightBracket if nesting > 0 => nesting -= 1, + _ if stop(p.current) => break, + _ => {} + } + if p.newline() { at_start = true; if min_indent > 0 && p.column(p.current_end()) < min_indent { @@ -54,10 +60,18 @@ pub(super) fn reparse_markup( text: &str, range: Range<usize>, at_start: &mut bool, + nesting: &mut usize, mut stop: impl FnMut(SyntaxKind) -> bool, ) -> Option<Vec<SyntaxNode>> { let mut p = Parser::new(text, range.start, LexMode::Markup); - while !p.eof() && !stop(p.current) && p.current_start() < range.end { + while !p.eof() && p.current_start() < range.end { + match p.current() { + SyntaxKind::LeftBracket => *nesting += 1, + SyntaxKind::RightBracket if *nesting > 0 => *nesting -= 1, + _ if stop(p.current) => break, + _ => {} + } + if p.newline() { *at_start = true; p.eat(); @@ -75,53 +89,41 @@ pub(super) fn reparse_markup( fn markup_expr(p: &mut Parser, at_start: &mut bool) { match p.current() { + SyntaxKind::Space + | SyntaxKind::Parbreak + | SyntaxKind::LineComment + | SyntaxKind::BlockComment => { + p.eat(); + return; + } + + SyntaxKind::Text + | SyntaxKind::Linebreak + | SyntaxKind::Escape + | SyntaxKind::Shorthand + | SyntaxKind::SmartQuote + | SyntaxKind::Raw + | SyntaxKind::Link + | SyntaxKind::Label + | SyntaxKind::Ref => p.eat(), + + SyntaxKind::Hashtag => embedded_code_expr(p), SyntaxKind::Star => strong(p), SyntaxKind::Underscore => emph(p), SyntaxKind::HeadingMarker if *at_start => heading(p), SyntaxKind::ListMarker if *at_start => list_item(p), SyntaxKind::EnumMarker if *at_start => enum_item(p), SyntaxKind::TermMarker if *at_start => term_item(p), - SyntaxKind::Dollar => equation(p), + SyntaxKind::Dollar => formula(p), - SyntaxKind::HeadingMarker + SyntaxKind::LeftBracket + | SyntaxKind::RightBracket + | SyntaxKind::HeadingMarker | SyntaxKind::ListMarker | SyntaxKind::EnumMarker | SyntaxKind::TermMarker | SyntaxKind::Colon => p.convert(SyntaxKind::Text), - SyntaxKind::Ident - | SyntaxKind::Let - | SyntaxKind::Set - | SyntaxKind::Show - | SyntaxKind::If - | SyntaxKind::While - | SyntaxKind::For - | SyntaxKind::Import - | SyntaxKind::Include - | SyntaxKind::Break - | SyntaxKind::Continue - | SyntaxKind::Return - | SyntaxKind::LeftBrace - | SyntaxKind::LeftBracket => embedded_code_expr(p), - - SyntaxKind::Text - | SyntaxKind::Linebreak - | SyntaxKind::Escape - | SyntaxKind::Shorthand - | SyntaxKind::Symbol - | SyntaxKind::SmartQuote - | SyntaxKind::Raw - | SyntaxKind::Link - | SyntaxKind::Label - | SyntaxKind::Ref => p.eat(), - - SyntaxKind::Space - | SyntaxKind::Parbreak - | SyntaxKind::LineComment - | SyntaxKind::BlockComment => { - p.eat(); - return; - } _ => {} } @@ -130,7 +132,7 @@ fn markup_expr(p: &mut Parser, at_start: &mut bool) { fn strong(p: &mut Parser) { let m = p.marker(); - p.expect(SyntaxKind::Star); + p.assert(SyntaxKind::Star); markup(p, false, 0, |kind| { kind == SyntaxKind::Star || kind == SyntaxKind::Parbreak @@ -142,7 +144,7 @@ fn strong(p: &mut Parser) { fn emph(p: &mut Parser) { let m = p.marker(); - p.expect(SyntaxKind::Underscore); + p.assert(SyntaxKind::Underscore); markup(p, false, 0, |kind| { kind == SyntaxKind::Underscore || kind == SyntaxKind::Parbreak @@ -154,7 +156,7 @@ fn emph(p: &mut Parser) { fn heading(p: &mut Parser) { let m = p.marker(); - p.expect(SyntaxKind::HeadingMarker); + p.assert(SyntaxKind::HeadingMarker); whitespace(p); markup(p, false, usize::MAX, |kind| { kind == SyntaxKind::Label || kind == SyntaxKind::RightBracket @@ -164,7 +166,7 @@ fn heading(p: &mut Parser) { fn list_item(p: &mut Parser) { let m = p.marker(); - p.expect(SyntaxKind::ListMarker); + p.assert(SyntaxKind::ListMarker); let min_indent = p.column(p.prev_end()); whitespace(p); markup(p, false, min_indent, |kind| kind == SyntaxKind::RightBracket); @@ -173,7 +175,7 @@ fn list_item(p: &mut Parser) { fn enum_item(p: &mut Parser) { let m = p.marker(); - p.expect(SyntaxKind::EnumMarker); + p.assert(SyntaxKind::EnumMarker); let min_indent = p.column(p.prev_end()); whitespace(p); markup(p, false, min_indent, |kind| kind == SyntaxKind::RightBracket); @@ -182,7 +184,7 @@ fn enum_item(p: &mut Parser) { fn term_item(p: &mut Parser) { let m = p.marker(); - p.expect(SyntaxKind::TermMarker); + p.assert(SyntaxKind::TermMarker); let min_indent = p.column(p.prev_end()); whitespace(p); markup(p, false, usize::MAX, |kind| { @@ -200,17 +202,18 @@ fn whitespace(p: &mut Parser) { } } -fn equation(p: &mut Parser) { +fn formula(p: &mut Parser) { let m = p.marker(); p.enter(LexMode::Math); - p.expect(SyntaxKind::Dollar); + p.assert(SyntaxKind::Dollar); math(p, |kind| kind == SyntaxKind::Dollar); p.expect(SyntaxKind::Dollar); p.exit(); - p.wrap(m, SyntaxKind::Math); + p.wrap(m, SyntaxKind::Formula); } fn math(p: &mut Parser, mut stop: impl FnMut(SyntaxKind) -> bool) { + let m = p.marker(); while !p.eof() && !stop(p.current()) { let prev = p.prev_end(); math_expr(p); @@ -218,6 +221,7 @@ fn math(p: &mut Parser, mut stop: impl FnMut(SyntaxKind) -> bool) { p.unexpected(); } } + p.wrap(m, SyntaxKind::Math); } fn math_expr(p: &mut Parser) { @@ -227,45 +231,44 @@ fn math_expr(p: &mut Parser) { fn math_expr_prec(p: &mut Parser, min_prec: usize, stop: SyntaxKind) { let m = p.marker(); match p.current() { - SyntaxKind::Ident => { + SyntaxKind::Hashtag => embedded_code_expr(p), + SyntaxKind::MathIdent => { p.eat(); - if p.directly_at(SyntaxKind::Atom) && p.current_text() == "(" { + if p.directly_at(SyntaxKind::MathAtom) && p.current_text() == "(" { math_args(p); p.wrap(m, SyntaxKind::FuncCall); + } else { + while p.directly_at(SyntaxKind::MathAtom) + && p.current_text() == "." + && matches!( + p.lexer.clone().next(), + SyntaxKind::MathIdent | SyntaxKind::MathAtom + ) + { + p.convert(SyntaxKind::Dot); + p.convert(SyntaxKind::Ident); + p.wrap(m, SyntaxKind::FieldAccess); + } } } - SyntaxKind::Atom if math_class(p.current_text()) == Some(MathClass::Fence) => { - math_delimited(p, MathClass::Fence) - } - - SyntaxKind::Atom if math_class(p.current_text()) == Some(MathClass::Opening) => { - math_delimited(p, MathClass::Closing) + SyntaxKind::MathAtom => { + 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() + } } - SyntaxKind::Let - | SyntaxKind::Set - | SyntaxKind::Show - | SyntaxKind::If - | SyntaxKind::While - | SyntaxKind::For - | SyntaxKind::Import - | SyntaxKind::Include - | SyntaxKind::Break - | SyntaxKind::Continue - | SyntaxKind::Return - | SyntaxKind::LeftBrace - | SyntaxKind::LeftBracket => embedded_code_expr(p), - - SyntaxKind::Atom - | SyntaxKind::Linebreak + SyntaxKind::Linebreak | SyntaxKind::Escape | SyntaxKind::Shorthand - | SyntaxKind::Symbol - | SyntaxKind::AlignPoint + | SyntaxKind::MathAlignPoint | SyntaxKind::Str => p.eat(), - _ => return, + _ => p.expected("expression"), } while !p.eof() && !p.at(stop) { @@ -282,10 +285,19 @@ fn math_expr_prec(p: &mut Parser, min_prec: usize, stop: SyntaxKind) { ast::Assoc::Right => {} } + if kind == SyntaxKind::MathFrac { + math_unparen(p, m); + } + p.eat(); + let m2 = p.marker(); math_expr_prec(p, prec, stop); + math_unparen(p, m2); + if p.eat_if(SyntaxKind::Underscore) || p.eat_if(SyntaxKind::Hat) { + let m3 = p.marker(); math_expr_prec(p, prec, SyntaxKind::Eof); + math_unparen(p, m3); } p.wrap(m, kind); @@ -294,11 +306,13 @@ fn math_expr_prec(p: &mut Parser, min_prec: usize, stop: SyntaxKind) { fn math_delimited(p: &mut Parser, stop: MathClass) { let m = p.marker(); - p.expect(SyntaxKind::Atom); + p.assert(SyntaxKind::MathAtom); + let m2 = p.marker(); while !p.eof() && !p.at(SyntaxKind::Dollar) { if math_class(p.current_text()) == Some(stop) { - p.eat(); - p.wrap(m, SyntaxKind::Delimited); + p.wrap(m2, SyntaxKind::Math); + p.assert(SyntaxKind::MathAtom); + p.wrap(m, SyntaxKind::MathDelimited); return; } @@ -310,6 +324,22 @@ fn math_delimited(p: &mut Parser, stop: MathClass) { } } +fn math_unparen(p: &mut Parser, m: Marker) { + let Some(node) = p.nodes.get_mut(m.0) else { return }; + if node.kind() != SyntaxKind::MathDelimited { + return; + } + + if let [first, .., last] = node.children_mut() { + if first.text() == "(" && last.text() == ")" { + first.convert_to_kind(SyntaxKind::LeftParen); + last.convert_to_kind(SyntaxKind::RightParen); + } + } + + node.convert_to_kind(SyntaxKind::Math); +} + fn math_class(text: &str) -> Option<MathClass> { let mut chars = text.chars(); chars @@ -321,20 +351,20 @@ fn math_class(text: &str) -> Option<MathClass> { fn math_op(kind: SyntaxKind) -> Option<(SyntaxKind, SyntaxKind, ast::Assoc, usize)> { match kind { SyntaxKind::Underscore => { - Some((SyntaxKind::Script, SyntaxKind::Hat, ast::Assoc::Right, 2)) + Some((SyntaxKind::MathScript, SyntaxKind::Hat, ast::Assoc::Right, 2)) } SyntaxKind::Hat => { - Some((SyntaxKind::Script, SyntaxKind::Underscore, ast::Assoc::Right, 2)) + Some((SyntaxKind::MathScript, SyntaxKind::Underscore, ast::Assoc::Right, 2)) } SyntaxKind::Slash => { - Some((SyntaxKind::Frac, SyntaxKind::Eof, ast::Assoc::Left, 1)) + Some((SyntaxKind::MathFrac, SyntaxKind::Eof, ast::Assoc::Left, 1)) } _ => None, } } fn math_args(p: &mut Parser) { - p.expect(SyntaxKind::Atom); + p.assert(SyntaxKind::MathAtom); let m = p.marker(); let mut m2 = p.marker(); while !p.eof() && !p.at(SyntaxKind::Dollar) { @@ -359,10 +389,11 @@ fn math_args(p: &mut Parser) { p.wrap(m2, SyntaxKind::Math); } p.wrap(m, SyntaxKind::Args); - p.expect(SyntaxKind::Atom); + p.expect(SyntaxKind::MathAtom); } fn code(p: &mut Parser, mut stop: impl FnMut(SyntaxKind) -> bool) { + let m = p.marker(); while !p.eof() && !stop(p.current()) { p.stop_at_newline(true); let prev = p.prev_end(); @@ -379,6 +410,7 @@ fn code(p: &mut Parser, mut stop: impl FnMut(SyntaxKind) -> bool) { p.unexpected(); } } + p.wrap(m, SyntaxKind::Code); } fn code_expr(p: &mut Parser) { @@ -386,6 +418,10 @@ fn code_expr(p: &mut Parser) { } fn embedded_code_expr(p: &mut Parser) { + p.stop_at_newline(true); + p.enter(LexMode::Code); + p.assert(SyntaxKind::Hashtag); + let stmt = matches!( p.current(), SyntaxKind::Let @@ -395,13 +431,12 @@ fn embedded_code_expr(p: &mut Parser) { | SyntaxKind::Include ); - p.stop_at_newline(true); - p.enter(LexMode::Code); code_expr_prec(p, true, 0); let semi = p.eat_if(SyntaxKind::Semicolon); if stmt && !semi && !p.eof() && !p.at(SyntaxKind::RightBracket) { p.expected("semicolon or line break"); } + p.exit(); p.unstop(); } @@ -424,7 +459,10 @@ fn code_expr_prec(p: &mut Parser, atomic: bool, min_prec: usize) { continue; } - if atomic { + let at_field_or_method = + p.directly_at(SyntaxKind::Dot) && p.lexer.clone().next() == SyntaxKind::Ident; + + if atomic && !at_field_or_method { break; } @@ -480,7 +518,7 @@ fn code_primary(p: &mut Parser, atomic: bool) { p.eat(); if !atomic && p.at(SyntaxKind::Arrow) { p.wrap(m, SyntaxKind::Params); - p.expect(SyntaxKind::Arrow); + p.assert(SyntaxKind::Arrow); code_expr(p); p.wrap(m, SyntaxKind::Closure); } @@ -489,7 +527,7 @@ fn code_primary(p: &mut Parser, atomic: bool) { SyntaxKind::LeftBrace => code_block(p), SyntaxKind::LeftBracket => content_block(p), SyntaxKind::LeftParen => with_paren(p), - SyntaxKind::Dollar => equation(p), + SyntaxKind::Dollar => formula(p), SyntaxKind::Let => let_binding(p), SyntaxKind::Set => set_rule(p), SyntaxKind::Show => show_rule(p), @@ -536,7 +574,7 @@ fn code_block(p: &mut Parser) { let m = p.marker(); p.enter(LexMode::Code); p.stop_at_newline(false); - p.expect(SyntaxKind::LeftBrace); + p.assert(SyntaxKind::LeftBrace); code(p, |kind| kind == SyntaxKind::RightBrace); p.expect(SyntaxKind::RightBrace); p.exit(); @@ -547,7 +585,7 @@ fn code_block(p: &mut Parser) { fn content_block(p: &mut Parser) { let m = p.marker(); p.enter(LexMode::Markup); - p.expect(SyntaxKind::LeftBracket); + p.assert(SyntaxKind::LeftBracket); markup(p, true, 0, |kind| kind == SyntaxKind::RightBracket); p.expect(SyntaxKind::RightBracket); p.exit(); @@ -560,7 +598,7 @@ fn with_paren(p: &mut Parser) { if p.at(SyntaxKind::Arrow) { validate_params(p, m); p.wrap(m, SyntaxKind::Params); - p.expect(SyntaxKind::Arrow); + p.assert(SyntaxKind::Arrow); code_expr(p); kind = SyntaxKind::Closure; } @@ -574,7 +612,7 @@ fn with_paren(p: &mut Parser) { fn collection(p: &mut Parser, keyed: bool) -> SyntaxKind { p.stop_at_newline(false); - p.expect(SyntaxKind::LeftParen); + p.assert(SyntaxKind::LeftParen); let mut count = 0; let mut parenthesized = true; |
