1#![doc = include_str!("readme.md")]
2use crate::{
3 ast::*,
4 language::ZigLanguage,
5 parser::{ZigParser, element_type::ZigElementType},
6};
7use oak_core::{Builder, BuilderCache, GreenNode, OakDiagnostics, Parser, RedNode, RedTree, SourceText, TextEdit, source::Source};
8use std::sync::Arc;
9
10#[derive(Clone)]
12pub struct ZigBuilder<'config> {
13 config: &'config ZigLanguage,
15}
16
17impl<'config> ZigBuilder<'config> {
18 pub fn new(config: &'config ZigLanguage) -> Self {
20 Self { config }
21 }
22
23 pub fn build_root(&self, green: &GreenNode<ZigLanguage>, source: &SourceText) -> Result<ZigRoot, oak_core::OakError> {
25 let mut items = Vec::new();
26 let red = RedNode::new(green, 0);
27
28 for child in red.children() {
29 if let RedTree::Node(n) = child {
30 match n.green.kind {
31 ZigElementType::Comptime => {
32 let mut is_block = false;
35 for child in n.children() {
36 if let RedTree::Node(cn) = child {
37 if cn.green.kind == ZigElementType::Block {
38 items.push(Item::Comptime(self.build_block(cn, source)?));
39 is_block = true;
40 break;
41 }
42 }
43 }
44 if !is_block {
45 }
49 }
50 ZigElementType::Var | ZigElementType::Const => {
51 let decl = self.build_declaration(n, source)?;
52 items.push(Item::Declaration(decl));
53 }
54 ZigElementType::ContainerField => {
55 let field = self.build_container_field(n, source)?;
56 items.push(Item::ContainerField(field));
57 }
58 _ => {}
59 }
60 }
61 }
62
63 Ok(ZigRoot { items })
64 }
65
66 fn build_block(&self, node: RedNode<ZigLanguage>, source: &SourceText) -> Result<Arc<Block>, oak_core::OakError> {
67 let mut statements = Vec::new();
68
69 for child in node.children() {
70 if let RedTree::Node(n) = child {
71 let stmt = self.build_statement(n, source)?;
72 statements.push(stmt);
73 }
74 }
75
76 Ok(Arc::new(Block { statements, span: node.span().into() }))
77 }
78
79 fn build_statement(&self, node: RedNode<ZigLanguage>, source: &SourceText) -> Result<Statement, oak_core::OakError> {
80 let kind = node.green.kind;
81 match kind {
82 ZigElementType::Block => Ok(Statement::Block(self.build_block(node, source)?)),
83 ZigElementType::IfStatement => {
84 Ok(Statement::Expression(Expression::Identifier("if".to_string())))
86 }
87 ZigElementType::WhileStatement => {
88 Ok(Statement::Expression(Expression::Identifier("while".to_string())))
90 }
91 ZigElementType::ForStatement => {
92 Ok(Statement::Expression(Expression::Identifier("for".to_string())))
94 }
95 ZigElementType::ReturnStatement => {
96 Ok(Statement::Expression(Expression::Identifier("return".to_string())))
98 }
99 ZigElementType::BreakStatement => {
100 Ok(Statement::Expression(Expression::Identifier("break".to_string())))
102 }
103 ZigElementType::ContinueStatement => {
104 Ok(Statement::Expression(Expression::Identifier("continue".to_string())))
106 }
107 ZigElementType::DeferStatement => {
108 Ok(Statement::Expression(Expression::Identifier("defer".to_string())))
110 }
111 ZigElementType::Comptime => {
112 for child in node.children() {
114 if let RedTree::Node(n) = child {
115 if n.green.kind == ZigElementType::Block {
116 return Ok(Statement::Comptime(self.build_block(n, source)?));
117 }
118 }
119 }
120 Ok(Statement::Expression(Expression::Identifier("comptime_expr".to_string())))
122 }
123 ZigElementType::Var | ZigElementType::Const => {
124 let decl = self.build_declaration(node, source)?;
125 Ok(Statement::Declaration(decl))
126 }
127 _ => {
128 Ok(Statement::Expression(Expression::Identifier("stmt".to_string())))
130 }
131 }
132 }
133
134 fn build_declaration(&self, node: RedNode<ZigLanguage>, _source: &SourceText) -> Result<Arc<Declaration>, oak_core::OakError> {
135 let span = node.span();
136 let decl = Arc::new(Declaration { name: "decl".to_string(), is_comptime: false, span: span.into() });
137 Ok(decl)
138 }
139
140 fn build_container_field(&self, node: RedNode<ZigLanguage>, _source: &SourceText) -> Result<Arc<ContainerField>, oak_core::OakError> {
141 let span = node.span();
142 let field = Arc::new(ContainerField { name: "field".to_string(), span: span.into() });
143 Ok(field)
144 }
145}
146
147impl<'config> Builder<ZigLanguage> for ZigBuilder<'config> {
148 fn build<'a, S: Source + ?Sized>(&self, source: &'a S, edits: &[TextEdit], cache: &'a mut impl BuilderCache<ZigLanguage>) -> oak_core::builder::BuildOutput<ZigLanguage> {
149 let parser = ZigParser::new(self.config);
150 let parse_result = parser.parse(source, edits, 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(parse_error) => OakDiagnostics { result: Err(parse_error), diagnostics: parse_result.diagnostics },
165 }
166 }
167}