1mod element_type;
2pub use element_type::CppElementType;
3
4use crate::{
5 language::CppLanguage,
6 lexer::{CppLexer, CppTokenType},
7};
8use oak_core::{
9 GreenNode, OakError,
10 parser::{Associativity, ParseCache, ParseOutput, Parser, ParserState, Pratt, PrattParser, parse_with_lexer},
11 source::{Source, TextEdit},
12};
13
14pub(crate) type State<'a, S> = ParserState<'a, CppLanguage, S>;
15
16pub struct CppParser<'config> {
17 pub(crate) config: &'config CppLanguage,
18}
19
20impl<'config> CppParser<'config> {
21 pub fn new(config: &'config CppLanguage) -> Self {
22 Self { config }
23 }
24
25 fn parse_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
26 use crate::lexer::CppTokenType::*;
27 match state.peek_kind() {
28 Some(Keyword) => {
29 state.bump();
30 while state.not_at_end() && !state.at(Semicolon) {
31 state.advance();
32 }
33 state.eat(Semicolon);
34 }
35 Some(LeftBrace) => self.parse_compound_statement(state)?,
36 Some(Preprocessor) => {
37 state.bump();
38 }
39 _ => {
40 PrattParser::parse(state, 0, self);
41 state.eat(Semicolon);
42 }
43 }
44 Ok(())
45 }
46
47 fn parse_compound_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
48 state.expect(CppTokenType::LeftBrace).ok();
49 while state.not_at_end() && !state.at(CppTokenType::RightBrace) {
50 self.parse_statement(state)?;
51 }
52 state.expect(CppTokenType::RightBrace).ok();
53 Ok(())
54 }
55}
56
57impl<'config> Parser<CppLanguage> for CppParser<'config> {
58 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<CppLanguage>) -> ParseOutput<'a, CppLanguage> {
59 let lexer = CppLexer::new(self.config);
60 parse_with_lexer(&lexer, text, edits, cache, |state| {
61 let cp = state.checkpoint();
62 while state.not_at_end() {
63 self.parse_statement(state)?;
64 }
65 Ok(state.finish_at(cp, CppElementType::SourceFile))
66 })
67 }
68}
69
70impl<'config> Pratt<CppLanguage> for CppParser<'config> {
71 fn primary<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, CppLanguage> {
72 use crate::lexer::CppTokenType::*;
73 let cp = state.checkpoint();
74 match state.peek_kind() {
75 Some(Identifier) => {
76 state.bump();
77 state.finish_at(cp, CppElementType::SourceFile) }
79 Some(IntegerLiteral) | Some(FloatLiteral) | Some(CharacterLiteral) | Some(StringLiteral) | Some(BooleanLiteral) => {
80 state.bump();
81 state.finish_at(cp, CppElementType::SourceFile) }
83 Some(LeftParen) => {
84 state.bump();
85 PrattParser::parse(state, 0, self);
86 state.expect(RightParen).ok();
87 state.finish_at(cp, CppElementType::SourceFile)
88 }
89 _ => {
90 state.bump();
91 state.finish_at(cp, CppElementType::Error)
92 }
93 }
94 }
95
96 fn prefix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, CppLanguage> {
97 self.primary(state)
98 }
99
100 fn infix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, left: &'a GreenNode<'a, CppLanguage>, min_precedence: u8) -> Option<&'a GreenNode<'a, CppLanguage>> {
101 use crate::lexer::CppTokenType::*;
102 let kind = state.peek_kind()?;
103
104 let (prec, assoc) = match kind {
105 Assign | PlusAssign | MinusAssign | StarAssign | SlashAssign | PercentAssign | AndAssign | OrAssign | XorAssign | LeftShiftAssign | RightShiftAssign => (1, Associativity::Right),
106 LogicalOr => (2, Associativity::Left),
107 LogicalAnd => (3, Associativity::Left),
108 Equal | NotEqual | Less | Greater | LessEqual | GreaterEqual => (4, Associativity::Left),
109 Plus | Minus => (10, Associativity::Left),
110 Star | Slash | Percent => (11, Associativity::Left),
111 LeftParen | LeftBracket | Dot | Arrow => (15, Associativity::Left),
112 Scope => (16, Associativity::Left),
113 _ => return None,
114 };
115
116 if prec < min_precedence {
117 return None;
118 }
119
120 match kind {
121 LeftParen => {
122 let cp = state.checkpoint();
123 state.push_child(left);
124 state.expect(LeftParen).ok();
125 while state.not_at_end() && !state.at(RightParen) {
126 state.bump();
127 }
128 state.expect(RightParen).ok();
129 Some(state.finish_at(cp, CppElementType::SourceFile))
130 }
131 _ => {
132 let cp = state.checkpoint();
133 state.push_child(left);
134 state.bump();
135 let right = PrattParser::parse(state, prec + (assoc as u8), self);
136 state.push_child(right);
137 Some(state.finish_at(cp, CppElementType::SourceFile))
138 }
139 }
140 }
141}