1use crate::language::CSharpLanguage;
2pub mod element_type;
3pub use element_type::CSharpElementType;
4use oak_core::{
5 GreenNode, OakError,
6 parser::{
7 ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer,
8 pratt::{Associativity, Pratt, PrattParser, binary},
9 },
10 source::{Source, TextEdit},
11};
12
13pub(crate) type State<'a, S> = ParserState<'a, CSharpLanguage, S>;
14
15pub struct CSharpParser<'config> {
16 pub(crate) _language: &'config CSharpLanguage,
17}
18
19impl<'config> Pratt<CSharpLanguage> for CSharpParser<'config> {
20 fn primary<'a, S: oak_core::source::Source + ?Sized>(&self, state: &mut ParserState<'a, CSharpLanguage, S>) -> &'a GreenNode<'a, CSharpLanguage> {
21 use crate::{lexer::CSharpTokenType::*, parser::CSharpElementType::*};
22 let cp = state.checkpoint();
23 match state.peek_kind() {
24 Some(Identifier) => {
25 state.bump();
26 state.finish_at(cp, IdentifierName)
27 }
28 Some(Number) | Some(NumberLiteral) | Some(String) | Some(StringLiteral) | Some(TrueKeyword) | Some(FalseKeyword) | Some(NullKeyword) => {
29 state.bump();
30 state.finish_at(cp, LiteralExpression)
31 }
32 Some(LeftParen) => {
33 state.bump();
34 PrattParser::parse(state, 0, self);
35 state.expect(RightParen).ok();
36 state.finish_at(cp, BinaryExpression) }
38 _ => {
39 state.bump();
40 state.finish_at(cp, Root)
41 }
42 }
43 }
44
45 fn prefix<'a, S: oak_core::source::Source + ?Sized>(&self, state: &mut ParserState<'a, CSharpLanguage, S>) -> &'a GreenNode<'a, CSharpLanguage> {
46 self.primary(state)
47 }
48
49 fn infix<'a, S: oak_core::source::Source + ?Sized>(&self, state: &mut ParserState<'a, CSharpLanguage, S>, left: &'a GreenNode<'a, CSharpLanguage>, min_precedence: u8) -> Option<&'a GreenNode<'a, CSharpLanguage>> {
50 use crate::{lexer::CSharpTokenType::*, parser::CSharpElementType::*};
51 let kind = state.peek_kind()?;
52
53 let (prec, assoc) = match kind {
54 Assign | PlusAssign | MinusAssign | StarAssign | SlashAssign | PercentAssign | AndAssign | OrAssign | XorAssign | LeftShiftAssign | RightShiftAssign | QuestionQuestionAssign => (1, Associativity::Right),
55 LogicalOr => (2, Associativity::Left),
56 LogicalAnd => (3, Associativity::Left),
57 Equal | NotEqual | Less | Greater | LessEqual | GreaterEqual | IsKeyword | AsKeyword => (4, Associativity::Left),
58 Plus | Minus => (10, Associativity::Left),
59 Star | Slash | Percent => (11, Associativity::Left),
60 LeftParen | LeftBracket | Dot => (15, Associativity::Left),
61 _ => return None,
62 };
63
64 if prec < min_precedence {
65 return None;
66 }
67
68 match kind {
69 LeftParen => {
70 let cp = state.checkpoint();
71 state.push_child(left);
72 state.expect(LeftParen).ok();
73 while state.not_at_end() && !state.at(RightParen) {
74 state.bump();
75 }
76 state.expect(RightParen).ok();
77 Some(state.finish_at(cp, InvocationExpression))
78 }
79 LeftBracket => {
80 let cp = state.checkpoint();
81 state.push_child(left);
82 state.expect(LeftBracket).ok();
83 while state.not_at_end() && !state.at(RightBracket) {
84 state.bump();
85 }
86 state.expect(RightBracket).ok();
87 Some(state.finish_at(cp, ElementAccessExpression))
88 }
89 Dot => {
90 let cp = state.checkpoint();
91 state.push_child(left);
92 state.expect(Dot).ok();
93 state.expect(Identifier).ok();
94 Some(state.finish_at(cp, MemberAccessExpression))
95 }
96 Assign | PlusAssign | MinusAssign | StarAssign | SlashAssign | PercentAssign | AndAssign | OrAssign | XorAssign | LeftShiftAssign | RightShiftAssign | QuestionQuestionAssign => {
97 Some(binary(state, left, kind, prec, assoc, AssignmentExpression, |s, p| PrattParser::parse(s, p, self)))
98 }
99 _ => Some(binary(state, left, kind, prec, assoc, BinaryExpression, |s, p| PrattParser::parse(s, p, self))),
100 }
101 }
102}
103
104impl<'config> CSharpParser<'config> {
105 pub fn new(language: &'config CSharpLanguage) -> Self {
106 Self { _language: language }
107 }
108
109 fn parse_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
110 use crate::lexer::CSharpTokenType::*;
111 match state.peek_kind() {
112 Some(NamespaceKeyword) => self.parse_namespace_declaration(state)?,
113 Some(UsingKeyword) => self.parse_using_directive(state)?,
114 Some(ClassKeyword) | Some(StructKeyword) | Some(InterfaceKeyword) | Some(EnumKeyword) | Some(PublicKeyword) | Some(PrivateKeyword) | Some(ProtectedKeyword) | Some(InternalKeyword) | Some(StaticKeyword) => self.parse_declaration(state)?,
115 Some(IfKeyword) => self.parse_if_statement(state)?,
116 Some(WhileKeyword) => self.parse_while_statement(state)?,
117 Some(ForKeyword) => self.parse_for_statement(state)?,
118 Some(ReturnKeyword) => self.parse_return_statement(state)?,
119 Some(LeftBrace) => self.parse_block(state)?,
120 _ => {
121 PrattParser::parse(state, 0, self);
122 state.eat(Semicolon);
123 }
124 }
125 Ok(())
126 }
127
128 fn parse_namespace_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
129 use crate::{lexer::CSharpTokenType::*, parser::CSharpElementType::*};
130 let cp = state.checkpoint();
131 state.expect(NamespaceKeyword).ok();
132 while state.not_at_end() && !state.at(LeftBrace) {
133 state.bump();
134 }
135 self.parse_block(state)?;
136 state.finish_at(cp, NamespaceDeclaration);
137 Ok(())
138 }
139
140 fn parse_using_directive<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
141 use crate::{lexer::CSharpTokenType::*, parser::CSharpElementType::*};
142 let cp = state.checkpoint();
143 state.expect(UsingKeyword).ok();
144 while state.not_at_end() && !state.at(Semicolon) {
145 state.bump();
146 }
147 state.eat(Semicolon);
148 state.finish_at(cp, UsingDirective);
149 Ok(())
150 }
151
152 fn parse_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
153 use crate::{lexer::CSharpTokenType::*, parser::CSharpElementType::*};
154 while state.not_at_end() && matches!(state.peek_kind(), Some(PublicKeyword) | Some(PrivateKeyword) | Some(ProtectedKeyword) | Some(InternalKeyword) | Some(StaticKeyword) | Some(ReadonlyKeyword) | Some(AbstractKeyword)) {
156 state.bump();
157 }
158
159 match state.peek_kind() {
160 Some(ClassKeyword) => {
161 let cp = state.checkpoint();
162 state.bump();
163 state.expect(Identifier).ok();
164 while state.not_at_end() && !state.at(LeftBrace) {
165 state.bump();
166 }
167 self.parse_block(state)?;
168 state.finish_at(cp, ClassDeclaration);
169 }
170 Some(InterfaceKeyword) => {
171 let cp = state.checkpoint();
172 state.bump();
173 state.expect(Identifier).ok();
174 self.parse_block(state)?;
175 state.finish_at(cp, InterfaceDeclaration);
176 }
177 _ => {
178 while state.not_at_end() && !state.at(Semicolon) && !state.at(LeftBrace) {
179 state.bump();
180 }
181 if state.eat(LeftBrace) {
182 while state.not_at_end() && !state.at(RightBrace) {
183 self.parse_statement(state)?;
184 }
185 state.expect(RightBrace).ok();
186 }
187 else {
188 state.eat(Semicolon);
189 }
190 }
191 }
192 Ok(())
193 }
194
195 fn parse_if_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
196 use crate::{lexer::CSharpTokenType::*, parser::CSharpElementType::*};
197 let cp = state.checkpoint();
198 state.bump(); state.expect(LeftParen).ok();
200 PrattParser::parse(state, 0, self);
201 state.expect(RightParen).ok();
202 self.parse_statement(state)?;
203 if state.eat(ElseKeyword) {
204 self.parse_statement(state)?;
205 }
206 state.finish_at(cp, IfStatement);
207 Ok(())
208 }
209
210 fn parse_while_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
211 use crate::{lexer::CSharpTokenType::*, parser::CSharpElementType::*};
212 let cp = state.checkpoint();
213 state.bump(); state.expect(LeftParen).ok();
215 PrattParser::parse(state, 0, self);
216 state.expect(RightParen).ok();
217 self.parse_statement(state)?;
218 state.finish_at(cp, WhileStatement);
219 Ok(())
220 }
221
222 fn parse_for_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
223 use crate::{lexer::CSharpTokenType::*, parser::CSharpElementType::*};
224 let cp = state.checkpoint();
225 state.bump(); state.expect(LeftParen).ok();
227 PrattParser::parse(state, 0, self);
228 state.expect(RightParen).ok();
229 self.parse_statement(state)?;
230 state.finish_at(cp, ForStatement);
231 Ok(())
232 }
233
234 fn parse_block<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
235 use crate::{lexer::CSharpTokenType::*, parser::CSharpElementType::*};
236 let cp = state.checkpoint();
237 state.expect(LeftBrace).ok();
238 while state.not_at_end() && !state.at(RightBrace) {
239 self.parse_statement(state)?;
240 }
241 state.expect(RightBrace).ok();
242 state.finish_at(cp, Block);
243 Ok(())
244 }
245
246 fn parse_return_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
247 use crate::{lexer::CSharpTokenType::*, parser::CSharpElementType::*};
248 let cp = state.checkpoint();
249 state.bump(); if !state.at(Semicolon) && !state.at(RightBrace) {
251 PrattParser::parse(state, 0, self);
252 }
253 state.eat(Semicolon);
254 state.finish_at(cp, ReturnStatement);
255 Ok(())
256 }
257}
258
259impl<'config> Parser<CSharpLanguage> for CSharpParser<'config> {
260 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<CSharpLanguage>) -> ParseOutput<'a, CSharpLanguage> {
261 let lexer = crate::lexer::CSharpLexer::new(self._language);
262 parse_with_lexer(&lexer, text, edits, cache, |state| {
263 let cp = state.checkpoint();
264 while state.not_at_end() {
265 self.parse_statement(state)?;
266 }
267 Ok(state.finish_at(cp, crate::parser::CSharpElementType::Root))
268 })
269 }
270}