Skip to main content

oak_cpp/parser/
mod.rs

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) // 简化处理
78            }
79            Some(IntegerLiteral) | Some(FloatLiteral) | Some(CharacterLiteral) | Some(StringLiteral) | Some(BooleanLiteral) => {
80                state.bump();
81                state.finish_at(cp, CppElementType::SourceFile) // 简化处理
82            }
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}