oak_notedown/parser/
mod.rs1pub mod element_type;
3
4use crate::{
5 language::NotedownLanguage,
6 lexer::{NotedownLexer, token_type::NoteTokenType},
7 parser::element_type::NoteElementType,
8};
9use oak_core::{
10 TextEdit,
11 errors::OakError,
12 parser::{ParseCache, ParseOutput, Parser, ParserState},
13 source::Source,
14 tree::GreenNode,
15};
16
17pub(crate) type State<'a, S> = ParserState<'a, NotedownLanguage, S>;
18
19pub struct NoteParser<'a> {
21 pub language: &'a NotedownLanguage,
23}
24
25impl<'a> NoteParser<'a> {
26 pub fn new(language: &'a NotedownLanguage) -> Self {
28 Self { language }
29 }
30}
31
32impl<'p> Parser<NotedownLanguage> for NoteParser<'p> {
33 fn parse<'a, S: Source + ?Sized>(&self, source: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<NotedownLanguage>) -> ParseOutput<'a, NotedownLanguage> {
34 let lexer = NotedownLexer::new(self.language);
35 oak_core::parser::parse_with_lexer(&lexer, source, edits, cache, |state| {
36 let checkpoint = state.checkpoint();
37 while state.not_at_end() {
38 self.parse_block(state);
39 }
40
41 Ok(state.finish_at(checkpoint, NoteElementType::Root))
42 })
43 }
44}
45
46impl<'p> NoteParser<'p> {
47 fn parse_block<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
48 let kind = state.peek_kind();
49 match kind {
50 Some(NoteTokenType::Hash) => self.parse_heading(state),
51 Some(NoteTokenType::Asterisk) | Some(NoteTokenType::Dash) | Some(NoteTokenType::Plus) => self.parse_list_item(state),
52 Some(NoteTokenType::Pipe) => self.parse_table(state),
53 Some(NoteTokenType::Backtick) => self.parse_code_block(state),
54 _ => self.parse_paragraph(state),
55 }
56 }
57
58 fn parse_heading<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
59 let checkpoint = state.checkpoint();
60 let mut level = 0;
61 while state.at(NoteTokenType::Hash) {
62 state.bump();
63 level += 1;
64 }
65
66 self.parse_inline_content(state);
67
68 let kind = match level {
69 1..=6 => NoteElementType::Heading,
70 _ => NoteElementType::Paragraph,
71 };
72 state.finish_at(checkpoint, kind);
73 }
74
75 fn parse_list_item<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
76 let checkpoint = state.checkpoint();
77 state.bump(); self.parse_inline_content(state);
79 state.finish_at(checkpoint, NoteElementType::ListItem);
80 }
81
82 fn parse_table<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
83 let checkpoint = state.checkpoint();
84 while state.not_at_end() && state.at(NoteTokenType::Pipe) {
85 self.parse_table_row(state);
86 while state.at(NoteTokenType::Newline) || state.at(NoteTokenType::Whitespace) {
87 state.bump();
88 }
89 }
90 state.finish_at(checkpoint, NoteElementType::Table);
91 }
92
93 fn parse_table_row<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
94 let checkpoint = state.checkpoint();
95 while state.at(NoteTokenType::Pipe) {
96 self.parse_table_cell(state);
97 }
98 if state.at(NoteTokenType::Newline) {
99 state.bump();
100 }
101 state.finish_at(checkpoint, NoteElementType::TableRow);
102 }
103
104 fn parse_table_cell<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
105 let checkpoint = state.checkpoint();
106 state.bump(); while state.not_at_end() && !state.at(NoteTokenType::Pipe) && !state.at(NoteTokenType::Newline) {
108 self.parse_inline_content(state);
109 }
110 state.finish_at(checkpoint, NoteElementType::Root);
112 }
113
114 fn parse_paragraph<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
115 let checkpoint = state.checkpoint();
116 self.parse_inline_content(state);
117 if state.at(NoteTokenType::Newline) {
118 state.bump();
119 }
120 state.finish_at(checkpoint, NoteElementType::Paragraph);
121 }
122
123 fn parse_inline_content<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
124 while state.not_at_end() && !state.at(NoteTokenType::Newline) {
125 let checkpoint = state.checkpoint();
126 let kind = state.peek_kind();
127 match kind {
128 Some(NoteTokenType::Asterisk) | Some(NoteTokenType::Underscore) => {
129 let marker = kind.unwrap();
130 state.bump();
131 while state.not_at_end() && !state.at(marker) && !state.at(NoteTokenType::Newline) {
132 self.parse_inline_content(state);
133 }
134 if state.at(marker) {
135 state.bump();
136 }
137 state.finish_at(checkpoint, NoteElementType::Root);
138 }
139 Some(NoteTokenType::LeftBracket) => {
140 state.bump(); while state.not_at_end() && !state.at(NoteTokenType::RightBracket) && !state.at(NoteTokenType::Newline) {
142 self.parse_inline_content(state);
143 }
144 if state.at(NoteTokenType::RightBracket) {
145 state.bump();
146 }
147 state.finish_at(checkpoint, NoteElementType::Link);
148 }
149 _ => {
150 state.bump();
151 }
152 }
153 }
154 }
155
156 fn parse_code_block<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
157 let checkpoint = state.checkpoint();
158 state.bump(); while state.not_at_end() && !state.at(NoteTokenType::Backtick) {
160 state.bump();
161 }
162 if state.at(NoteTokenType::Backtick) {
163 state.bump();
164 }
165 state.finish_at(checkpoint, NoteElementType::CodeBlock);
166 }
167}