1use crate::{
2 ast::*,
3 language::ElixirLanguage,
4 lexer::token_type::ElixirTokenType,
5 parser::{ElixirParser, element_type::ElixirElementType},
6};
7use core::range::Range;
8use oak_core::{Builder, BuilderCache, GreenNode, OakDiagnostics, OakError, Parser, RedNode, RedTree, SourceText, TextEdit, builder::BuildOutput, source::Source};
9
10#[derive(Clone, Copy)]
12pub struct ElixirBuilder<'config> {
13 config: &'config ElixirLanguage,
15}
16
17impl<'config> ElixirBuilder<'config> {
18 pub fn new(config: &'config ElixirLanguage) -> Self {
20 Self { config }
21 }
22}
23
24impl<'config> Builder<ElixirLanguage> for ElixirBuilder<'config> {
25 fn build<'a, S: Source + ?Sized>(&self, source: &S, edits: &[TextEdit], _cache: &'a mut impl BuilderCache<ElixirLanguage>) -> BuildOutput<ElixirLanguage> {
26 let parser = ElixirParser::new(self.config);
27
28 let mut cache = oak_core::parser::session::ParseSession::<ElixirLanguage>::default();
29 let parse_result = parser.parse(source, edits, &mut cache);
30
31 match parse_result.result {
32 Ok(green_tree) => {
33 let source_text = SourceText::new(source.get_text_in((0..source.length()).into()).into_owned());
34 match self.build_root(green_tree.clone(), &source_text) {
35 Ok(ast_root) => OakDiagnostics { result: Ok(ast_root), diagnostics: parse_result.diagnostics },
36 Err(build_error) => {
37 let mut diagnostics = parse_result.diagnostics;
38 diagnostics.push(build_error.clone());
39 OakDiagnostics { result: Err(build_error), diagnostics }
40 }
41 }
42 }
43 Err(parse_error) => OakDiagnostics { result: Err(parse_error), diagnostics: parse_result.diagnostics },
44 }
45 }
46}
47
48impl<'config> ElixirBuilder<'config> {
49 pub(crate) fn build_root(&self, green_tree: GreenNode<ElixirLanguage>, source: &SourceText) -> Result<ElixirRoot, OakError> {
51 let red_root = RedNode::new(&green_tree, 0);
52 let mut items = Vec::new();
53
54 for child in red_root.children() {
55 match child {
56 RedTree::Node(n) => {
57 if let Some(item) = self.build_item(n, source)? {
58 items.push(item);
59 }
60 }
61 RedTree::Leaf(_) => {}
62 }
63 }
64 Ok(ElixirRoot { items })
65 }
66
67 fn build_item(&self, node: RedNode<ElixirLanguage>, source: &SourceText) -> Result<Option<Item>, OakError> {
68 match node.green.kind {
69 ElixirElementType::ModuleDefinition => {
70 let module = self.build_module(node, source)?;
71 Ok(Some(Item::Module(module)))
72 }
73 ElixirElementType::FunctionDefinition => {
74 let func = self.build_function(node, source)?;
75 Ok(Some(Item::Function(func)))
76 }
77 _ => {
78 if let Some(expr) = self.build_expr_opt(node, source)? {
79 Ok(Some(Item::Statement(Statement::ExprStmt { span: expr_span(&expr), expr })))
80 }
81 else {
82 Ok(None)
83 }
84 }
85 }
86 }
87
88 fn build_module(&self, node: RedNode<ElixirLanguage>, source: &SourceText) -> Result<Module, OakError> {
89 let span = node.span();
90 let mut name = Identifier { name: String::new(), span: (0..0).into() };
91 let mut items = Vec::new();
92
93 for child in node.children() {
94 match child {
95 RedTree::Node(n) => match n.green.kind {
96 ElixirElementType::IdentifierExpression => {
97 name = self.build_identifier(n, source)?;
98 }
99 _ => {
100 if let Some(item) = self.build_item(n, source)? {
101 items.push(item);
102 }
103 }
104 },
105 RedTree::Leaf(t) => {
106 if t.kind == ElixirTokenType::Identifier {
107 name = Identifier { name: text(source, t.span.clone().into()), span: t.span.clone().into() };
108 }
109 }
110 }
111 }
112
113 Ok(Module { name, items, span: span.into() })
114 }
115
116 fn build_function(&self, node: RedNode<ElixirLanguage>, source: &SourceText) -> Result<Function, OakError> {
117 let span = node.span();
118 let mut name = Identifier { name: String::new(), span: (0..0).into() };
119 let mut params = Vec::new();
120 let mut body = Block { statements: Vec::new(), span: (0..0).into() };
121
122 for child in node.children() {
123 match child {
124 RedTree::Node(n) => match n.green.kind {
125 ElixirElementType::IdentifierExpression => {
126 name = self.build_identifier(n, source)?;
127 }
128 ElixirElementType::CallExpression => {
129 for grand_child in n.children() {
132 match grand_child {
133 RedTree::Node(gn) => {
134 if let Some(expr) = self.build_expr_opt(gn, source)? {
135 let span = expr_span(&expr);
136 match expr {
137 Expr::Ident(id) if name.name.is_empty() => name = id,
138 _ => params.push(Param {
139 name: match expr {
140 Expr::Ident(id) => id,
141 _ => Identifier { name: "_".to_string(), span: (0..0).into() }, },
143 ty: None,
144 span,
145 }),
146 }
147 }
148 }
149 RedTree::Leaf(gt) if gt.kind == ElixirTokenType::Identifier => {
150 if name.name.is_empty() {
151 name = Identifier { name: text(source, gt.span.clone().into()), span: gt.span.clone().into() };
152 }
153 }
154 _ => {}
155 }
156 }
157 }
158 _ => {
159 if let Some(expr) = self.build_expr_opt(n, source)? {
160 body.statements.push(Statement::ExprStmt { span: expr_span(&expr), expr });
161 }
162 }
163 },
164 RedTree::Leaf(t) if t.kind == ElixirTokenType::Identifier => {
165 if name.name.is_empty() {
166 name = Identifier { name: text(source, t.span.clone().into()), span: t.span.clone().into() };
167 }
168 }
169 _ => {}
170 }
171 }
172
173 body.span = span.into();
174 Ok(Function { name, params, body, span: span.into() })
175 }
176
177 fn build_expr_opt(&self, node: RedNode<ElixirLanguage>, source: &SourceText) -> Result<Option<Expr>, OakError> {
178 match node.green.kind {
179 ElixirElementType::IdentifierExpression => Ok(Some(Expr::Ident(self.build_identifier(node, source)?))),
180 ElixirElementType::LiteralExpression => {
181 for child in node.children() {
182 if let RedTree::Leaf(t) = child {
183 match t.kind {
184 ElixirTokenType::Number | ElixirTokenType::Float => {
185 return Ok(Some(Expr::Number { value: text(source, t.span.clone().into()), span: t.span.clone().into() }));
186 }
187 ElixirTokenType::String => {
188 return Ok(Some(Expr::String { value: text(source, t.span.clone().into()), span: t.span.clone().into() }));
189 }
190 ElixirTokenType::Atom => {
191 return Ok(Some(Expr::Atom { value: text(source, t.span.clone().into()), span: t.span.clone().into() }));
192 }
193 ElixirTokenType::True => {
194 return Ok(Some(Expr::Bool { value: true, span: t.span.clone().into() }));
195 }
196 ElixirTokenType::False => {
197 return Ok(Some(Expr::Bool { value: false, span: t.span.clone().into() }));
198 }
199 _ => {}
200 }
201 }
202 }
203 Ok(None)
204 }
205 ElixirElementType::BinaryExpression => {
206 let mut left = None;
207 let mut op = None;
208 let mut right = None;
209 let span = node.span();
210
211 for child in node.children() {
212 match child {
213 RedTree::Node(n) => {
214 let expr = self.build_expr_opt(n, source)?;
215 if left.is_none() {
216 left = expr;
217 }
218 else {
219 right = expr;
220 }
221 }
222 RedTree::Leaf(t) => {
223 op = Some(t.kind);
224 }
225 }
226 }
227
228 if let (Some(l), Some(o), Some(r)) = (left, op, right) { Ok(Some(Expr::Binary { left: Box::new(l), op: o, right: Box::new(r), span: span.into() })) } else { Ok(None) }
229 }
230 ElixirElementType::MatchExpression => {
231 let mut left = None;
232 let mut right = None;
233 let span = node.span();
234
235 for child in node.children() {
236 if let RedTree::Node(n) = child {
237 let expr = self.build_expr_opt(n, source)?;
238 if left.is_none() {
239 left = expr;
240 }
241 else {
242 right = expr;
243 }
244 }
245 }
246
247 if let (Some(l), Some(r)) = (left, right) { Ok(Some(Expr::Match { left: Box::new(l), right: Box::new(r), span: span.into() })) } else { Ok(None) }
248 }
249 ElixirElementType::UnaryExpression => {
250 let mut op = None;
251 let mut expr = None;
252 let span = node.span();
253
254 for child in node.children() {
255 match child {
256 RedTree::Node(n) => {
257 expr = self.build_expr_opt(n, source)?;
258 }
259 RedTree::Leaf(t) => {
260 op = Some(t.kind);
261 }
262 }
263 }
264
265 if let (Some(o), Some(e)) = (op, expr) {
266 if o == ElixirTokenType::At {
267 if let Expr::Ident(id) = e {
268 return Ok(Some(Expr::Attribute { name: id, span: span.into() }));
269 }
270 }
271 Ok(Some(Expr::Unary { op: o, expr: Box::new(e), span: span.into() }))
272 }
273 else {
274 Ok(None)
275 }
276 }
277 ElixirElementType::CallExpression => {
278 let mut callee = None;
279 let mut args = Vec::new();
280 let span = node.span();
281
282 for child in node.children() {
283 match child {
284 RedTree::Node(n) => {
285 if let Some(expr) = self.build_expr_opt(n, source)? {
286 if callee.is_none() {
287 callee = Some(Box::new(expr));
288 }
289 else {
290 args.push(expr);
291 }
292 }
293 }
294 RedTree::Leaf(t) if t.kind == ElixirTokenType::Identifier => {
295 if callee.is_none() {
296 callee = Some(Box::new(Expr::Ident(Identifier { name: text(source, t.span.clone().into()), span: t.span.clone().into() })));
297 }
298 }
299 _ => {}
300 }
301 }
302
303 if let Some(c) = callee { Ok(Some(Expr::Call { callee: c, args, span: span.into() })) } else { Ok(None) }
304 }
305 ElixirElementType::AccessExpression => {
306 let mut receiver = None;
307 let mut field = None;
308 let span = node.span();
309
310 for child in node.children() {
311 match child {
312 RedTree::Node(n) => {
313 if let Some(expr) = self.build_expr_opt(n, source)? {
314 if receiver.is_none() {
315 receiver = Some(Box::new(expr));
316 }
317 else if let Expr::Ident(id) = expr {
318 field = Some(id);
319 }
320 }
321 }
322 RedTree::Leaf(t) if t.kind == ElixirTokenType::Identifier => {
323 if receiver.is_none() {
324 receiver = Some(Box::new(Expr::Ident(Identifier { name: text(source, t.span.clone().into()), span: t.span.clone().into() })));
325 }
326 else {
327 field = Some(Identifier { name: text(source, t.span.clone().into()), span: t.span.clone().into() });
328 }
329 }
330 _ => {}
331 }
332 }
333
334 if let (Some(r), Some(f)) = (receiver, field) { Ok(Some(Expr::Field { receiver: r, field: f, span: span.into() })) } else { Ok(None) }
335 }
336 ElixirElementType::BlockExpression => {
337 let mut statements = Vec::new();
338 let span = node.span();
339
340 for child in node.children() {
341 if let RedTree::Node(n) = child {
342 if let Some(expr) = self.build_expr_opt(n, source)? {
343 statements.push(Statement::ExprStmt { span: expr_span(&expr), expr });
344 }
345 }
346 }
347 Ok(Some(Expr::Block(Block { statements, span: span.into() })))
348 }
349 ElixirElementType::ListLiteral => {
350 let mut items = Vec::new();
351 let span = node.span();
352 for child in node.children() {
353 if let RedTree::Node(n) = child {
354 if let Some(expr) = self.build_expr_opt(n, source)? {
355 items.push(expr);
356 }
357 }
358 }
359 Ok(Some(Expr::List { items, span: span.into() }))
360 }
361 ElixirElementType::TupleLiteral => {
362 let mut items = Vec::new();
363 let span = node.span();
364 for child in node.children() {
365 if let RedTree::Node(n) = child {
366 if let Some(expr) = self.build_expr_opt(n, source)? {
367 items.push(expr);
368 }
369 }
370 }
371 Ok(Some(Expr::Tuple { items, span: span.into() }))
372 }
373 _ => Ok(None),
374 }
375 }
376
377 fn build_identifier(&self, node: RedNode<ElixirLanguage>, source: &SourceText) -> Result<Identifier, OakError> {
378 let span = node.span();
379 for child in node.children() {
380 if let RedTree::Leaf(t) = child {
381 if t.kind == ElixirTokenType::Identifier {
382 return Ok(Identifier { name: text(source, t.span.clone().into()), span: t.span.clone().into() });
383 }
384 }
385 }
386 Ok(Identifier { name: String::new(), span: span.into() })
387 }
388}
389
390fn text(source: &SourceText, span: Range<usize>) -> String {
391 source.get_text_in(span).into_owned()
392}
393
394fn expr_span(expr: &Expr) -> Range<usize> {
395 match expr {
396 Expr::Ident(id) => id.span.clone(),
397 Expr::Atom { span, .. } => span.clone(),
398 Expr::Number { span, .. } => span.clone(),
399 Expr::String { span, .. } => span.clone(),
400 Expr::Bool { span, .. } => span.clone(),
401 Expr::Unary { span, .. } => span.clone(),
402 Expr::Binary { span, .. } => span.clone(),
403 Expr::Match { span, .. } => span.clone(),
404 Expr::Call { span, .. } => span.clone(),
405 Expr::Field { span, .. } => span.clone(),
406 Expr::Attribute { span, .. } => span.clone(),
407 Expr::Index { span, .. } => span.clone(),
408 Expr::Paren { span, .. } => span.clone(),
409 Expr::List { span, .. } => span.clone(),
410 Expr::Tuple { span, .. } => span.clone(),
411 Expr::Map { span, .. } => span.clone(),
412 Expr::Block(b) => b.span.clone(),
413 }
414}