1use crate::{
2 RParser,
3 ast::{Expr, Identifier, RRoot, Statement},
4 language::RLanguage,
5 lexer::token_type::RTokenType,
6 parser::element_type::RElementType,
7};
8use oak_core::{Builder, BuilderCache, GreenNode, GreenTree, OakDiagnostics, OakError, Parser, SourceText, TextEdit, builder::BuildOutput, source::Source};
9
10#[derive(Clone)]
11pub struct RBuilder<'config> {
12 config: &'config RLanguage,
13}
14
15impl<'config> RBuilder<'config> {
16 pub fn new(config: &'config RLanguage) -> Self {
17 Self { config }
18 }
19
20 pub fn build_root(&self, green_tree: &GreenNode<RLanguage>, source: &SourceText) -> Result<RRoot, OakError> {
21 let mut statements = Vec::new();
22 let mut current_offset = 0;
23
24 for child in green_tree.children() {
25 let child_len = child.len() as usize;
26 if let GreenTree::Node(node) = child {
27 if !node.kind.is_trivia() {
28 if let Some(stmt) = self.build_statement(node, current_offset, source)? {
29 statements.push(stmt);
30 }
31 }
32 }
33 current_offset += child_len;
34 }
35
36 Ok(RRoot { statements })
37 }
38
39 fn build_statement(&self, node: &GreenNode<RLanguage>, offset: usize, source: &SourceText) -> Result<Option<Statement>, OakError> {
40 match node.kind {
41 RElementType::Assignment => {
42 let mut name = None;
43 let mut expr = None;
44 let mut current_offset = offset;
45
46 for child in node.children() {
47 let child_len = child.len() as usize;
48 match child {
49 GreenTree::Node(sub_node) => {
50 if sub_node.kind == RElementType::Identifier {
51 name = Some(Identifier { name: source.get_text_in((current_offset..current_offset + child_len).into()).to_string(), span: (current_offset..current_offset + child_len).into() });
52 }
53 else if sub_node.kind == RElementType::LiteralExpression || sub_node.kind == RElementType::IdentifierExpression || sub_node.kind == RElementType::CallExpression {
54 expr = Some(self.build_expression(sub_node, current_offset, source)?)
55 }
56 }
57 _ => {}
58 }
59 current_offset += child_len
60 }
61
62 if let (Some(n), Some(e)) = (name, expr) { Ok(Some(Statement::Assignment { name: n, expr: e, span: (offset..current_offset).into() })) } else { Ok(None) }
63 }
64 RElementType::Function => {
65 let name = Identifier { name: "anonymous".to_string(), span: (offset..offset).into() };
66 let mut params = Vec::new();
67 let mut body = Vec::new();
68 let mut current_offset = offset;
69
70 for child in node.children() {
71 let child_len = child.len() as usize;
72 if let GreenTree::Node(sub_node) = child {
73 match sub_node.kind {
74 RElementType::Identifier => params.push(Identifier { name: source.get_text_in((current_offset..current_offset + child_len).into()).to_string(), span: (current_offset..current_offset + child_len).into() }),
75 RElementType::BlockExpression => {
76 let mut block_offset = current_offset;
77 for block_child in sub_node.children() {
78 let block_child_len = block_child.len() as usize;
79 if let GreenTree::Node(stmt_node) = block_child {
80 if let Some(s) = self.build_statement(stmt_node, block_offset, source)? {
81 body.push(s)
82 }
83 }
84 block_offset += block_child_len
85 }
86 }
87 _ => {}
88 }
89 }
90 current_offset += child_len
91 }
92
93 Ok(Some(Statement::FunctionDef { name, params, body, span: (offset..current_offset).into() }))
94 }
95 _ => {
96 if let Ok(expr) = self.build_expression(node, offset, source) {
97 Ok(Some(Statement::ExprStmt { expr, span: (offset..offset + node.text_len() as usize).into() }))
98 }
99 else {
100 Ok(None)
101 }
102 }
103 }
104 }
105
106 fn build_expression(&self, node: &GreenNode<RLanguage>, offset: usize, source: &SourceText) -> Result<Expr, OakError> {
107 match node.kind {
108 RElementType::IdentifierExpression | RElementType::Identifier => Ok(Expr::Ident(Identifier { name: source.get_text_in((offset..offset + node.text_len() as usize).into()).to_string(), span: (offset..offset + node.text_len() as usize).into() })),
109 RElementType::LiteralExpression => {
110 let text = source.get_text_in((offset..offset + node.text_len() as usize).into()).to_string();
111 if text == "TRUE" || text == "FALSE" {
112 Ok(Expr::Bool { value: text == "TRUE", span: (offset..offset + node.text_len() as usize).into() })
113 }
114 else if text == "NULL" {
115 Ok(Expr::Null { span: (offset..offset + node.text_len() as usize).into() })
116 }
117 else {
118 Ok(Expr::Literal { value: text, span: (offset..offset + node.text_len() as usize).into() })
119 }
120 }
121 RElementType::CallExpression => {
122 let mut callee = None;
123 let mut args = Vec::new();
124 let mut current_offset = offset;
125
126 for child in node.children() {
127 let child_len = child.len() as usize;
128 if let GreenTree::Node(sub_node) = child {
129 if callee.is_none() && (sub_node.kind == RElementType::Identifier || sub_node.kind == RElementType::IdentifierExpression) {
130 callee = Some(Box::new(self.build_expression(sub_node, current_offset, source)?))
131 }
132 else if sub_node.kind != RElementType::LeftParen && sub_node.kind != RElementType::RightParen && sub_node.kind != RElementType::Comma && !sub_node.kind.is_trivia() {
133 args.push(self.build_expression(sub_node, current_offset, source)?)
134 }
135 }
136 current_offset += child_len
137 }
138
139 if let Some(c) = callee { Ok(Expr::Call { callee: c, args, span: (offset..offset + node.text_len() as usize).into() }) } else { Err(OakError::custom_error(format!("Unexpected token at offset {}", offset))) }
140 }
141 _ => Err(OakError::custom_error(format!("Unexpected token at offset {}", offset))),
142 }
143 }
144}
145
146impl<'config> Builder<RLanguage> for RBuilder<'config> {
147 fn build<'a, S: Source + ?Sized>(&self, source: &S, edits: &[TextEdit], _cache: &'a mut impl BuilderCache<RLanguage>) -> BuildOutput<RLanguage> {
148 let parser = RParser::new(self.config);
149 let mut parse_cache = oak_core::parser::session::ParseSession::<RLanguage>::default();
150 let parse_result = parser.parse(source, edits, &mut parse_cache);
151
152 match parse_result.result {
153 Ok(green_tree) => {
154 let source_text = SourceText::new(source.get_text_in((0..source.length()).into()).into_owned());
155 match self.build_root(green_tree, &source_text) {
156 Ok(ast_root) => OakDiagnostics { result: Ok(ast_root), diagnostics: parse_result.diagnostics },
157 Err(build_error) => {
158 let mut diagnostics = parse_result.diagnostics;
159 diagnostics.push(build_error.clone());
160 OakDiagnostics { result: Err(build_error), diagnostics }
161 }
162 }
163 }
164 Err(e) => OakDiagnostics { result: Err(e), diagnostics: parse_result.diagnostics },
165 }
166 }
167}