Skip to main content

oak_xml/parser/
mod.rs

1//! XML parser implementation.
2
3/// XML element types.
4pub 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
19/// XML parser.
20pub 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    /// Creates a new `XmlParser`.
52    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)?; // xml
61
62        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        // Start Tag
83        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        // Content
112        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        // End Tag
126        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}