1use crate::{
4 adapters::FunctionMapper,
5 config::GaiaConfig,
6 instruction::GaiaInstruction,
7 program::{GaiaConstant, GaiaFunction, GaiaProgram},
8 types::GaiaType,
9 Backend, GeneratedFiles,
10};
11use clr_assembler::formats::msil::writer::MsilWriter;
12use gaia_types::{
13 helpers::{AbiCompatible, ApiCompatible, Architecture, CompilationTarget},
14 GaiaError, Result,
15};
16use std::collections::HashMap;
17
18#[derive(Default)]
20pub struct ClrBackend {}
21
22impl Backend for ClrBackend {
23 fn name(&self) -> &'static str {
24 "MSIL"
25 }
26
27 fn primary_target(&self) -> CompilationTarget {
28 CompilationTarget {
29 build: Architecture::CLR,
30 host: AbiCompatible::MicrosoftIntermediateLanguage,
31 target: ApiCompatible::ClrRuntime(4),
32 }
33 }
34
35 fn match_score(&self, target: &CompilationTarget) -> f32 {
36 match target.build {
37 Architecture::CLR => match target.host {
38 AbiCompatible::Unknown => 5.0,
40 AbiCompatible::MicrosoftIntermediateLanguage => 30.0,
42 _ => -100.0,
43 },
44 _ => -100.0,
45 }
46 }
47
48 fn generate(&self, program: &GaiaProgram, _config: &GaiaConfig) -> Result<GeneratedFiles> {
49 let mut files = HashMap::new();
50 match _config.target.host {
51 AbiCompatible::Unknown => {
52 files.insert("main.dll".to_string(), compile(program)?);
53 }
54 AbiCompatible::MicrosoftIntermediateLanguage => {
55 files.insert("main.il".to_string(), compile(program)?);
56 }
57 _ => Err(GaiaError::invalid_data("Unsupported host ABI for CLR backend"))?,
58 }
59
60 Ok(GeneratedFiles { files, diagnostics: vec![] })
61 }
62}
63
64impl ClrBackend {
65 pub fn generate(program: &GaiaProgram) -> Result<Vec<u8>> {
67 let mut context = create_il_context()?;
68 compile_program(&mut context, program)?;
69 generate_il_bytecode(context)
70 }
71}
72
73pub fn compile(program: &GaiaProgram) -> Result<Vec<u8>> {
75 ClrBackend::generate(program)
76}
77
78fn create_il_context() -> Result<IlContext> {
80 Ok(IlContext::new())
81}
82
83fn compile_program(context: &mut IlContext, program: &GaiaProgram) -> Result<()> {
85 context.emit_assembly_declaration(&program.name)?;
87
88 for function in &program.functions {
90 compile_function(context, function)?;
91 }
92
93 Ok(())
94}
95
96fn compile_function(context: &mut IlContext, function: &GaiaFunction) -> Result<()> {
98 let inferred_return_type = if function.name == "main" && function.return_type.is_none() {
100 let has_return = function.instructions.iter().any(|inst| matches!(inst, GaiaInstruction::Return));
102 if has_return {
103 Some(GaiaType::Integer32)
104 }
105 else {
106 function.return_type.clone()
107 }
108 }
109 else {
110 function.return_type.clone()
111 };
112
113 start_function(context, &function.name, &function.parameters, &inferred_return_type)?;
115
116 for instruction in &function.instructions {
118 compile_instruction(context, instruction)?;
119 }
120
121 end_function(context)?;
123
124 Ok(())
125}
126
127fn compile_instruction(context: &mut IlContext, instruction: &GaiaInstruction) -> Result<()> {
129 match instruction {
130 GaiaInstruction::LoadConstant(constant) => compile_load_constant(context, constant),
131 GaiaInstruction::LoadLocal(index) => compile_load_local(context, (*index).try_into().unwrap()),
132 GaiaInstruction::StoreLocal(index) => compile_store_local(context, (*index).try_into().unwrap()),
133 GaiaInstruction::LoadArgument(index) => compile_load_argument(context, (*index).try_into().unwrap()),
134 GaiaInstruction::Add => compile_add(context),
136 GaiaInstruction::Subtract => compile_subtract(context),
137 GaiaInstruction::Multiply => compile_multiply(context),
138 GaiaInstruction::Divide => compile_divide(context),
139 GaiaInstruction::Equal => compile_equal(context),
140 GaiaInstruction::NotEqual => compile_not_equal(context),
141 GaiaInstruction::LessThan => compile_less_than(context),
142 GaiaInstruction::GreaterThan => compile_greater_than(context),
143 GaiaInstruction::Jump(label) => compile_branch(context, label),
144 GaiaInstruction::JumpIfTrue(label) => compile_branch_if_true(context, label),
145 GaiaInstruction::JumpIfFalse(label) => compile_branch_if_false(context, label),
146 GaiaInstruction::Call(function_name, _arg_count) => compile_call(context, function_name),
147 GaiaInstruction::Return => compile_return(context),
148 GaiaInstruction::Label(name) => compile_label(context, name),
149 GaiaInstruction::Duplicate => compile_duplicate(context),
150 GaiaInstruction::Pop => compile_pop(context),
151 GaiaInstruction::LoadIndirect(gaia_type) => compile_load_indirect(context, gaia_type),
153 GaiaInstruction::StoreIndirect(gaia_type) => compile_store_indirect(context, gaia_type),
154 GaiaInstruction::Convert(from_type, to_type) => compile_convert(context, from_type, to_type),
155 GaiaInstruction::Box(gaia_type) => compile_box(context, gaia_type),
156 GaiaInstruction::Unbox(gaia_type) => compile_unbox(context, gaia_type),
157 _ => Ok(()), }
159}
160
161fn compile_load_constant(context: &mut IlContext, constant: &GaiaConstant) -> Result<()> {
162 match constant {
163 GaiaConstant::Integer8(value) => context.emit_ldc_i4(*value as i32),
164 GaiaConstant::Integer16(value) => context.emit_ldc_i4(*value as i32),
165 GaiaConstant::Integer32(value) => context.emit_ldc_i4(*value),
166 GaiaConstant::Integer64(value) => context.emit_ldc_i8(*value),
167 GaiaConstant::Float32(value) => context.emit_ldc_r4(*value),
168 GaiaConstant::Float64(value) => context.emit_ldc_r8(*value),
169 GaiaConstant::String(value) => context.emit_ldstr(value),
170 GaiaConstant::Boolean(value) => context.emit_ldc_i4(if *value { 1 } else { 0 }),
171 GaiaConstant::Null => context.emit_ldnull(),
172 }
173}
174
175fn compile_load_local(context: &mut IlContext, index: u32) -> Result<()> {
176 context.emit_ldloc(index)
177}
178
179fn compile_store_local(context: &mut IlContext, index: u32) -> Result<()> {
180 context.emit_stloc(index)
181}
182
183fn compile_load_argument(context: &mut IlContext, index: u32) -> Result<()> {
184 context.emit_ldarg(index)
185}
186
187fn compile_add(context: &mut IlContext) -> Result<()> {
188 context.emit_add()
189}
190
191fn compile_subtract(context: &mut IlContext) -> Result<()> {
192 context.emit_sub()
193}
194
195fn compile_multiply(context: &mut IlContext) -> Result<()> {
196 context.emit_mul()
197}
198
199fn compile_divide(context: &mut IlContext) -> Result<()> {
200 context.emit_div()
201}
202
203fn compile_equal(context: &mut IlContext) -> Result<()> {
204 context.emit_ceq()
205}
206
207fn compile_not_equal(context: &mut IlContext) -> Result<()> {
208 context.emit_ceq()?;
209 context.emit_ldc_i4(0)?;
210 context.emit_ceq()
211}
212
213fn compile_less_than(context: &mut IlContext) -> Result<()> {
214 context.emit_clt()
215}
216
217fn compile_greater_than(context: &mut IlContext) -> Result<()> {
218 context.emit_cgt()
219}
220
221fn compile_branch(context: &mut IlContext, label: &str) -> Result<()> {
222 context.emit_br(label)
223}
224
225fn compile_branch_if_true(context: &mut IlContext, label: &str) -> Result<()> {
226 context.emit_brtrue(label)
227}
228
229fn compile_branch_if_false(context: &mut IlContext, label: &str) -> Result<()> {
230 context.emit_brfalse(label)
231}
232
233fn compile_call(context: &mut IlContext, function_name: &str) -> Result<()> {
234 let mapper = FunctionMapper::new();
235 let il_target = CompilationTarget {
236 build: Architecture::CLR,
237 host: AbiCompatible::MicrosoftIntermediateLanguage,
238 target: ApiCompatible::ClrRuntime(4),
239 };
240 let mapped_name = mapper.map_function(&il_target, function_name);
241 context.emit_call(&mapped_name.unwrap_or(function_name))
242}
243
244fn compile_return(context: &mut IlContext) -> Result<()> {
245 context.emit_ret()
246}
247
248fn compile_label(context: &mut IlContext, name: &str) -> Result<()> {
249 context.define_label(name)
250}
251
252fn compile_duplicate(context: &mut IlContext) -> Result<()> {
253 context.emit_dup()
254}
255
256fn compile_pop(context: &mut IlContext) -> Result<()> {
257 context.emit_pop()
258}
259
260fn compile_load_address(context: &mut IlContext, addr: u32) -> Result<()> {
261 context.emit_ldloca(addr)
262}
263
264fn compile_load_indirect(context: &mut IlContext, gaia_type: &GaiaType) -> Result<()> {
265 match gaia_type {
266 GaiaType::Integer8 => context.emit_ldind_i4(), GaiaType::Integer16 => context.emit_ldind_i4(), GaiaType::Integer32 => context.emit_ldind_i4(),
269 GaiaType::Integer64 => context.emit_ldind_i8(),
270 GaiaType::Float32 => context.emit_ldind_r4(),
271 GaiaType::Float64 => context.emit_ldind_r8(),
272 _ => context.emit_ldind_ref(),
273 }
274}
275
276fn compile_store_indirect(context: &mut IlContext, gaia_type: &GaiaType) -> Result<()> {
277 match gaia_type {
278 GaiaType::Integer8 => context.emit_stind_i4(), GaiaType::Integer16 => context.emit_stind_i4(), GaiaType::Integer32 => context.emit_stind_i4(),
281 GaiaType::Integer64 => context.emit_stind_i8(),
282 GaiaType::Float32 => context.emit_stind_r4(),
283 GaiaType::Float64 => context.emit_stind_r8(),
284 _ => context.emit_stind_ref(),
285 }
286}
287
288fn compile_convert(_context: &mut IlContext, _from_type: &GaiaType, _to_type: &GaiaType) -> Result<()> {
289 match _to_type {
290 GaiaType::Integer8 => _context.emit_conv_i4(), GaiaType::Integer16 => _context.emit_conv_i4(), GaiaType::Integer32 => _context.emit_conv_i4(),
293 GaiaType::Integer64 => _context.emit_conv_i8(),
294 GaiaType::Float32 => _context.emit_conv_r4(),
295 GaiaType::Float64 => _context.emit_conv_r8(),
296 _ => Ok(()),
297 }
298}
299
300fn compile_box(context: &mut IlContext, gaia_type: &GaiaType) -> Result<()> {
301 context.emit_box(gaia_type)
302}
303
304fn compile_unbox(context: &mut IlContext, gaia_type: &GaiaType) -> Result<()> {
305 context.emit_unbox(gaia_type)
306}
307
308fn start_function(context: &mut IlContext, name: &str, parameters: &[GaiaType], return_type: &Option<GaiaType>) -> Result<()> {
310 context.start_method(name, parameters, return_type)
311}
312
313fn end_function(context: &mut IlContext) -> Result<()> {
314 context.end_method()
315}
316
317fn gaia_type_to_msil_name(gaia_type: &GaiaType) -> &'static str {
319 match gaia_type {
320 GaiaType::Integer8 => "int8",
321 GaiaType::Integer16 => "int16",
322 GaiaType::Integer32 => "int32",
323 GaiaType::Integer64 => "int64",
324 GaiaType::Float32 => "float32",
325 GaiaType::Float64 => "float64",
326 GaiaType::Boolean => "bool",
327 GaiaType::String => "string",
328 GaiaType::Object => "object",
329 GaiaType::Array(_) => "object",
330 GaiaType::Pointer(_) => "native int",
331 GaiaType::Void => "void",
332 GaiaType::Integer => "int32",
333 GaiaType::Float => "float32",
334 GaiaType::Double => "float64",
335 }
336}
337
338fn generate_il_bytecode(context: IlContext) -> Result<Vec<u8>> {
340 context.generate_bytecode()
341}
342
343struct IlContext {
345 writer: MsilWriter<String>,
346}
347
348impl IlContext {
349 fn new() -> Self {
350 Self { writer: MsilWriter::new(String::new()) }
351 }
352
353 fn emit_assembly_declaration(&mut self, name: &str) -> Result<()> {
354 self.writer.write_assembly(name)
355 }
356
357 fn start_method(&mut self, name: &str, parameters: &[GaiaType], return_type: &Option<GaiaType>) -> Result<()> {
358 let param_names: Vec<&str> = parameters.iter().map(|t| gaia_type_to_msil_name(t)).collect();
359 let ret_name: Option<&str> = return_type.as_ref().map(|t| gaia_type_to_msil_name(t));
360 self.writer.start_method(name, ¶m_names, ret_name)
361 }
362
363 fn end_method(&mut self) -> Result<()> {
364 self.writer.end_method()
365 }
366
367 fn generate_bytecode(self) -> Result<Vec<u8>> {
368 Ok(self.writer.finish().into_bytes())
369 }
370
371 fn emit_ldc_i4(&mut self, value: i32) -> Result<()> {
372 self.writer.emit_ldc_i4(value)
373 }
374
375 fn emit_ldc_i8(&mut self, value: i64) -> Result<()> {
376 self.writer.emit_ldc_i8(value)
377 }
378
379 fn emit_ldc_r4(&mut self, value: f32) -> Result<()> {
380 self.writer.emit_ldc_r4(value)
381 }
382
383 fn emit_ldc_r8(&mut self, value: f64) -> Result<()> {
384 self.writer.emit_ldc_r8(value)
385 }
386
387 fn emit_ldstr(&mut self, value: &str) -> Result<()> {
388 self.writer.emit_ldstr(value)
389 }
390
391 fn emit_ldnull(&mut self) -> Result<()> {
392 self.writer.emit_ldnull()
393 }
394
395 fn emit_ldloc(&mut self, index: u32) -> Result<()> {
396 self.writer.emit_ldloc(index)
397 }
398
399 fn emit_stloc(&mut self, index: u32) -> Result<()> {
400 self.writer.emit_stloc(index)
401 }
402
403 fn emit_ldarg(&mut self, index: u32) -> Result<()> {
404 self.writer.emit_ldarg(index)
405 }
406
407 fn emit_add(&mut self) -> Result<()> {
408 self.writer.emit_add()
409 }
410
411 fn emit_sub(&mut self) -> Result<()> {
412 self.writer.emit_sub()
413 }
414
415 fn emit_mul(&mut self) -> Result<()> {
416 self.writer.emit_mul()
417 }
418
419 fn emit_div(&mut self) -> Result<()> {
420 self.writer.emit_div()
421 }
422
423 fn emit_ceq(&mut self) -> Result<()> {
424 self.writer.emit_ceq()
425 }
426
427 fn emit_clt(&mut self) -> Result<()> {
428 self.writer.emit_clt()
429 }
430
431 fn emit_cgt(&mut self) -> Result<()> {
432 self.writer.emit_cgt()
433 }
434
435 fn emit_br(&mut self, label: &str) -> Result<()> {
436 self.writer.emit_br(label)
437 }
438
439 fn emit_brtrue(&mut self, label: &str) -> Result<()> {
440 self.writer.emit_brtrue(label)
441 }
442
443 fn emit_brfalse(&mut self, label: &str) -> Result<()> {
444 self.writer.emit_brfalse(label)
445 }
446
447 fn emit_call(&mut self, function_name: &str) -> Result<()> {
448 self.writer.emit_call(function_name)
449 }
450
451 fn emit_ret(&mut self) -> Result<()> {
452 self.writer.emit_ret()
453 }
454
455 fn define_label(&mut self, name: &str) -> Result<()> {
456 self.writer.define_label(name)
457 }
458
459 fn emit_dup(&mut self) -> Result<()> {
460 self.writer.emit_dup()
461 }
462
463 fn emit_pop(&mut self) -> Result<()> {
464 self.writer.emit_pop()
465 }
466
467 fn emit_ldloca(&mut self, addr: u32) -> Result<()> {
468 self.writer.emit_ldloca(addr)
469 }
470
471 fn emit_ldind_i4(&mut self) -> Result<()> {
472 self.writer.emit_ldind_i4()
473 }
474
475 fn emit_ldind_i8(&mut self) -> Result<()> {
476 self.writer.emit_ldind_i8()
477 }
478
479 fn emit_ldind_r4(&mut self) -> Result<()> {
480 self.writer.emit_ldind_r4()
481 }
482
483 fn emit_ldind_r8(&mut self) -> Result<()> {
484 self.writer.emit_ldind_r8()
485 }
486
487 fn emit_ldind_ref(&mut self) -> Result<()> {
488 self.writer.emit_ldind_ref()
489 }
490
491 fn emit_stind_i4(&mut self) -> Result<()> {
492 self.writer.emit_stind_i4()
493 }
494
495 fn emit_stind_i8(&mut self) -> Result<()> {
496 self.writer.emit_stind_i8()
497 }
498
499 fn emit_stind_r4(&mut self) -> Result<()> {
500 self.writer.emit_stind_r4()
501 }
502
503 fn emit_stind_r8(&mut self) -> Result<()> {
504 self.writer.emit_stind_r8()
505 }
506
507 fn emit_stind_ref(&mut self) -> Result<()> {
508 self.writer.emit_stind_ref()
509 }
510
511 fn emit_conv_i4(&mut self) -> Result<()> {
512 self.writer.emit_conv_i4()
513 }
514
515 fn emit_conv_i8(&mut self) -> Result<()> {
516 self.writer.emit_conv_i8()
517 }
518
519 fn emit_conv_r4(&mut self) -> Result<()> {
520 self.writer.emit_conv_r4()
521 }
522
523 fn emit_conv_r8(&mut self) -> Result<()> {
524 self.writer.emit_conv_r8()
525 }
526
527 fn emit_box(&mut self, gaia_type: &GaiaType) -> Result<()> {
528 let type_name = match gaia_type {
529 GaiaType::Integer32 => "int32",
530 GaiaType::Integer64 => "int64",
531 GaiaType::Float32 => "float32",
532 GaiaType::Float64 => "float64",
533 GaiaType::Boolean => "bool",
534 _ => "object",
535 };
536 self.writer.emit_box(type_name)
537 }
538
539 fn emit_unbox(&mut self, gaia_type: &GaiaType) -> Result<()> {
540 let type_name = match gaia_type {
541 GaiaType::Integer32 => "int32",
542 GaiaType::Integer64 => "int64",
543 GaiaType::Float32 => "float32",
544 GaiaType::Float64 => "float64",
545 GaiaType::Boolean => "bool",
546 _ => "object",
547 };
548 self.writer.emit_unbox(type_name)
549 }
550}