1#![doc = include_str!("readme.md")]
2pub mod element_type;
4
5pub use element_type::JElementType;
6
7use crate::{language::JLanguage, lexer::JTokenType};
8use oak_core::{
9 OakError, TextEdit,
10 parser::{ParseCache, ParseOutput, Parser, ParserState},
11 source::Source,
12};
13
14pub(crate) type State<'a, S> = ParserState<'a, JLanguage, S>;
15
16pub struct JParser<'config> {
18 pub(crate) config: &'config JLanguage,
19}
20
21impl<'config> JParser<'config> {
22 pub fn new(config: &'config JLanguage) -> Self {
24 Self { config }
25 }
26
27 fn parse_sentence<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> bool {
29 let cp = state.checkpoint();
30
31 let mut matched;
33 if state.at(JTokenType::Identifier) && (state.peek_kind_at(1) == Some(JTokenType::IsGlobal) || state.peek_kind_at(1) == Some(JTokenType::IsLocal)) {
34 matched = self.parse_assignment(state);
35 }
36 else {
37 matched = self.parse_expression(state);
38 }
39
40 if matched {
41 state.finish_at(cp, JElementType::Sentence);
42 }
43 matched
44 }
45
46 fn parse_assignment<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> bool {
48 let cp = state.checkpoint();
49 state.eat(JTokenType::Identifier);
50 if state.at(JTokenType::IsGlobal) {
51 state.eat(JTokenType::IsGlobal);
52 }
53 else {
54 state.eat(JTokenType::IsLocal);
55 }
56 self.parse_expression(state);
57 state.finish_at(cp, JElementType::Assignment);
58 true
59 }
60
61 fn parse_expression<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> bool {
63 let cp = state.checkpoint();
64 let mut matched = false;
65
66 while state.not_at_end() && !state.at(JTokenType::Newline) && !state.at(JTokenType::Eof) {
67 if state.at(JTokenType::Identifier) {
68 state.eat(JTokenType::Identifier);
69 matched = true;
70 }
71 else if state.at(JTokenType::NumberLiteral) {
72 state.eat(JTokenType::NumberLiteral);
73 matched = true;
74 }
75 else if state.at(JTokenType::StringLiteral) {
76 state.eat(JTokenType::StringLiteral);
77 matched = true;
78 }
79 else if state.at(JTokenType::LeftParen) {
80 let group_cp = state.checkpoint();
81 state.eat(JTokenType::LeftParen);
82 self.parse_expression(state);
83 let _ = state.expect(JTokenType::RightParen);
84 state.finish_at(group_cp, JElementType::Group);
85 matched = true;
86 }
87 else {
88 state.advance();
90 matched = true;
91 }
92 }
93
94 if matched {
95 state.finish_at(cp, JElementType::Expression);
96 }
97 matched
98 }
99}
100
101impl<'config> Parser<JLanguage> for JParser<'config> {
102 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<JLanguage>) -> ParseOutput<'a, JLanguage> {
103 let lexer = crate::lexer::JLexer::new(self.config);
104 oak_core::parser::parse_with_lexer(&lexer, text, edits, cache, |state| {
105 let root_cp = state.checkpoint();
106 let unit_cp = state.checkpoint();
107
108 while state.not_at_end() {
109 if !self.parse_sentence(state) {
110 state.advance();
111 }
112 }
113
114 state.finish_at(unit_cp, JElementType::CompilationUnit);
115 Ok(state.finish_at(root_cp, JElementType::Root))
116 })
117 }
118}