Skip to main content

oak_gsgl/builder/
mod.rs

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
5/// Builder for the GSGL language.
6pub struct GsglBuilder {}
7
8impl GsglBuilder {
9    /// Creates a new `GsglBuilder`.
10    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}