1pub mod element_type;
3
4use crate::{
5 language::TypstLanguage,
6 lexer::{TypstLexer, token_type::TypstTokenType},
7 parser::element_type::TypstElementType,
8};
9use oak_core::{
10 GreenNode, OakError,
11 parser::{ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer},
12 source::{Source, TextEdit},
13};
14
15pub(crate) type State<'a, S> = ParserState<'a, TypstLanguage, S>;
16
17pub struct TypstParser<'config> {
19 pub(crate) config: &'config TypstLanguage,
20}
21
22impl<'config> TypstParser<'config> {
23 pub fn new(config: &'config TypstLanguage) -> Self {
25 Self { config }
26 }
27
28 fn parse_item<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
29 let kind = state.peek_kind();
30 match kind {
31 Some(TypstTokenType::Heading) => {
32 let checkpoint = state.checkpoint();
33 state.bump(); while state.not_at_end() && state.peek_kind() != Some(TypstTokenType::Newline) {
35 self.parse_item(state)?;
36 }
37 state.finish_at(checkpoint, TypstElementType::Heading);
38 }
39 Some(TypstTokenType::Hash) => {
40 let checkpoint = state.checkpoint();
41 state.bump(); while state.not_at_end()
44 && state
45 .peek_kind()
46 .map(|k| {
47 matches!(
48 k,
49 TypstTokenType::Identifier
50 | TypstTokenType::Let
51 | TypstTokenType::If
52 | TypstTokenType::Else
53 | TypstTokenType::For
54 | TypstTokenType::While
55 | TypstTokenType::Set
56 | TypstTokenType::Show
57 | TypstTokenType::Import
58 | TypstTokenType::Include
59 )
60 })
61 .unwrap_or(false)
62 {
63 state.bump()
64 }
65
66 if state.peek_kind() == Some(TypstTokenType::LeftBracket) {
67 state.bump(); while state.not_at_end() && state.peek_kind() != Some(TypstTokenType::RightBracket) {
69 self.parse_item(state)?;
70 }
71 if state.peek_kind() == Some(TypstTokenType::RightBracket) {
72 state.bump();
73 }
74 }
75 else {
76 while state.not_at_end() && !matches!(state.peek_kind(), Some(TypstTokenType::Newline) | Some(TypstTokenType::Whitespace)) {
78 state.bump()
79 }
80 }
81 state.finish_at(checkpoint, TypstElementType::Quote);
82 }
83 Some(TypstTokenType::Dollar) => {
84 let checkpoint = state.checkpoint();
85 state.bump(); while state.not_at_end() && state.peek_kind() != Some(TypstTokenType::Dollar) {
87 self.parse_item(state)?;
88 }
89 if state.peek_kind() == Some(TypstTokenType::Dollar) {
90 state.bump()
91 }
92 state.finish_at(checkpoint, TypstElementType::Math);
93 }
94 Some(TypstTokenType::Strong) => {
95 let checkpoint = state.checkpoint();
96 state.bump(); while state.not_at_end() && state.peek_kind() != Some(TypstTokenType::Strong) {
98 self.parse_item(state)?;
99 }
100 if state.peek_kind() == Some(TypstTokenType::Strong) {
101 state.bump()
102 }
103 state.finish_at(checkpoint, TypstElementType::Strong);
104 }
105 Some(TypstTokenType::Emphasis) => {
106 let checkpoint = state.checkpoint();
107 state.bump(); while state.not_at_end() && state.peek_kind() != Some(TypstTokenType::Emphasis) {
109 self.parse_item(state)?;
110 }
111 if state.peek_kind() == Some(TypstTokenType::Emphasis) {
112 state.bump()
113 }
114 state.finish_at(checkpoint, TypstElementType::Emphasis);
115 }
116 Some(TypstTokenType::ListItem) => {
117 let checkpoint = state.checkpoint();
118 state.bump(); while state.not_at_end() && state.peek_kind() != Some(TypstTokenType::Newline) {
120 self.parse_item(state)?;
121 }
122 state.finish_at(checkpoint, TypstElementType::ListItem);
123 }
124 Some(TypstTokenType::EnumItem) => {
125 let checkpoint = state.checkpoint();
126 state.bump(); while state.not_at_end() && state.peek_kind() != Some(TypstTokenType::Newline) {
128 self.parse_item(state)?;
129 }
130 state.finish_at(checkpoint, TypstElementType::EnumItem);
131 }
132 Some(TypstTokenType::Backtick) => {
133 let checkpoint = state.checkpoint();
134 state.bump(); while state.not_at_end() && state.peek_kind() != Some(TypstTokenType::Backtick) {
136 state.bump()
137 }
138 if state.peek_kind() == Some(TypstTokenType::Backtick) {
139 state.bump()
140 }
141 state.finish_at(checkpoint, TypstElementType::Raw);
142 }
143 _ => {
144 state.bump();
145 }
146 };
147 Ok(())
148 }
149}
150
151impl<'config> Parser<TypstLanguage> for TypstParser<'config> {
152 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<TypstLanguage>) -> ParseOutput<'a, TypstLanguage> {
153 let lexer = TypstLexer::new(&self.config);
154 parse_with_lexer(&lexer, text, edits, cache, |state| {
155 let checkpoint = state.checkpoint();
156
157 while state.not_at_end() {
158 self.parse_item(state)?
159 }
160
161 Ok(state.finish_at(checkpoint, TypstElementType::Root))
162 })
163 }
164}