Skip to main content

oak_msil/builder/
mod.rs

1use crate::{
2    ast::*,
3    language::MsilLanguage,
4    parser::{MsilParser, element_type::MsilElementType},
5};
6use oak_core::{Builder, BuilderCache, GreenNode, OakDiagnostics, Source, SourceText, TextEdit};
7
8#[derive(Clone)]
9pub struct MsilBuilder<'config> {
10    #[allow(dead_code)]
11    config: &'config MsilLanguage,
12}
13
14impl<'config> MsilBuilder<'config> {
15    pub fn new(config: &'config MsilLanguage) -> Self {
16        Self { config }
17    }
18
19    fn build_root(&self, green_tree: &GreenNode<MsilLanguage>, source: &SourceText) -> Result<MsilRoot, oak_core::OakError> {
20        let red_root = oak_core::RedNode::new(green_tree, 0);
21
22        let mut items = Vec::new();
23        for child in red_root.children() {
24            if let oak_core::RedTree::Node(node) = child {
25                if let Some(item) = self.build_item(&node, source) {
26                    items.push(item)
27                }
28            }
29        }
30
31        Ok(MsilRoot { items })
32    }
33
34    fn build_item(&self, node: &oak_core::RedNode<MsilLanguage>, source: &SourceText) -> Option<Item> {
35        let kind = node.green.kind;
36        match kind {
37            MsilElementType::Assembly => {
38                let mut name = "unknown".to_string();
39                for child in node.children() {
40                    if let oak_core::RedTree::Node(n) = child {
41                        if n.green.kind == MsilElementType::Identifier {
42                            name = source.get_text_in(n.span()).to_string();
43                            break;
44                        }
45                    }
46                }
47                Some(Item::Assembly(crate::ast::Assembly { name, span: node.span() }))
48            }
49            MsilElementType::AssemblyExtern => {
50                let mut name = "unknown".to_string();
51                for child in node.children() {
52                    if let oak_core::RedTree::Node(n) = child {
53                        if n.green.kind == MsilElementType::Identifier {
54                            name = source.get_text_in(n.span()).to_string();
55                            break;
56                        }
57                    }
58                }
59                Some(Item::AssemblyExtern(name))
60            }
61            MsilElementType::Module => {
62                let mut name = "unknown".to_string();
63                for child in node.children() {
64                    if let oak_core::RedTree::Node(n) = child {
65                        if n.green.kind == MsilElementType::Identifier {
66                            name = source.get_text_in(n.span()).to_string();
67                            break;
68                        }
69                    }
70                }
71                Some(Item::Module(name))
72            }
73            MsilElementType::Class => {
74                let mut name = "Unknown".to_string();
75                let mut methods = Vec::new();
76                for child in node.children() {
77                    if let oak_core::RedTree::Node(n) = child {
78                        if n.green.kind == MsilElementType::Identifier {
79                            name = source.get_text_in(n.span()).to_string()
80                        }
81                        else if n.green.kind == MsilElementType::Method {
82                            if let Some(method) = self.build_method(&n, source) {
83                                methods.push(method)
84                            }
85                        }
86                    }
87                }
88                Some(Item::Class(crate::ast::Class { name, methods, span: node.span() }))
89            }
90            _ => None,
91        }
92    }
93
94    fn build_method(&self, node: &oak_core::RedNode<MsilLanguage>, source: &SourceText) -> Option<crate::ast::Method> {
95        let mut name = "Unknown".to_string();
96        for child in node.children() {
97            if let oak_core::RedTree::Node(n) = child {
98                if n.green.kind == MsilElementType::Identifier {
99                    name = source.get_text_in(n.span()).to_string();
100                    break;
101                }
102            }
103        }
104
105        Some(crate::ast::Method {
106            name,
107            instructions: Vec::new(), // TODO: Parse instructions
108            span: node.span(),
109        })
110    }
111}
112
113impl<'config> Builder<MsilLanguage> for MsilBuilder<'config> {
114    fn build<'a, S: Source + ?Sized>(&self, source: &S, edits: &[TextEdit], _cache: &'a mut impl BuilderCache<MsilLanguage>) -> OakDiagnostics<MsilRoot> {
115        let parser = MsilParser::new(self.config);
116        let lexer = crate::lexer::MsilLexer::new(&self.config);
117
118        let mut cache = oak_core::parser::session::ParseSession::<MsilLanguage>::default();
119        let parse_result = oak_core::parser::parse(&parser, &lexer, source, edits, &mut cache);
120
121        match parse_result.result {
122            Ok(green_tree) => {
123                let source_text = SourceText::new(source.get_text_in((0..source.length()).into()).into_owned());
124                OakDiagnostics { result: self.build_root(green_tree, &source_text), diagnostics: parse_result.diagnostics }
125            }
126            Err(parse_error) => OakDiagnostics { result: Err(parse_error), diagnostics: parse_result.diagnostics },
127        }
128    }
129}