1use crate::{
4 ast::*,
5 language::MsilLanguage,
6 parser::{MsilParser, element_type::MsilElementType},
7};
8use oak_core::{Builder, BuilderCache, GreenNode, OakDiagnostics, Source, SourceText, TextEdit};
9
10#[derive(Clone)]
12pub struct MsilBuilder<'config> {
13 #[allow(dead_code)]
14 config: &'config MsilLanguage,
15}
16
17impl<'config> MsilBuilder<'config> {
18 pub fn new(config: &'config MsilLanguage) -> Self {
20 Self { config }
21 }
22
23 pub fn build_root(&self, green_tree: &GreenNode<MsilLanguage>, source: &SourceText) -> Result<MsilRoot, oak_core::OakError> {
25 let red_root = oak_core::RedNode::new(green_tree, 0);
26
27 let mut items = Vec::new();
28 for child in red_root.children() {
29 if let oak_core::RedTree::Node(node) = child {
30 if let Some(item) = self.build_item(&node, source) {
31 items.push(item)
32 }
33 }
34 }
35
36 Ok(MsilRoot { items })
37 }
38
39 fn build_item(&self, node: &oak_core::RedNode<MsilLanguage>, source: &SourceText) -> Option<Item> {
40 let kind = node.green.kind;
41 match kind {
42 MsilElementType::Assembly => {
43 let mut name = "unknown".to_string();
44 for child in node.children() {
45 if let oak_core::RedTree::Node(n) = child {
46 if n.green.kind == MsilElementType::Identifier {
47 name = source.get_text_in(n.span()).to_string();
48 break;
49 }
50 }
51 }
52 Some(Item::Assembly(crate::ast::Assembly { name, span: node.span() }))
53 }
54 MsilElementType::AssemblyExtern => {
55 let mut name = "unknown".to_string();
56 for child in node.children() {
57 if let oak_core::RedTree::Node(n) = child {
58 if n.green.kind == MsilElementType::Identifier {
59 name = source.get_text_in(n.span()).to_string();
60 break;
61 }
62 }
63 }
64 Some(Item::AssemblyExtern(name))
65 }
66 MsilElementType::Module => {
67 let mut name = "unknown".to_string();
68 for child in node.children() {
69 if let oak_core::RedTree::Node(n) = child {
70 if n.green.kind == MsilElementType::Identifier {
71 name = source.get_text_in(n.span()).to_string();
72 break;
73 }
74 }
75 }
76 Some(Item::Module(name))
77 }
78 MsilElementType::Class => {
79 let mut name = "Unknown".to_string();
80 let mut methods = Vec::new();
81 for child in node.children() {
82 if let oak_core::RedTree::Node(n) = child {
83 if n.green.kind == MsilElementType::Identifier {
84 name = source.get_text_in(n.span()).to_string()
85 }
86 else if n.green.kind == MsilElementType::Method {
87 if let Some(method) = self.build_method(&n, source) {
88 methods.push(method)
89 }
90 }
91 }
92 }
93 Some(Item::Class(crate::ast::Class { name, methods, span: node.span() }))
94 }
95 _ => None,
96 }
97 }
98
99 fn build_method(&self, node: &oak_core::RedNode<MsilLanguage>, source: &SourceText) -> Option<crate::ast::Method> {
100 let mut name = "Unknown".to_string();
101 let mut instructions = Vec::new();
102 for child in node.children() {
103 if let oak_core::RedTree::Node(n) = child {
104 if n.green.kind == MsilElementType::Identifier {
105 name = source.get_text_in(n.span()).to_string();
106 }
107 else if n.green.kind == MsilElementType::Instruction {
108 if let Some(inst) = self.build_instruction(&n, source) {
109 instructions.push(inst);
110 }
111 }
112 }
113 }
114
115 Some(crate::ast::Method { name, instructions, span: node.span() })
116 }
117
118 fn build_instruction(&self, node: &oak_core::RedNode<MsilLanguage>, source: &SourceText) -> Option<Instruction> {
119 let mut opcode = String::new();
120 let mut operand = None;
121
122 for child in node.children() {
123 if let oak_core::RedTree::Node(n) = child {
124 match n.green.kind {
125 MsilElementType::Identifier => {
126 if opcode.is_empty() {
127 opcode = source.get_text_in(n.span()).to_string();
128 }
129 else {
130 operand = Some(source.get_text_in(n.span()).to_string());
131 }
132 }
133 MsilElementType::String => {
134 operand = Some(source.get_text_in(n.span()).to_string());
135 }
136 _ => {}
137 }
138 }
139 }
140
141 if opcode == "ldstr" {
142 Some(Instruction::String(operand.unwrap_or_default()))
143 }
144 else if opcode == "call" {
145 Some(Instruction::Call(operand.unwrap_or_default()))
146 }
147 else if !opcode.is_empty() {
148 Some(Instruction::Simple(opcode))
149 }
150 else {
151 None
152 }
153 }
154}
155
156impl<'config> Builder<MsilLanguage> for MsilBuilder<'config> {
157 fn build<'a, S: Source + ?Sized>(&self, source: &S, edits: &[TextEdit], _cache: &'a mut impl BuilderCache<MsilLanguage>) -> OakDiagnostics<MsilRoot> {
158 let parser = MsilParser::new(self.config);
159 let lexer = crate::lexer::MsilLexer::new(&self.config);
160
161 let mut cache = oak_core::parser::session::ParseSession::<MsilLanguage>::default();
162 let parse_result = oak_core::parser::parse(&parser, &lexer, source, edits, &mut cache);
163
164 match parse_result.result {
165 Ok(green_tree) => {
166 let source_text = SourceText::new(source.get_text_in((0..source.length()).into()).into_owned());
167 OakDiagnostics { result: self.build_root(green_tree, &source_text), diagnostics: parse_result.diagnostics }
168 }
169 Err(parse_error) => OakDiagnostics { result: Err(parse_error), diagnostics: parse_result.diagnostics },
170 }
171 }
172}