1#![doc = include_str!("readme.md")]
2use crate::{ast::*, language::GsglLanguage, lexer::token_type::GsglTokenType, parser::element_type::GsglElementType};
3use oak_core::{Builder, BuilderCache, OakDiagnostics, OakError, Parser, RedNode, RedTree, Source, SourceText, TextEdit, builder::BuildOutput};
4
5pub struct GsglBuilder {}
7
8impl GsglBuilder {
9 pub fn new(_lang: &GsglLanguage) -> Self {
11 Self {}
12 }
13
14 fn build_type(&self, node: RedNode<GsglLanguage>, source: &SourceText) -> Result<GsglType, OakError> {
15 let mut name = String::new();
16 for child in node.children() {
17 if let RedTree::Leaf(t) = child {
18 if t.kind == GsglTokenType::Identifier || (t.kind as u8 >= 84 && t.kind as u8 <= 107) {
19 name = source.get_text_in(t.span.clone().into()).to_string();
20 break;
21 }
22 }
23 }
24 Ok(GsglType { name })
25 }
26
27 fn build_param(&self, node: RedNode<GsglLanguage>, source: &SourceText) -> Result<GsglParam, OakError> {
28 let mut name = String::new();
29 let mut ty = GsglType { name: String::new() };
30 for child in node.children() {
31 if let RedTree::Leaf(t) = child {
32 if t.kind == GsglTokenType::Identifier {
33 if name.is_empty() {
34 name = source.get_text_in(t.span.clone().into()).to_string();
35 }
36 }
37 else if t.kind as u8 >= 84 && t.kind as u8 <= 107 {
38 ty = GsglType { name: source.get_text_in(t.span.clone().into()).to_string() };
39 }
40 }
41 }
42 Ok(GsglParam { name, ty })
43 }
44
45 fn build_function(&self, node: RedNode<GsglLanguage>, source: &SourceText) -> Result<GsglFunction, OakError> {
46 let mut name = String::new();
47 let mut return_type = GsglType { name: String::new() };
48 let mut params = Vec::new();
49
50 for child in node.children() {
51 match child {
52 RedTree::Leaf(t) => {
53 if t.kind == GsglTokenType::Identifier {
54 if return_type.name.is_empty() {
55 return_type.name = source.get_text_in(t.span.clone().into()).to_string();
56 }
57 else if name.is_empty() {
58 name = source.get_text_in(t.span.clone().into()).to_string();
59 }
60 }
61 else if t.kind as u8 >= 84 && t.kind as u8 <= 107 {
62 return_type.name = source.get_text_in(t.span.clone().into()).to_string();
63 }
64 }
65 RedTree::Node(n) => {
66 if n.kind::<GsglElementType>() == GsglElementType::Parameter {
67 params.push(self.build_param(n, source)?);
68 }
69 }
70 }
71 }
72
73 Ok(GsglFunction { name, return_type, params })
74 }
75
76 fn build_struct_member(&self, node: RedNode<GsglLanguage>, source: &SourceText) -> Result<GsglStructMember, OakError> {
77 let mut name = String::new();
78 let mut ty = GsglType { name: String::new() };
79 for child in node.children() {
80 if let RedTree::Leaf(t) = child {
81 if t.kind == GsglTokenType::Identifier {
82 if ty.name.is_empty() {
83 ty.name = source.get_text_in(t.span.clone().into()).to_string();
84 }
85 else if name.is_empty() {
86 name = source.get_text_in(t.span.clone().into()).to_string();
87 }
88 }
89 else if t.kind as u8 >= 84 && t.kind as u8 <= 107 {
90 ty.name = source.get_text_in(t.span.clone().into()).to_string();
91 }
92 }
93 }
94 Ok(GsglStructMember { name, ty })
95 }
96
97 fn build_struct(&self, node: RedNode<GsglLanguage>, source: &SourceText) -> Result<GsglStruct, OakError> {
98 let mut name = String::new();
99 let mut members = Vec::new();
100
101 for child in node.children() {
102 match child {
103 RedTree::Leaf(t) => {
104 if t.kind == GsglTokenType::Identifier && name.is_empty() {
105 name = source.get_text_in(t.span.clone().into()).to_string();
106 }
107 }
108 RedTree::Node(n) => {
109 if n.kind::<GsglElementType>() == GsglElementType::VariableDecl {
110 members.push(self.build_struct_member(n, source)?);
111 }
112 }
113 }
114 }
115
116 Ok(GsglStruct { name, members })
117 }
118}
119
120impl Builder<GsglLanguage> for GsglBuilder {
121 fn build<'a, S: Source + ?Sized>(&self, text: &S, edits: &[TextEdit], cache: &'a mut impl BuilderCache<GsglLanguage>) -> BuildOutput<GsglLanguage> {
122 let source = SourceText::new(text.get_text_from(0).as_ref());
123 let mut functions = Vec::new();
124 let mut structs = Vec::new();
125
126 let parse_output = crate::parser::GsglParser::new(GsglLanguage::default()).parse(text, edits, cache);
127 let root = RedNode::new(parse_output.green(), 0);
128
129 let result = (|| {
130 for child in root.children() {
131 if let RedTree::Node(n) = child {
132 match n.kind() {
133 GsglElementType::FunctionDecl => {
134 functions.push(self.build_function(n, &source)?);
135 }
136 GsglElementType::StructDecl => {
137 structs.push(self.build_struct(n, &source)?);
138 }
139 _ => {}
140 }
141 }
142 }
143 Ok(GsglRoot { functions, structs })
144 })();
145
146 match result {
147 Ok(root) => OakDiagnostics::success(root),
148 Err(e) => OakDiagnostics::error(e),
149 }
150 }
151}