gaia_assembler/backends/dotnet/
msil.rs1#[cfg(feature = "clr-assembler")]
4use crate::{
5 adapters::FunctionMapper,
6 config::{GaiaConfig, GaiaSettings},
7 instruction::{CmpCondition, CoreInstruction, GaiaInstruction},
8 program::{GaiaConstant, GaiaFunction, GaiaModule},
9 types::GaiaType,
10 Backend, GeneratedFiles,
11};
12#[cfg(feature = "clr-assembler")]
13use clr_assembler::program::*;
14#[cfg(feature = "clr-assembler")]
15use gaia_types::{
16 helpers::{AbiCompatible, ApiCompatible, Architecture, ArtifactType, CompilationTarget},
17 GaiaError, Result,
18};
19#[cfg(feature = "clr-assembler")]
20use std::collections::HashMap;
21
22#[derive(Default)]
24#[cfg(feature = "clr-assembler")]
25pub struct ClrBackend {}
26
27#[cfg(feature = "clr-assembler")]
28impl ClrBackend {
29 pub fn generate_with_settings(program: &GaiaModule, settings: &GaiaSettings) -> Result<Vec<u8>> {
31 let clr_program = convert_to_clr_program(program, Some(settings))?;
32 let buffer = std::io::Cursor::new(Vec::new());
33 let writer = clr_assembler::formats::dll::writer::DllWriter::new(buffer);
34 let result = writer.write(&clr_program);
35 if let Some(error) = result.diagnostics.into_iter().next() {
36 return Err(error);
37 }
38 Ok(result.result.expect("Failed to get DLL buffer").into_inner())
39 }
40}
41
42#[cfg(feature = "clr-assembler")]
43impl Backend for ClrBackend {
44 fn name(&self) -> &'static str {
45 "MSIL"
46 }
47
48 fn primary_target(&self) -> CompilationTarget {
49 CompilationTarget {
50 build: Architecture::CLR,
51 host: AbiCompatible::MicrosoftIntermediateLanguage,
52 target: ApiCompatible::ClrRuntime(4),
53 }
54 }
55
56 fn artifact_type(&self) -> ArtifactType {
57 ArtifactType::Bytecode
58 }
59
60 fn match_score(&self, target: &CompilationTarget) -> f32 {
61 match target.build {
62 Architecture::CLR => match target.host {
63 AbiCompatible::Unknown => 30.0,
64 AbiCompatible::MicrosoftIntermediateLanguage => 30.0,
65 _ => -100.0,
66 },
67 _ => -100.0,
68 }
69 }
70
71 fn generate(&self, program: &GaiaModule, _config: &GaiaConfig) -> Result<GeneratedFiles> {
72 let clr_program = convert_to_clr_program(program, Some(&_config.setting))?;
73 let mut files = HashMap::new();
74
75 match _config.target.host {
76 AbiCompatible::Unknown => {
77 let buffer = std::io::Cursor::new(Vec::new());
78 let writer = clr_assembler::formats::dll::writer::DllWriter::new(buffer);
79 let result = writer.write(&clr_program);
80 if let Some(error) = result.diagnostics.into_iter().next() {
81 return Err(error);
82 }
83 files.insert("main.dll".to_string(), result.result.expect("Failed to get DLL buffer").into_inner());
84 }
85 AbiCompatible::MicrosoftIntermediateLanguage => {
86 let source = clr_assembler::formats::msil::program_to_source(&clr_program);
87 files.insert("main.il".to_string(), source.into_bytes());
88 }
89 _ => Err(GaiaError::invalid_data("Unsupported host ABI for CLR backend"))?,
90 }
91
92 Ok(GeneratedFiles { artifact_type: ArtifactType::Bytecode, files, diagnostics: vec![] })
93 }
94}
95
96#[cfg(feature = "clr-assembler")]
97struct IlContext {
98 builder: ClrBuilder,
99 function_mapper: FunctionMapper,
100 #[allow(dead_code)]
101 field_types: HashMap<(String, String), GaiaType>,
102}
103
104#[cfg(feature = "clr-assembler")]
105impl IlContext {
106 fn new(name: String) -> Self {
107 Self { builder: ClrBuilder::new(name), function_mapper: FunctionMapper::new(), field_types: HashMap::new() }
108 }
109
110 fn map_function(&self, raw_name: &str) -> String {
111 let il_target = CompilationTarget {
112 build: Architecture::CLR,
113 host: AbiCompatible::MicrosoftIntermediateLanguage,
114 target: ApiCompatible::ClrRuntime(4),
115 };
116 self.function_mapper.map_function(&il_target, raw_name).unwrap_or(raw_name).to_string()
117 }
118}
119
120#[cfg(feature = "clr-assembler")]
121fn convert_to_clr_program(program: &GaiaModule, settings: Option<&GaiaSettings>) -> Result<ClrProgram> {
122 let mut context = IlContext::new(program.name.clone());
123 if let Some(s) = settings {
124 context.function_mapper = FunctionMapper::from_config(s).unwrap_or_default();
125 }
126
127 for import in &program.imports {
129 context.builder.add_external_assembly(import.library.clone());
130 }
131
132 for s in &program.structs {
134 context.builder.begin_class(s.name.clone(), None);
135 for (name, ty) in &s.fields {
136 context.field_types.insert((s.name.clone(), name.clone()), ty.clone());
138 }
139 }
141
142 for function in &program.functions {
144 let _is_entry = function.name == "main";
145 let ret_type = gaia_type_to_clr_type(&function.signature.return_type);
146
147 context.builder.begin_method(function.name.clone(), ret_type);
148 for block in &function.blocks {
151 for instruction in &block.instructions {
152 compile_instruction(&mut context, instruction)?;
153 }
154
155 match &block.terminator {
156 crate::program::GaiaTerminator::Return => {
157 context.builder.emit(ClrOpcode::Ret, None);
158 }
159 crate::program::GaiaTerminator::Call { callee, .. } => {
160 let mapped = context.map_function(callee);
161 context.builder.emit(
162 ClrOpcode::Call,
163 Some(ClrInstructionOperand::Method(
164 mapped,
165 None,
166 vec![],
167 Box::new(ClrTypeReference::Primitive("void".to_string())),
168 )),
169 );
170 }
171 _ => {} }
173 }
174 }
175
176 Ok(context.builder.finish())
177}
178
179#[cfg(feature = "clr-assembler")]
180fn compile_instruction(context: &mut IlContext, instruction: &GaiaInstruction) -> Result<()> {
181 match instruction {
182 GaiaInstruction::Core(core) => match core {
183 CoreInstruction::PushConstant(constant) => match constant {
184 GaiaConstant::I32(v) => context.builder.emit(ClrOpcode::LdcI4, Some(ClrInstructionOperand::Int32(*v))),
185 GaiaConstant::String(s) => {
186 context.builder.emit(ClrOpcode::Ldstr, Some(ClrInstructionOperand::String(s.clone())))
187 }
188 _ => {}
189 },
190 CoreInstruction::Add(_) => context.builder.emit(ClrOpcode::Add, None),
191 CoreInstruction::Sub(_) => context.builder.emit(ClrOpcode::Sub, None),
192 CoreInstruction::Mul(_) => context.builder.emit(ClrOpcode::Mul, None),
193 CoreInstruction::Div(_) => context.builder.emit(ClrOpcode::Div, None),
194 _ => {}
195 },
196 _ => {}
197 }
198 Ok(())
199}
200
201#[cfg(feature = "clr-assembler")]
202fn gaia_type_to_clr_type(t: &GaiaType) -> ClrTypeReference {
203 match t {
204 GaiaType::I32 => ClrTypeReference::Primitive("int32".to_string()),
205 GaiaType::String => ClrTypeReference::Primitive("string".to_string()),
206 GaiaType::Void => ClrTypeReference::Primitive("void".to_string()),
207 _ => ClrTypeReference::Primitive("object".to_string()),
208 }
209}