1#![doc = include_str!("readme.md")]
2pub mod element_type;
3
4pub use element_type::AplElementType;
5
6use crate::{language::AplLanguage, lexer::token_type::AplTokenType};
7use oak_core::{
8 OakError, TextEdit,
9 parser::{Parser, ParserState},
10 source::Source,
11};
12
13pub(crate) type State<'a, S> = ParserState<'a, AplLanguage, S>;
14
15pub struct AplParser<'config> {
16 pub(crate) config: &'config AplLanguage,
17}
18
19impl<'config> AplParser<'config> {
20 pub fn new(config: &'config AplLanguage) -> Self {
21 Self { config }
22 }
23
24 pub(crate) fn parse_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
26 let cp = state.checkpoint();
27
28 if state.at(AplTokenType::Identifier) && state.peek_kind_at(1) == Some(AplTokenType::LeftArrow) {
30 state.advance(); state.advance(); self.parse_expression(state)?;
33 state.finish_at(cp, AplElementType::Assignment);
34 }
35 else {
36 self.parse_expression(state)?;
37 state.finish_at(cp, AplElementType::Statement);
38 }
39
40 Ok(())
41 }
42
43 pub(crate) fn parse_expression<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
45 let cp = state.checkpoint();
46
47 while state.not_at_end() && !state.at(AplTokenType::Newline) && !state.at(AplTokenType::Diamond) {
48 if state.at(AplTokenType::Identifier) {
49 state.advance();
50 }
51 else if state.at(AplTokenType::NumberLiteral) {
52 state.advance();
53 }
54 else if state.at(AplTokenType::StringLiteral) {
55 state.advance();
56 }
57 else if state.at(AplTokenType::LeftParen) {
58 state.advance();
59 self.parse_expression(state)?;
60 state.expect(AplTokenType::RightParen).ok();
61 }
62 else if state.at(AplTokenType::LeftBrace) {
63 state.advance();
65 while state.not_at_end() && !state.at(AplTokenType::RightBrace) {
66 state.advance();
67 }
68 state.expect(AplTokenType::RightBrace).ok();
69 }
70 else {
71 state.advance();
73 }
74 }
75
76 state.finish_at(cp, AplElementType::Expression);
77 Ok(())
78 }
79}
80
81impl<'config> Parser<AplLanguage> for AplParser<'config> {
82 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl oak_core::ParseCache<AplLanguage>) -> oak_core::ParseOutput<'a, AplLanguage> {
83 let lexer = crate::lexer::AplLexer::new(self.config);
84 oak_core::parser::parse_with_lexer(&lexer, text, edits, cache, |state| {
85 let checkpoint = state.checkpoint();
86
87 while state.not_at_end() && !state.at(AplTokenType::Eof) {
88 if state.at(AplTokenType::Newline) || state.at(AplTokenType::Whitespace) {
89 state.advance();
90 continue;
91 }
92
93 if state.at(AplTokenType::Comment) {
94 state.advance();
95 continue;
96 }
97
98 self.parse_statement(state)?;
99
100 if state.at(AplTokenType::Diamond) {
101 state.advance();
102 }
103 }
104
105 Ok(state.finish_at(checkpoint, AplElementType::Root))
106 })
107 }
108}