1pub mod element_type;
5pub use element_type::XmlElementType;
6
7use crate::{
8 language::XmlLanguage,
9 lexer::{XmlLexer, token_type::XmlTokenType},
10};
11use oak_core::{
12 OakError, TextEdit,
13 parser::{ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer},
14 source::Source,
15};
16
17pub(crate) type State<'a, S> = ParserState<'a, XmlLanguage, S>;
18
19pub struct XmlParser<'config> {
21 pub(crate) config: &'config XmlLanguage,
22}
23
24impl<'config> Parser<XmlLanguage> for XmlParser<'config> {
25 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<XmlLanguage>) -> ParseOutput<'a, XmlLanguage> {
26 let lexer = XmlLexer::new(&self.config);
27 parse_with_lexer(&lexer, text, edits, cache, |state| {
28 let checkpoint = state.checkpoint();
29
30 self.skip_trivia(state);
31 if state.at(XmlTokenType::LeftAngle) && state.peek_kind_at(1) == Some(XmlTokenType::Question) {
32 self.parse_prolog(state)?;
33 }
34
35 while state.not_at_end() {
36 self.skip_trivia(state);
37 if state.at(XmlTokenType::LeftAngle) {
38 self.parse_element(state)?;
39 }
40 else if state.not_at_end() {
41 state.advance();
42 }
43 }
44
45 Ok(state.finish_at(checkpoint, element_type::XmlElementType::Root))
46 })
47 }
48}
49
50impl<'config> XmlParser<'config> {
51 pub fn new(config: &'config XmlLanguage) -> Self {
53 Self { config }
54 }
55
56 pub(crate) fn parse_prolog<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
57 let checkpoint = state.checkpoint();
58 state.expect(XmlTokenType::LeftAngle)?;
59 state.expect(XmlTokenType::Question)?;
60 state.expect(XmlTokenType::Identifier)?; while state.not_at_end() && !state.at(XmlTokenType::Question) {
63 self.skip_trivia(state);
64 if state.at(XmlTokenType::Identifier) {
65 self.parse_attribute(state)?
66 }
67 else {
68 break;
69 }
70 }
71
72 self.skip_trivia(state);
73 state.expect(XmlTokenType::Question)?;
74 state.expect(XmlTokenType::RightAngle)?;
75 state.finish_at(checkpoint, element_type::XmlElementType::Prolog);
76 Ok(())
77 }
78
79 pub(crate) fn parse_element<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
80 let checkpoint = state.checkpoint();
81
82 let start_tag_checkpoint = state.checkpoint();
84 state.expect(XmlTokenType::LeftAngle)?;
85 self.skip_trivia(state);
86 state.expect(XmlTokenType::Identifier)?;
87
88 while state.not_at_end() && !state.at(XmlTokenType::RightAngle) && !state.at(XmlTokenType::SlashRightAngle) {
89 self.skip_trivia(state);
90 if state.at(XmlTokenType::Identifier) {
91 self.parse_attribute(state)?;
92 }
93 else {
94 break;
95 }
96 }
97
98 self.skip_trivia(state);
99 let is_self_closing = state.at(XmlTokenType::SlashRightAngle);
100 if is_self_closing {
101 let self_closing_checkpoint = state.checkpoint();
102 state.expect(XmlTokenType::SlashRightAngle)?;
103 state.finish_at(self_closing_checkpoint, element_type::XmlElementType::SelfClosingTag);
104 state.finish_at(checkpoint, XmlElementType::Element);
105 return Ok(());
106 }
107
108 state.expect(XmlTokenType::RightAngle)?;
109 state.finish_at(start_tag_checkpoint, element_type::XmlElementType::StartTag);
110
111 while state.not_at_end() {
113 self.skip_trivia(state);
114 if state.at(XmlTokenType::LeftAngleSlash) {
115 break;
116 }
117 if state.at(XmlTokenType::LeftAngle) {
118 self.parse_element(state)?;
119 }
120 else {
121 state.advance();
122 }
123 }
124
125 let end_tag_checkpoint = state.checkpoint();
127 state.expect(XmlTokenType::LeftAngleSlash)?;
128 self.skip_trivia(state);
129 state.expect(XmlTokenType::Identifier)?;
130 self.skip_trivia(state);
131 state.expect(XmlTokenType::RightAngle)?;
132 state.finish_at(end_tag_checkpoint, element_type::XmlElementType::EndTag);
133
134 state.finish_at(checkpoint, element_type::XmlElementType::Element);
135 Ok(())
136 }
137
138 fn parse_attribute<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
139 let checkpoint = state.checkpoint();
140 state.expect(XmlTokenType::Identifier)?;
141 self.skip_trivia(state);
142 state.expect(XmlTokenType::Equals)?;
143 self.skip_trivia(state);
144 state.expect(XmlTokenType::StringLiteral)?;
145 state.finish_at(checkpoint, element_type::XmlElementType::Attribute);
146 Ok(())
147 }
148
149 fn skip_trivia<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
150 use oak_core::TokenType;
151 while let Some(token) = state.current() {
152 if token.kind.is_ignored() {
153 state.bump();
154 }
155 else {
156 break;
157 }
158 }
159 }
160}