1#[cfg(feature = "clr")]
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")]
13use clr_assembler::program::*;
14#[cfg(feature = "clr")]
15#[allow(unused_imports)]
16use gaia_types::{
17 helpers::{AbiCompatible, ApiCompatible, Architecture, CompilationTarget},
18 GaiaError, Result,
19};
20#[cfg(feature = "clr")]
21use std::collections::HashMap;
22
23#[derive(Default)]
25#[cfg(feature = "clr")]
26pub struct ClrBackend {}
27
28#[cfg(feature = "clr")]
29impl Backend for ClrBackend {
30 fn name(&self) -> &'static str {
31 "MSIL"
32 }
33
34 fn primary_target(&self) -> CompilationTarget {
35 CompilationTarget {
36 build: Architecture::CLR,
37 host: AbiCompatible::MicrosoftIntermediateLanguage,
38 target: ApiCompatible::ClrRuntime(4),
39 }
40 }
41
42 fn match_score(&self, target: &CompilationTarget) -> f32 {
43 match target.build {
44 Architecture::CLR => match target.host {
45 AbiCompatible::Unknown => 30.0,
47 AbiCompatible::MicrosoftIntermediateLanguage => 30.0,
49 _ => -100.0,
50 },
51 _ => -100.0,
52 }
53 }
54
55 fn generate(&self, program: &GaiaModule, _config: &GaiaConfig) -> Result<GeneratedFiles> {
56 let mut files = HashMap::new();
57 match _config.target.host {
58 AbiCompatible::Unknown => {
59 let clr_program = convert_to_clr_program(program, Some(&_config.setting))?;
61 let buffer = std::io::Cursor::new(Vec::new());
62 let writer = clr_assembler::formats::dll::writer::DllWriter::new(buffer);
63 let result = writer.write(&clr_program);
64 if let Some(error) = result.diagnostics.into_iter().next() {
65 return Err(error);
66 }
67 files.insert("main.dll".to_string(), result.result.expect("Failed to get DLL buffer").into_inner());
68 }
69 AbiCompatible::MicrosoftIntermediateLanguage => {
70 files.insert("main.il".to_string(), compile_with_settings(program, Some(&_config.setting))?);
72 }
73 _ => Err(GaiaError::invalid_data("Unsupported host ABI for CLR backend"))?,
74 }
75
76 Ok(GeneratedFiles { files, diagnostics: vec![] })
77 }
78}
79
80#[cfg(feature = "clr")]
81impl ClrBackend {
82 pub fn generate(program: &GaiaModule) -> Result<Vec<u8>> {
84 compile_with_settings(program, None)
86 }
87
88 pub fn generate_with_settings(program: &GaiaModule, settings: &GaiaSettings) -> Result<Vec<u8>> {
90 compile_with_settings(program, Some(settings))
92 }
93}
94
95#[cfg(feature = "clr")]
97pub fn compile(program: &GaiaModule) -> Result<Vec<u8>> {
98 ClrBackend::generate(program)
99}
100
101#[cfg(feature = "clr")]
103fn compile_with_settings(program: &GaiaModule, settings: Option<&GaiaSettings>) -> Result<Vec<u8>> {
104 let mut context = IlContext::new_text();
105 if let Some(s) = settings {
106 context.function_mapper = FunctionMapper::from_config(s).unwrap_or_default();
107 }
108 compile_program(&mut context, program)?;
109 context.generate_bytecode()
110}
111
112#[cfg(feature = "clr")]
114fn compile_program(context: &mut IlContext, program: &GaiaModule) -> Result<()> {
115 for s in &program.structs {
117 for (name, ty) in &s.fields {
118 context.field_types.insert((s.name.clone(), name.clone()), ty.clone());
119 }
120 }
121 for c in &program.classes {
122 for field in &c.fields {
123 context.field_types.insert((c.name.clone(), field.name.clone()), field.ty.clone());
124 }
125 }
126 for g in &program.globals {
127 context.field_types.insert(("Main".to_string(), g.name.clone()), g.ty.clone());
128 }
129
130 context.emit_assembly_declaration(&program.name)?;
132
133 for import in &program.imports {
135 context.emit_external_assembly(&import.library)?;
136 }
137
138 for s in &program.structs {
140 compile_struct(context, s)?;
141 }
142
143 for c in &program.classes {
145 compile_class(context, c)?;
146 }
147
148 for function in &program.functions {
150 compile_function(context, function)?;
151 }
152
153 Ok(())
154}
155
156#[cfg(feature = "clr")]
158fn compile_struct(context: &mut IlContext, s: &crate::program::GaiaStruct) -> Result<()> {
159 context.start_class(&s.name)?;
160
161 for (name, ty) in &s.fields {
162 context.write_field(name, ty)?;
163 }
164
165 if let IlMode::Text(writer) = &mut context.mode {
167 writer.write_default_constructor()?;
168 }
169
170 context.end_class()?;
171 Ok(())
172}
173
174#[cfg(feature = "clr")]
176fn compile_class(context: &mut IlContext, c: &crate::program::GaiaClass) -> Result<()> {
177 context.start_class(&c.name)?;
178
179 for field in &c.fields {
180 context.write_field(&field.name, &field.ty)?;
181 }
182
183 for method in &c.methods {
184 compile_function(context, method)?;
185 }
186
187 context.end_class()?;
188 Ok(())
189}
190
191#[cfg(feature = "clr")]
193fn compile_function(context: &mut IlContext, function: &GaiaFunction) -> Result<()> {
194 start_function(
196 context,
197 &function.name,
198 &function.signature.params,
199 &Some(function.signature.return_type.clone()),
200 function.name == "main",
201 )?;
202
203 for block in &function.blocks {
205 context.define_label(&block.label)?;
206
207 for instruction in &block.instructions {
208 compile_instruction(context, instruction)?;
209 }
210
211 match &block.terminator {
213 crate::program::GaiaTerminator::Jump(label) => context.emit_br(label)?,
214 crate::program::GaiaTerminator::Branch { true_label, false_label } => {
215 context.emit_brtrue(true_label)?;
216 context.emit_br(false_label)?;
217 }
218 crate::program::GaiaTerminator::Return => context.emit_ret()?,
219 crate::program::GaiaTerminator::Call { callee, args_count: _, next_block } => {
220 context.emit_call(callee)?;
221 context.emit_br(next_block)?;
222 }
223 crate::program::GaiaTerminator::Halt => {
224 context.emit_ldc_i4(0)?;
225 context.emit_call("ExitProcess")?;
226 }
227 }
228 }
229
230 end_function(context)?;
232
233 Ok(())
234}
235
236#[cfg(feature = "clr")]
238fn compile_instruction(context: &mut IlContext, instruction: &GaiaInstruction) -> Result<()> {
239 match instruction {
240 GaiaInstruction::Core(core) => match core {
241 CoreInstruction::PushConstant(constant) => compile_load_constant(context, constant),
242 CoreInstruction::Load(gaia_type) => compile_load_indirect(context, gaia_type),
243 CoreInstruction::Store(gaia_type) => compile_store_indirect(context, gaia_type),
244 CoreInstruction::Add(_) => compile_add(context),
245 CoreInstruction::Sub(_) => compile_subtract(context),
246 CoreInstruction::Mul(_) => compile_multiply(context),
247 CoreInstruction::Div(_) => compile_divide(context),
248 CoreInstruction::Pop => compile_pop(context),
249 CoreInstruction::Dup => compile_duplicate(context),
250 CoreInstruction::Cmp(cond, _) => match cond {
251 CmpCondition::Eq => compile_equal(context),
252 CmpCondition::Ne => compile_not_equal(context),
253 CmpCondition::Lt => compile_less_than(context),
254 CmpCondition::Le => compile_less_than_or_equal(context),
255 CmpCondition::Gt => compile_greater_than(context),
256 CmpCondition::Ge => compile_greater_than_or_equal(context),
257 },
258 CoreInstruction::Ret => compile_return(context),
259 CoreInstruction::Br(label) => compile_branch(context, label),
260 CoreInstruction::BrTrue(label) => compile_branch_true(context, label),
261 CoreInstruction::BrFalse(label) => compile_branch_false(context, label),
262 CoreInstruction::Label(name) => compile_label(context, name),
263 CoreInstruction::Call(name, arg_count) => compile_call(context, name, *arg_count),
264 CoreInstruction::LoadLocal(index, _) => compile_load_local(context, *index),
265 CoreInstruction::StoreLocal(index, _) => compile_store_local(context, *index),
266 CoreInstruction::LoadArg(index, _) => compile_load_argument(context, *index),
267 CoreInstruction::StoreArg(index, _) => compile_store_argument(context, *index),
268 CoreInstruction::New(type_name) => compile_new_object(context, type_name),
269 CoreInstruction::NewArray(elem_type, _) => compile_new_array(context, elem_type),
270 CoreInstruction::LoadField(type_name, field_name) => {
271 let gaia_type = context
272 .field_types
273 .get(&(type_name.to_string(), field_name.to_string()))
274 .cloned()
275 .unwrap_or(GaiaType::Object);
276 compile_load_field(context, type_name, field_name, &gaia_type)
277 }
278 CoreInstruction::StoreField(type_name, field_name) => {
279 let gaia_type = context
280 .field_types
281 .get(&(type_name.to_string(), field_name.to_string()))
282 .cloned()
283 .unwrap_or(GaiaType::Object);
284 compile_store_field(context, type_name, field_name, &gaia_type)
285 }
286 CoreInstruction::LoadElement(elem_type) => compile_load_element(context, elem_type),
287 CoreInstruction::StoreElement(elem_type) => compile_store_element(context, elem_type),
288 CoreInstruction::ArrayLength => compile_array_length(context),
289 _ => Ok(()),
290 },
291 GaiaInstruction::Managed(managed) => match managed {
292 _ => Ok(()),
293 },
294 _ => Ok(()),
295 }
296}
297
298#[cfg(feature = "clr")]
299fn compile_new_object(context: &mut IlContext, type_name: &str) -> Result<()> {
300 let ctor_ref = format!("instance void {}::.ctor()", type_name);
302 context.emit_newobj(&ctor_ref)
303}
304
305#[cfg(feature = "clr")]
306fn compile_load_field(context: &mut IlContext, type_name: &str, field_name: &str, gaia_type: &GaiaType) -> Result<()> {
307 let field_ref = format!("{} {}::{}", gaia_type_to_msil_name(gaia_type), type_name, field_name);
308 context.emit_ldfld(&field_ref)
309}
310
311#[cfg(feature = "clr")]
312fn compile_store_field(context: &mut IlContext, type_name: &str, field_name: &str, gaia_type: &GaiaType) -> Result<()> {
313 let field_ref = format!("{} {}::{}", gaia_type_to_msil_name(gaia_type), type_name, field_name);
314 context.emit_stfld(&field_ref)
315}
316
317#[cfg(feature = "clr")]
318fn compile_new_array(context: &mut IlContext, elem_type: &GaiaType) -> Result<()> {
319 context.emit_newarr(&gaia_type_to_msil_name(elem_type))
320}
321
322#[cfg(feature = "clr")]
323fn compile_load_element(context: &mut IlContext, elem_type: &GaiaType) -> Result<()> {
324 context.emit_ldelem(&gaia_type_to_msil_name(elem_type))
325}
326
327#[cfg(feature = "clr")]
328fn compile_store_element(context: &mut IlContext, elem_type: &GaiaType) -> Result<()> {
329 context.emit_stelem(&gaia_type_to_msil_name(elem_type))
330}
331
332#[cfg(feature = "clr")]
333fn compile_array_length(context: &mut IlContext) -> Result<()> {
334 context.emit_ldlen()
335}
336
337#[cfg(feature = "clr")]
338fn compile_return(context: &mut IlContext) -> Result<()> {
339 context.emit_ret()
340}
341
342#[cfg(feature = "clr")]
343fn compile_branch(context: &mut IlContext, label: &str) -> Result<()> {
344 context.emit_br(label)
345}
346
347#[cfg(feature = "clr")]
348fn compile_branch_true(context: &mut IlContext, label: &str) -> Result<()> {
349 context.emit_brtrue(label)
350}
351
352#[cfg(feature = "clr")]
353fn compile_branch_false(context: &mut IlContext, label: &str) -> Result<()> {
354 context.emit_brfalse(label)
355}
356
357#[cfg(feature = "clr")]
358fn compile_label(context: &mut IlContext, name: &str) -> Result<()> {
359 context.define_label(name)
360}
361
362#[cfg(feature = "clr")]
363fn compile_call(context: &mut IlContext, name: &str, _arg_count: usize) -> Result<()> {
364 let mapped_name = context.map_function(name);
367 context.emit_call(&mapped_name)
368}
369
370#[cfg(feature = "clr")]
371fn compile_load_constant(context: &mut IlContext, constant: &GaiaConstant) -> Result<()> {
372 match constant {
373 GaiaConstant::I8(value) => context.emit_ldc_i4(*value as i32),
374 GaiaConstant::U8(value) => context.emit_ldc_i4(*value as i32),
375 GaiaConstant::I16(value) => context.emit_ldc_i4(*value as i32),
376 GaiaConstant::U16(value) => context.emit_ldc_i4(*value as i32),
377 GaiaConstant::I32(value) => context.emit_ldc_i4(*value),
378 GaiaConstant::U32(value) => context.emit_ldc_i4(*value as i32),
379 GaiaConstant::I64(value) => context.emit_ldc_i8(*value),
380 GaiaConstant::U64(value) => context.emit_ldc_i8(*value as i64),
381 GaiaConstant::F32(value) => context.emit_ldc_r4(*value),
382 GaiaConstant::F64(value) => context.emit_ldc_r8(*value),
383 GaiaConstant::String(value) => context.emit_ldstr(value),
384 GaiaConstant::Bool(value) => context.emit_ldc_i4(if *value { 1 } else { 0 }),
385 GaiaConstant::Null => context.emit_ldnull(),
386 _ => Err(GaiaError::custom_error("Unsupported constant type for CLR")),
387 }
388}
389
390#[cfg(feature = "clr")]
391fn compile_load_local(context: &mut IlContext, index: u32) -> Result<()> {
392 context.emit_ldloc(index)
393}
394
395#[cfg(feature = "clr")]
396fn compile_store_local(context: &mut IlContext, index: u32) -> Result<()> {
397 context.emit_stloc(index)
398}
399
400#[cfg(feature = "clr")]
401fn compile_load_argument(context: &mut IlContext, index: u32) -> Result<()> {
402 context.emit_ldarg(index)
403}
404
405#[cfg(feature = "clr")]
406fn compile_store_argument(context: &mut IlContext, index: u32) -> Result<()> {
407 context.emit_starg(index)
408}
409
410#[cfg(feature = "clr")]
411fn compile_add(context: &mut IlContext) -> Result<()> {
412 context.emit_add()
413}
414
415#[cfg(feature = "clr")]
416fn compile_subtract(context: &mut IlContext) -> Result<()> {
417 context.emit_sub()
418}
419
420#[cfg(feature = "clr")]
421fn compile_multiply(context: &mut IlContext) -> Result<()> {
422 context.emit_mul()
423}
424
425#[cfg(feature = "clr")]
426fn compile_divide(context: &mut IlContext) -> Result<()> {
427 context.emit_div()
428}
429
430#[cfg(feature = "clr")]
431fn compile_equal(context: &mut IlContext) -> Result<()> {
432 context.emit_ceq()
433}
434
435#[cfg(feature = "clr")]
436fn compile_not_equal(context: &mut IlContext) -> Result<()> {
437 context.emit_ceq()?;
438 context.emit_ldc_i4(0)?;
439 context.emit_ceq()
440}
441
442#[cfg(feature = "clr")]
443fn compile_less_than(context: &mut IlContext) -> Result<()> {
444 context.emit_clt()
445}
446
447#[cfg(feature = "clr")]
448fn compile_greater_than(context: &mut IlContext) -> Result<()> {
449 context.emit_cgt()
450}
451
452#[cfg(feature = "clr")]
453fn compile_less_than_or_equal(context: &mut IlContext) -> Result<()> {
454 context.emit_cgt()?;
456 context.emit_ldc_i4(0)?;
457 context.emit_ceq()
458}
459
460#[cfg(feature = "clr")]
461fn compile_greater_than_or_equal(context: &mut IlContext) -> Result<()> {
462 context.emit_clt()?;
464 context.emit_ldc_i4(0)?;
465 context.emit_ceq()
466}
467
468#[cfg(feature = "clr")]
469fn compile_logical_not(context: &mut IlContext) -> Result<()> {
470 context.emit_ldc_i4(0)?;
472 context.emit_ceq()
473}
474
475#[cfg(feature = "clr")]
476fn compile_duplicate(context: &mut IlContext) -> Result<()> {
477 context.emit_dup()
478}
479
480#[cfg(feature = "clr")]
481fn compile_pop(context: &mut IlContext) -> Result<()> {
482 context.emit_pop()
483}
484
485#[cfg(feature = "clr")]
486fn compile_logical_and(context: &mut IlContext) -> Result<()> {
487 context.emit_and()
488}
489
490#[cfg(feature = "clr")]
491fn compile_logical_or(context: &mut IlContext) -> Result<()> {
492 context.emit_or()
493}
494
495#[cfg(feature = "clr")]
496fn compile_load_address(context: &mut IlContext, addr: u32) -> Result<()> {
497 context.emit_ldloca(addr)
498}
499
500#[cfg(feature = "clr")]
501fn compile_load_indirect(context: &mut IlContext, gaia_type: &GaiaType) -> Result<()> {
502 match gaia_type {
503 GaiaType::I8 => context.emit_ldind_i4(), GaiaType::I16 => context.emit_ldind_i4(), GaiaType::I32 => context.emit_ldind_i4(),
506 GaiaType::I64 => context.emit_ldind_i8(),
507 GaiaType::F32 => context.emit_ldind_r4(),
508 GaiaType::F64 => context.emit_ldind_r8(),
509 _ => context.emit_ldind_ref(),
510 }
511}
512
513#[cfg(feature = "clr")]
514fn compile_store_indirect(context: &mut IlContext, gaia_type: &GaiaType) -> Result<()> {
515 match gaia_type {
516 GaiaType::I8 => context.emit_stind_i4(), GaiaType::I16 => context.emit_stind_i4(), GaiaType::I32 => context.emit_stind_i4(),
519 GaiaType::I64 => context.emit_stind_i8(),
520 GaiaType::F32 => context.emit_stind_r4(),
521 GaiaType::F64 => context.emit_stind_r8(),
522 _ => context.emit_stind_ref(),
523 }
524}
525
526#[cfg(feature = "clr")]
527fn compile_convert(_context: &mut IlContext, _from_type: &GaiaType, _to_type: &GaiaType) -> Result<()> {
528 match _to_type {
529 GaiaType::I8 => _context.emit_conv_i4(), GaiaType::I16 => _context.emit_conv_i4(), GaiaType::I32 => _context.emit_conv_i4(),
532 GaiaType::I64 => _context.emit_conv_i8(),
533 GaiaType::F32 => _context.emit_conv_r4(),
534 GaiaType::F64 => _context.emit_conv_r8(),
535 _ => Ok(()),
536 }
537}
538
539#[cfg(feature = "clr")]
540fn compile_box(context: &mut IlContext, gaia_type: &GaiaType) -> Result<()> {
541 context.emit_box(gaia_type)
542}
543
544#[cfg(feature = "clr")]
545fn compile_unbox(context: &mut IlContext, gaia_type: &GaiaType) -> Result<()> {
546 context.emit_unbox(gaia_type)
547}
548
549#[cfg(feature = "clr")]
551fn start_function(
552 context: &mut IlContext,
553 name: &str,
554 parameters: &[GaiaType],
555 return_type: &Option<GaiaType>,
556 is_entry: bool,
557) -> Result<()> {
558 context.start_method(name, parameters, return_type, is_entry)
559}
560
561#[cfg(feature = "clr")]
562fn end_function(context: &mut IlContext) -> Result<()> {
563 context.end_method()
564}
565
566#[cfg(feature = "clr")]
568fn gaia_type_to_msil_name(gaia_type: &GaiaType) -> String {
569 match gaia_type {
570 GaiaType::I8 => "int8".to_string(),
571 GaiaType::U8 => "uint8".to_string(),
572 GaiaType::I16 => "int16".to_string(),
573 GaiaType::U16 => "uint16".to_string(),
574 GaiaType::I32 => "int32".to_string(),
575 GaiaType::U32 => "uint32".to_string(),
576 GaiaType::I64 => "int64".to_string(),
577 GaiaType::U64 => "uint64".to_string(),
578 GaiaType::F32 => "float32".to_string(),
579 GaiaType::F64 => "float64".to_string(),
580 GaiaType::Bool => "bool".to_string(),
581 GaiaType::String => "string".to_string(),
582 GaiaType::Object => "object".to_string(),
583 GaiaType::Class(name) => name.clone(),
584 GaiaType::Struct(name) => name.clone(),
585 GaiaType::Array(elem, _) => format!("{}[]", gaia_type_to_msil_name(elem)),
586 GaiaType::Pointer(_, _) => "native int".to_string(),
587 GaiaType::Void => "void".to_string(),
588 _ => "object".to_string(),
589 }
590}
591
592#[cfg(feature = "clr")]
594struct MsilWriter<W: std::fmt::Write> {
595 writer: gaia_types::writer::TextWriter<W>,
596}
597
598#[cfg(feature = "clr")]
599impl<W: std::fmt::Write> MsilWriter<W> {
600 fn new(writer: W) -> Self {
601 Self { writer: gaia_types::writer::TextWriter::new(writer) }
602 }
603
604 fn finish(self) -> W {
605 self.writer.into_inner()
606 }
607
608 fn write_assembly(&mut self, name: &str) -> Result<()> {
609 self.writer.write_line(&format!(".assembly {} {{}}", name))?;
610 Ok(())
611 }
612
613 fn write_external_assembly(&mut self, name: &str) -> Result<()> {
614 self.writer.write_line(&format!(".assembly extern {} {{}}", name))?;
615 Ok(())
616 }
617
618 fn start_class(&mut self, name: &str) -> Result<()> {
619 self.writer
620 .write_line(&format!(".class public auto ansi beforefieldinit {} extends [mscorlib]System.Object {{", name))?;
621 self.writer.indent("")?;
622 Ok(())
623 }
624
625 fn end_class(&mut self) -> Result<()> {
626 self.writer.dedent("}")?;
627 self.writer.write_line("")?;
628 Ok(())
629 }
630
631 fn write_field(&mut self, name: &str, msil_type: &str) -> Result<()> {
632 self.writer.write_line(&format!(".field public {} {}", msil_type, name))?;
633 Ok(())
634 }
635
636 fn write_default_constructor(&mut self) -> Result<()> {
637 self.writer.write_line(".method public hidebysig specialname rtspecialname instance void .ctor() cil managed {")?;
638 self.writer.indent("")?;
639 self.writer.write_line("ldarg.0")?;
640 self.writer.write_line("call instance void [mscorlib]System.Object::.ctor()")?;
641 self.writer.write_line("ret")?;
642 self.writer.dedent("}")?;
643 Ok(())
644 }
645
646 fn start_method(&mut self, name: &str, parameters: &[&str], return_type: Option<&str>, is_entry: bool) -> Result<()> {
647 let ret = return_type.unwrap_or("void");
648 let params = parameters.join(", ");
649 self.writer.write_line(&format!(".method public hidebysig {} {}({}) cil managed {{", ret, name, params))?;
650 self.writer.indent("")?;
651 if is_entry {
652 self.writer.write_line(".entrypoint")?;
653 }
654 self.writer.write_line(".maxstack 8")?;
655 Ok(())
656 }
657
658 fn end_method(&mut self) -> Result<()> {
659 self.writer.dedent("}")?;
660 self.writer.write_line("")?;
661 Ok(())
662 }
663
664 fn define_label(&mut self, name: &str) -> Result<()> {
665 self.writer.write_line(&format!("{}:", name))?;
666 Ok(())
667 }
668
669 fn emit_ldc_i4(&mut self, value: i32) -> Result<()> {
670 self.writer.write_line(&format!("ldc.i4 {}", value))?;
671 Ok(())
672 }
673
674 fn emit_ldc_i8(&mut self, value: i64) -> Result<()> {
675 self.writer.write_line(&format!("ldc.i8 {}", value))?;
676 Ok(())
677 }
678
679 fn emit_ldc_r4(&mut self, value: f32) -> Result<()> {
680 self.writer.write_line(&format!("ldc.r4 {}", value))?;
681 Ok(())
682 }
683
684 fn emit_ldc_r8(&mut self, value: f64) -> Result<()> {
685 self.writer.write_line(&format!("ldc.r8 {}", value))?;
686 Ok(())
687 }
688
689 fn emit_ldstr(&mut self, value: &str) -> Result<()> {
690 self.writer.write_line(&format!("ldstr \"{}\"", value))?;
691 Ok(())
692 }
693
694 fn emit_ldnull(&mut self) -> Result<()> {
695 self.writer.write_line("ldnull")?;
696 Ok(())
697 }
698
699 fn emit_ldloc(&mut self, index: u32) -> Result<()> {
700 self.writer.write_line(&format!("ldloc {}", index))?;
701 Ok(())
702 }
703
704 fn emit_stloc(&mut self, index: u32) -> Result<()> {
705 self.writer.write_line(&format!("stloc {}", index))?;
706 Ok(())
707 }
708
709 fn emit_ldarg(&mut self, index: u32) -> Result<()> {
710 self.writer.write_line(&format!("ldarg {}", index))?;
711 Ok(())
712 }
713
714 fn emit_starg(&mut self, index: u32) -> Result<()> {
715 self.writer.write_line(&format!("starg {}", index))?;
716 Ok(())
717 }
718
719 fn emit_add(&mut self) -> Result<()> {
720 self.writer.write_line("add")?;
721 Ok(())
722 }
723
724 fn emit_sub(&mut self) -> Result<()> {
725 self.writer.write_line("sub")?;
726 Ok(())
727 }
728
729 fn emit_mul(&mut self) -> Result<()> {
730 self.writer.write_line("mul")?;
731 Ok(())
732 }
733
734 fn emit_div(&mut self) -> Result<()> {
735 self.writer.write_line("div")?;
736 Ok(())
737 }
738
739 fn emit_ceq(&mut self) -> Result<()> {
740 self.writer.write_line("ceq")?;
741 Ok(())
742 }
743
744 fn emit_cgt(&mut self) -> Result<()> {
745 self.writer.write_line("cgt")?;
746 Ok(())
747 }
748
749 fn emit_clt(&mut self) -> Result<()> {
750 self.writer.write_line("clt")?;
751 Ok(())
752 }
753
754 fn emit_br(&mut self, label: &str) -> Result<()> {
755 self.writer.write_line(&format!("br {}", label))?;
756 Ok(())
757 }
758
759 fn emit_brtrue(&mut self, label: &str) -> Result<()> {
760 self.writer.write_line(&format!("brtrue {}", label))?;
761 Ok(())
762 }
763
764 fn emit_brfalse(&mut self, label: &str) -> Result<()> {
765 self.writer.write_line(&format!("brfalse {}", label))?;
766 Ok(())
767 }
768
769 fn emit_call(&mut self, method_ref: &str) -> Result<()> {
770 self.writer.write_line(&format!("call {}", method_ref))?;
771 Ok(())
772 }
773
774 fn emit_ret(&mut self) -> Result<()> {
775 self.writer.write_line("ret")?;
776 Ok(())
777 }
778
779 fn emit_dup(&mut self) -> Result<()> {
780 self.writer.write_line("dup")?;
781 Ok(())
782 }
783
784 fn emit_pop(&mut self) -> Result<()> {
785 self.writer.write_line("pop")?;
786 Ok(())
787 }
788
789 fn emit_newarr(&mut self, type_name: &str) -> Result<()> {
790 self.writer.write_line(&format!("newarr {}", type_name))?;
791 Ok(())
792 }
793
794 fn emit_ldelem(&mut self, type_name: &str) -> Result<()> {
795 self.writer.write_line(&format!("ldelem {}", type_name))?;
796 Ok(())
797 }
798
799 fn emit_stelem(&mut self, type_name: &str) -> Result<()> {
800 self.writer.write_line(&format!("stelem {}", type_name))?;
801 Ok(())
802 }
803
804 fn emit_ldlen(&mut self) -> Result<()> {
805 self.writer.write_line("ldlen")?;
806 Ok(())
807 }
808
809 fn emit_and(&mut self) -> Result<()> {
810 self.writer.write_line("and")?;
811 Ok(())
812 }
813
814 fn emit_or(&mut self) -> Result<()> {
815 self.writer.write_line("or")?;
816 Ok(())
817 }
818
819 fn emit_ldloca(&mut self, index: u32) -> Result<()> {
820 self.writer.write_line(&format!("ldloca {}", index))?;
821 Ok(())
822 }
823
824 fn emit_ldind_i4(&mut self) -> Result<()> {
825 self.writer.write_line("ldind.i4")?;
826 Ok(())
827 }
828
829 fn emit_ldind_i8(&mut self) -> Result<()> {
830 self.writer.write_line("ldind.i8")?;
831 Ok(())
832 }
833
834 fn emit_ldind_r4(&mut self) -> Result<()> {
835 self.writer.write_line("ldind.r4")?;
836 Ok(())
837 }
838
839 fn emit_ldind_r8(&mut self) -> Result<()> {
840 self.writer.write_line("ldind.r8")?;
841 Ok(())
842 }
843
844 fn emit_ldind_ref(&mut self) -> Result<()> {
845 self.writer.write_line("ldind.ref")?;
846 Ok(())
847 }
848
849 fn emit_stind_i4(&mut self) -> Result<()> {
850 self.writer.write_line("stind.i4")?;
851 Ok(())
852 }
853
854 fn emit_stind_i8(&mut self) -> Result<()> {
855 self.writer.write_line("stind.i8")?;
856 Ok(())
857 }
858
859 fn emit_stind_r4(&mut self) -> Result<()> {
860 self.writer.write_line("stind.r4")?;
861 Ok(())
862 }
863
864 fn emit_stind_r8(&mut self) -> Result<()> {
865 self.writer.write_line("stind.r8")?;
866 Ok(())
867 }
868
869 fn emit_stind_ref(&mut self) -> Result<()> {
870 self.writer.write_line("stind.ref")?;
871 Ok(())
872 }
873
874 fn emit_newobj(&mut self, method_ref: &str) -> Result<()> {
875 self.writer.write_line(&format!("newobj {}", method_ref))?;
876 Ok(())
877 }
878
879 fn emit_ldfld(&mut self, field_ref: &str) -> Result<()> {
880 self.writer.write_line(&format!("ldfld {}", field_ref))?;
881 Ok(())
882 }
883
884 fn emit_stfld(&mut self, field_ref: &str) -> Result<()> {
885 self.writer.write_line(&format!("stfld {}", field_ref))?;
886 Ok(())
887 }
888
889 fn emit_conv_i4(&mut self) -> Result<()> {
890 self.writer.write_line("conv.i4")?;
891 Ok(())
892 }
893
894 fn emit_conv_i8(&mut self) -> Result<()> {
895 self.writer.write_line("conv.i8")?;
896 Ok(())
897 }
898
899 fn emit_conv_r4(&mut self) -> Result<()> {
900 self.writer.write_line("conv.r4")?;
901 Ok(())
902 }
903
904 fn emit_conv_r8(&mut self) -> Result<()> {
905 self.writer.write_line("conv.r8")?;
906 Ok(())
907 }
908
909 fn emit_box(&mut self, type_name: &str) -> Result<()> {
910 self.writer.write_line(&format!("box {}", type_name))?;
911 Ok(())
912 }
913
914 fn emit_unbox(&mut self, type_name: &str) -> Result<()> {
915 self.writer.write_line(&format!("unbox {}", type_name))?;
916 Ok(())
917 }
918}
919
920#[cfg(feature = "clr")]
922struct IlContext {
923 mode: IlMode,
924 function_mapper: FunctionMapper,
925 field_types: HashMap<(String, String), GaiaType>,
927}
928
929#[cfg(feature = "clr")]
930enum IlMode {
931 Text(MsilWriter<String>),
932 Binary { program: ClrProgram, current_type: Option<ClrType>, current_method: Option<ClrMethod> },
933}
934
935#[cfg(feature = "clr")]
936impl IlContext {
937 fn new_text() -> Self {
938 Self {
939 mode: IlMode::Text(MsilWriter::new(String::new())),
940 function_mapper: FunctionMapper::new(),
941 field_types: HashMap::new(),
942 }
943 }
944
945 fn new_binary(name: String) -> Self {
946 let program = ClrProgram {
947 name: name.clone(),
948 version: ClrVersion { major: 1, minor: 0, build: 0, revision: 0 },
949 access_flags: ClrAccessFlags {
950 is_public: true,
951 is_private: false,
952 is_security_transparent: false,
953 is_retargetable: false,
954 },
955 external_assemblies: vec![ClrExternalAssembly {
956 name: "mscorlib".to_string(),
957 version: ClrVersion { major: 4, minor: 0, build: 0, revision: 0 },
958 public_key_token: Some(vec![0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89]),
959 culture: None,
960 hash_algorithm: None,
961 }],
962 module: Some(ClrModule { name: format!("{}.dll", name), mvid: None }),
963 types: vec![],
964 global_methods: vec![],
965 global_fields: vec![],
966 attributes: vec![],
967 constant_pool: ClrConstantPool::new(),
968 source_file: None,
969 };
970 Self {
971 mode: IlMode::Binary { program, current_type: None, current_method: None },
972 function_mapper: FunctionMapper::new(),
973 field_types: HashMap::new(),
974 }
975 }
976
977 fn start_class(&mut self, name: &str) -> Result<()> {
978 match &mut self.mode {
979 IlMode::Text(writer) => writer.start_class(name),
980 IlMode::Binary { current_type, .. } => {
981 let clr_type = ClrType {
982 name: name.to_string(),
983 namespace: None,
984 access_flags: ClrAccessFlags {
985 is_public: true,
986 is_private: false,
987 is_security_transparent: false,
988 is_retargetable: false,
989 },
990 base_type: Some("System.Object".to_string()),
991 interfaces: vec![],
992 fields: vec![],
993 methods: vec![],
994 properties: vec![],
995 events: vec![],
996 nested_types: vec![],
997 attributes: vec![],
998 };
999 *current_type = Some(clr_type);
1000 Ok(())
1001 }
1002 }
1003 }
1004
1005 fn end_class(&mut self) -> Result<()> {
1006 match &mut self.mode {
1007 IlMode::Text(writer) => writer.end_class(),
1008 IlMode::Binary { program, current_type, .. } => {
1009 if let Some(t) = current_type.take() {
1010 program.types.push(t);
1011 }
1012 Ok(())
1013 }
1014 }
1015 }
1016
1017 fn write_field(&mut self, name: &str, gaia_type: &GaiaType) -> Result<()> {
1018 match &mut self.mode {
1019 IlMode::Text(writer) => writer.write_field(name, &gaia_type_to_msil_name(gaia_type)),
1020 IlMode::Binary { current_type, .. } => {
1021 if let Some(t) = current_type {
1022 t.fields.push(ClrField {
1023 name: name.to_string(),
1024 field_type: gaia_type_to_clr_type(gaia_type),
1025 access_flags: ClrAccessFlags {
1026 is_public: true,
1027 is_private: false,
1028 is_security_transparent: false,
1029 is_retargetable: false,
1030 },
1031 default_value: None,
1032 attributes: vec![],
1033 });
1034 }
1035 Ok(())
1036 }
1037 }
1038 }
1039
1040 fn emit_assembly_declaration(&mut self, name: &str) -> Result<()> {
1041 match &mut self.mode {
1042 IlMode::Text(writer) => writer.write_assembly(name),
1043 IlMode::Binary { .. } => Ok(()), }
1045 }
1046
1047 fn emit_external_assembly(&mut self, name: &str) -> Result<()> {
1048 match &mut self.mode {
1049 IlMode::Text(writer) => writer.write_external_assembly(name),
1050 IlMode::Binary { program, .. } => {
1051 if !program.external_assemblies.iter().any(|a| a.name == name) {
1053 program.external_assemblies.push(ClrExternalAssembly {
1054 name: name.to_string(),
1055 version: ClrVersion { major: 0, minor: 0, build: 0, revision: 0 },
1056 public_key_token: None,
1057 culture: None,
1058 hash_algorithm: None,
1059 });
1060 }
1061 Ok(())
1062 }
1063 }
1064 }
1065
1066 fn start_method(
1067 &mut self,
1068 name: &str,
1069 parameters: &[GaiaType],
1070 return_type: &Option<GaiaType>,
1071 is_entry: bool,
1072 ) -> Result<()> {
1073 match &mut self.mode {
1074 IlMode::Text(writer) => {
1075 let param_names: Vec<String> = parameters.iter().map(|t| gaia_type_to_msil_name(t)).collect();
1076 let param_refs: Vec<&str> = param_names.iter().map(|s| s.as_str()).collect();
1077 let ret_name_owned = return_type.as_ref().map(|t| gaia_type_to_msil_name(t));
1078 let ret_name = ret_name_owned.as_deref();
1079 writer.start_method(name, ¶m_refs, ret_name, is_entry)
1080 }
1081 IlMode::Binary { current_method, .. } => {
1082 let clr_params = parameters
1083 .iter()
1084 .enumerate()
1085 .map(|(i, t)| ClrParameter {
1086 name: format!("arg{}", i),
1087 parameter_type: gaia_type_to_clr_type(t),
1088 is_in: true,
1089 is_out: false,
1090 is_optional: false,
1091 default_value: None,
1092 attributes: vec![],
1093 })
1094 .collect();
1095
1096 let method = ClrMethod {
1097 name: name.to_string(),
1098 return_type: return_type.as_ref().map(gaia_type_to_clr_type).unwrap_or(ClrTypeReference {
1099 name: "void".to_string(),
1100 namespace: None,
1101 assembly: None,
1102 is_value_type: false,
1103 is_reference_type: false,
1104 generic_parameters: vec![],
1105 }),
1106 parameters: clr_params,
1107 access_flags: ClrAccessFlags {
1108 is_public: true,
1109 is_private: false,
1110 is_security_transparent: false,
1111 is_retargetable: false,
1112 },
1113 impl_flags: ClrMethodImplFlags { is_managed: true, ..Default::default() },
1114 instructions: vec![],
1115 max_stack: 8u16,
1116 locals: vec![],
1117 exception_handlers: vec![],
1118 attributes: vec![],
1119 is_entry_point: is_entry,
1120 };
1121 *current_method = Some(method);
1122 Ok(())
1123 }
1124 }
1125 }
1126
1127 fn end_method(&mut self) -> Result<()> {
1128 match &mut self.mode {
1129 IlMode::Text(writer) => writer.end_method(),
1130 IlMode::Binary { program, current_type, current_method } => {
1131 if let Some(method) = current_method.take() {
1132 if let Some(t) = current_type {
1133 t.methods.push(method);
1134 }
1135 else {
1136 program.global_methods.push(method);
1137 }
1138 }
1139 Ok(())
1140 }
1141 }
1142 }
1143
1144 fn generate_bytecode(self) -> Result<Vec<u8>> {
1145 match self.mode {
1146 IlMode::Text(writer) => Ok(writer.finish().into_bytes()),
1147 IlMode::Binary { .. } => Err(GaiaError::custom_error("Use convert_to_clr_program for binary mode")),
1148 }
1149 }
1150
1151 fn finish_binary(self) -> Result<ClrProgram> {
1152 match self.mode {
1153 IlMode::Binary { program, .. } => Ok(program),
1154 _ => Err(GaiaError::custom_error("Use generate_bytecode for text mode")),
1155 }
1156 }
1157
1158 fn map_function(&self, raw_name: &str) -> String {
1160 let il_target = CompilationTarget {
1161 build: Architecture::CLR,
1162 host: AbiCompatible::MicrosoftIntermediateLanguage,
1163 target: ApiCompatible::ClrRuntime(4),
1164 };
1165 self.function_mapper.map_function(&il_target, raw_name).unwrap_or(raw_name).to_string()
1166 }
1167
1168 fn emit_ldc_i4(&mut self, value: i32) -> Result<()> {
1169 self.emit_with_immediate(ClrOpcode::LdcI4, value)
1170 }
1171
1172 fn emit_ldc_i8(&mut self, value: i64) -> Result<()> {
1173 match &mut self.mode {
1174 IlMode::Text(writer) => writer.emit_ldc_i8(value),
1175 IlMode::Binary { current_method, .. } => {
1176 if let Some(method) = current_method {
1177 method.instructions.push(ClrInstruction::WithImmediate64 { opcode: ClrOpcode::LdcI8, value });
1178 Ok(())
1179 }
1180 else {
1181 Err(GaiaError::custom_error("No current method"))
1182 }
1183 }
1184 }
1185 }
1186
1187 fn emit_ldc_r4(&mut self, value: f32) -> Result<()> {
1188 match &mut self.mode {
1189 IlMode::Text(writer) => writer.emit_ldc_r4(value),
1190 IlMode::Binary { current_method, .. } => {
1191 if let Some(method) = current_method {
1192 method.instructions.push(ClrInstruction::WithFloat32 { opcode: ClrOpcode::LdcR4, value });
1193 Ok(())
1194 }
1195 else {
1196 Err(GaiaError::custom_error("No current method"))
1197 }
1198 }
1199 }
1200 }
1201
1202 fn emit_ldc_r8(&mut self, value: f64) -> Result<()> {
1203 match &mut self.mode {
1204 IlMode::Text(writer) => writer.emit_ldc_r8(value),
1205 IlMode::Binary { current_method, .. } => {
1206 if let Some(method) = current_method {
1207 method.instructions.push(ClrInstruction::WithFloat64 { opcode: ClrOpcode::LdcR8, value });
1208 Ok(())
1209 }
1210 else {
1211 Err(GaiaError::custom_error("No current method"))
1212 }
1213 }
1214 }
1215 }
1216
1217 fn emit_ldstr(&mut self, value: &str) -> Result<()> {
1218 match &mut self.mode {
1219 IlMode::Text(writer) => writer.emit_ldstr(value),
1220 IlMode::Binary { current_method, .. } => {
1221 if let Some(method) = current_method {
1222 method.instructions.push(ClrInstruction::WithString { opcode: ClrOpcode::Ldstr, value: value.to_string() });
1223 Ok(())
1224 }
1225 else {
1226 Err(GaiaError::invalid_data("No current method context for binary IL generation"))
1227 }
1228 }
1229 }
1230 }
1231
1232 fn emit_ldnull(&mut self) -> Result<()> {
1233 self.emit_simple(ClrOpcode::Ldnull)
1234 }
1235
1236 fn emit_ldloc(&mut self, index: u32) -> Result<()> {
1237 match &mut self.mode {
1238 IlMode::Text(writer) => writer.emit_ldloc(index),
1239 IlMode::Binary { current_method, .. } => {
1240 if let Some(method) = current_method {
1241 method.instructions.push(ClrInstruction::WithLocalVar { opcode: ClrOpcode::Ldloc, index: index as u16 });
1242 Ok(())
1243 }
1244 else {
1245 Err(GaiaError::custom_error("No current method"))
1246 }
1247 }
1248 }
1249 }
1250
1251 fn emit_stloc(&mut self, index: u32) -> Result<()> {
1252 match &mut self.mode {
1253 IlMode::Text(writer) => writer.emit_stloc(index),
1254 IlMode::Binary { current_method, .. } => {
1255 if let Some(method) = current_method {
1256 method.instructions.push(ClrInstruction::WithLocalVar { opcode: ClrOpcode::Stloc, index: index as u16 });
1257 Ok(())
1258 }
1259 else {
1260 Err(GaiaError::custom_error("No current method"))
1261 }
1262 }
1263 }
1264 }
1265
1266 fn emit_ldarg(&mut self, index: u32) -> Result<()> {
1267 match &mut self.mode {
1268 IlMode::Text(writer) => writer.emit_ldarg(index),
1269 IlMode::Binary { current_method, .. } => {
1270 if let Some(method) = current_method {
1271 method.instructions.push(ClrInstruction::WithParameter { opcode: ClrOpcode::Ldarg, index: index as u16 });
1272 Ok(())
1273 }
1274 else {
1275 Err(GaiaError::custom_error("No current method"))
1276 }
1277 }
1278 }
1279 }
1280
1281 fn emit_starg(&mut self, index: u32) -> Result<()> {
1282 match &mut self.mode {
1283 IlMode::Text(writer) => writer.emit_starg(index),
1284 IlMode::Binary { current_method, .. } => {
1285 if let Some(method) = current_method {
1286 method.instructions.push(ClrInstruction::WithParameter { opcode: ClrOpcode::Starg, index: index as u16 });
1287 Ok(())
1288 }
1289 else {
1290 Err(GaiaError::custom_error("No current method"))
1291 }
1292 }
1293 }
1294 }
1295
1296 fn emit_add(&mut self) -> Result<()> {
1297 self.emit_simple(ClrOpcode::Add)
1298 }
1299
1300 fn emit_sub(&mut self) -> Result<()> {
1301 self.emit_simple(ClrOpcode::Sub)
1302 }
1303
1304 fn emit_mul(&mut self) -> Result<()> {
1305 self.emit_simple(ClrOpcode::Mul)
1306 }
1307
1308 fn emit_div(&mut self) -> Result<()> {
1309 self.emit_simple(ClrOpcode::Div)
1310 }
1311
1312 fn emit_ceq(&mut self) -> Result<()> {
1313 self.emit_simple(ClrOpcode::Ceq)
1314 }
1315
1316 fn emit_cgt(&mut self) -> Result<()> {
1317 self.emit_simple(ClrOpcode::Cgt)
1318 }
1319
1320 fn emit_clt(&mut self) -> Result<()> {
1321 self.emit_simple(ClrOpcode::Clt)
1322 }
1323
1324 fn emit_br(&mut self, label: &str) -> Result<()> {
1325 self.emit_branch(ClrOpcode::Br, label)
1326 }
1327
1328 fn emit_brtrue(&mut self, label: &str) -> Result<()> {
1329 self.emit_branch(ClrOpcode::Brtrue, label)
1330 }
1331
1332 fn emit_brfalse(&mut self, label: &str) -> Result<()> {
1333 self.emit_branch(ClrOpcode::Brfalse, label)
1334 }
1335
1336 fn emit_call(&mut self, method_ref: &str) -> Result<()> {
1337 match &mut self.mode {
1338 IlMode::Text(writer) => writer.emit_call(method_ref),
1339 IlMode::Binary { current_method, .. } => {
1340 if let Some(method) = current_method {
1341 method
1342 .instructions
1343 .push(ClrInstruction::WithMethod { opcode: ClrOpcode::Call, method_ref: method_ref.to_string() });
1344 Ok(())
1345 }
1346 else {
1347 Err(GaiaError::custom_error("No current method"))
1348 }
1349 }
1350 }
1351 }
1352
1353 fn emit_ret(&mut self) -> Result<()> {
1354 self.emit_simple(ClrOpcode::Ret)
1355 }
1356
1357 fn define_label(&mut self, name: &str) -> Result<()> {
1358 match &mut self.mode {
1359 IlMode::Text(writer) => writer.define_label(name),
1360 IlMode::Binary { .. } => Ok(()), }
1362 }
1363
1364 fn emit_dup(&mut self) -> Result<()> {
1365 self.emit_simple(ClrOpcode::Dup)
1366 }
1367
1368 fn emit_pop(&mut self) -> Result<()> {
1369 self.emit_simple(ClrOpcode::Pop)
1370 }
1371
1372 fn emit_newarr(&mut self, type_name: &str) -> Result<()> {
1373 match &mut self.mode {
1374 IlMode::Text(writer) => writer.emit_newarr(type_name),
1375 IlMode::Binary { current_method, .. } => {
1376 if let Some(method) = current_method {
1377 method
1378 .instructions
1379 .push(ClrInstruction::WithType { opcode: ClrOpcode::Newarr, type_ref: type_name.to_string() });
1380 Ok(())
1381 }
1382 else {
1383 Err(GaiaError::custom_error("No current method"))
1384 }
1385 }
1386 }
1387 }
1388
1389 fn emit_ldelem(&mut self, type_name: &str) -> Result<()> {
1390 match &mut self.mode {
1391 IlMode::Text(writer) => writer.emit_ldelem(type_name),
1392 IlMode::Binary { current_method, .. } => {
1393 if let Some(method) = current_method {
1394 method
1395 .instructions
1396 .push(ClrInstruction::WithType { opcode: ClrOpcode::Ldelem, type_ref: type_name.to_string() });
1397 Ok(())
1398 }
1399 else {
1400 Err(GaiaError::custom_error("No current method"))
1401 }
1402 }
1403 }
1404 }
1405
1406 fn emit_stelem(&mut self, type_name: &str) -> Result<()> {
1407 match &mut self.mode {
1408 IlMode::Text(writer) => writer.emit_stelem(type_name),
1409 IlMode::Binary { current_method, .. } => {
1410 if let Some(method) = current_method {
1411 method
1412 .instructions
1413 .push(ClrInstruction::WithType { opcode: ClrOpcode::Stelem, type_ref: type_name.to_string() });
1414 Ok(())
1415 }
1416 else {
1417 Err(GaiaError::custom_error("No current method"))
1418 }
1419 }
1420 }
1421 }
1422
1423 fn emit_ldlen(&mut self) -> Result<()> {
1424 self.emit_simple(ClrOpcode::Ldlen)
1425 }
1426
1427 fn emit_and(&mut self) -> Result<()> {
1428 self.emit_simple(ClrOpcode::And)
1429 }
1430
1431 fn emit_or(&mut self) -> Result<()> {
1432 self.emit_simple(ClrOpcode::Or)
1433 }
1434
1435 fn emit_ldloca(&mut self, index: u32) -> Result<()> {
1436 match &mut self.mode {
1437 IlMode::Text(writer) => writer.emit_ldloca(index),
1438 IlMode::Binary { current_method, .. } => {
1439 if let Some(method) = current_method {
1440 method.instructions.push(ClrInstruction::WithLocalVar { opcode: ClrOpcode::Ldloca, index: index as u16 });
1441 Ok(())
1442 }
1443 else {
1444 Err(GaiaError::custom_error("No current method"))
1445 }
1446 }
1447 }
1448 }
1449
1450 fn emit_ldind_i4(&mut self) -> Result<()> {
1451 self.emit_simple(ClrOpcode::LdindI4)
1452 }
1453
1454 fn emit_ldind_i8(&mut self) -> Result<()> {
1455 self.emit_simple(ClrOpcode::LdindI8)
1456 }
1457
1458 fn emit_ldind_r4(&mut self) -> Result<()> {
1459 self.emit_simple(ClrOpcode::LdindR4)
1460 }
1461
1462 fn emit_ldind_r8(&mut self) -> Result<()> {
1463 self.emit_simple(ClrOpcode::LdindR8)
1464 }
1465
1466 fn emit_ldind_ref(&mut self) -> Result<()> {
1467 self.emit_simple(ClrOpcode::LdindRef)
1468 }
1469
1470 fn emit_stind_i4(&mut self) -> Result<()> {
1471 self.emit_simple(ClrOpcode::StindI4)
1472 }
1473
1474 fn emit_stind_i8(&mut self) -> Result<()> {
1475 self.emit_simple(ClrOpcode::StindI8)
1476 }
1477
1478 fn emit_stind_r4(&mut self) -> Result<()> {
1479 self.emit_simple(ClrOpcode::StindR4)
1480 }
1481
1482 fn emit_stind_r8(&mut self) -> Result<()> {
1483 self.emit_simple(ClrOpcode::StindR8)
1484 }
1485
1486 fn emit_stind_ref(&mut self) -> Result<()> {
1487 self.emit_simple(ClrOpcode::StindRef)
1488 }
1489
1490 fn emit_newobj(&mut self, method_ref: &str) -> Result<()> {
1491 match &mut self.mode {
1492 IlMode::Text(writer) => writer.emit_newobj(method_ref),
1493 IlMode::Binary { current_method, .. } => {
1494 if let Some(method) = current_method {
1495 method
1496 .instructions
1497 .push(ClrInstruction::WithMethod { opcode: ClrOpcode::Newobj, method_ref: method_ref.to_string() });
1498 Ok(())
1499 }
1500 else {
1501 Err(GaiaError::custom_error("No current method"))
1502 }
1503 }
1504 }
1505 }
1506
1507 fn emit_ldfld(&mut self, field_ref: &str) -> Result<()> {
1508 match &mut self.mode {
1509 IlMode::Text(writer) => writer.emit_ldfld(field_ref),
1510 IlMode::Binary { current_method, .. } => {
1511 if let Some(method) = current_method {
1512 method
1513 .instructions
1514 .push(ClrInstruction::WithField { opcode: ClrOpcode::Ldfld, field_ref: field_ref.to_string() });
1515 Ok(())
1516 }
1517 else {
1518 Err(GaiaError::custom_error("No current method"))
1519 }
1520 }
1521 }
1522 }
1523
1524 fn emit_stfld(&mut self, field_ref: &str) -> Result<()> {
1525 match &mut self.mode {
1526 IlMode::Text(writer) => writer.emit_stfld(field_ref),
1527 IlMode::Binary { current_method, .. } => {
1528 if let Some(method) = current_method {
1529 method
1530 .instructions
1531 .push(ClrInstruction::WithField { opcode: ClrOpcode::Stfld, field_ref: field_ref.to_string() });
1532 Ok(())
1533 }
1534 else {
1535 Err(GaiaError::custom_error("No current method"))
1536 }
1537 }
1538 }
1539 }
1540
1541 fn emit_conv_i4(&mut self) -> Result<()> {
1542 self.emit_simple(ClrOpcode::ConvI4)
1543 }
1544
1545 fn emit_conv_i8(&mut self) -> Result<()> {
1546 self.emit_simple(ClrOpcode::ConvI8)
1547 }
1548
1549 fn emit_conv_r4(&mut self) -> Result<()> {
1550 self.emit_simple(ClrOpcode::ConvR4)
1551 }
1552
1553 fn emit_conv_r8(&mut self) -> Result<()> {
1554 self.emit_simple(ClrOpcode::ConvR8)
1555 }
1556
1557 fn emit_box(&mut self, gaia_type: &GaiaType) -> Result<()> {
1558 let type_name = gaia_type_to_msil_name(gaia_type);
1559 match &mut self.mode {
1560 IlMode::Text(writer) => writer.emit_box(&type_name),
1561 IlMode::Binary { current_method, .. } => {
1562 if let Some(method) = current_method {
1563 method.instructions.push(ClrInstruction::WithType { opcode: ClrOpcode::Box, type_ref: type_name });
1564 Ok(())
1565 }
1566 else {
1567 Err(GaiaError::custom_error("No current method"))
1568 }
1569 }
1570 }
1571 }
1572
1573 fn emit_unbox(&mut self, gaia_type: &GaiaType) -> Result<()> {
1574 let type_name = gaia_type_to_msil_name(gaia_type);
1575 match &mut self.mode {
1576 IlMode::Text(writer) => writer.emit_unbox(&type_name),
1577 IlMode::Binary { current_method, .. } => {
1578 if let Some(method) = current_method {
1579 method.instructions.push(ClrInstruction::WithType { opcode: ClrOpcode::Unbox, type_ref: type_name });
1580 Ok(())
1581 }
1582 else {
1583 Err(GaiaError::custom_error("No current method"))
1584 }
1585 }
1586 }
1587 }
1588
1589 fn emit_simple(&mut self, opcode: ClrOpcode) -> Result<()> {
1590 match &mut self.mode {
1591 IlMode::Text(writer) => match opcode {
1592 ClrOpcode::Add => writer.emit_add(),
1593 ClrOpcode::Sub => writer.emit_sub(),
1594 ClrOpcode::Mul => writer.emit_mul(),
1595 ClrOpcode::Div => writer.emit_div(),
1596 ClrOpcode::Ceq => writer.emit_ceq(),
1597 ClrOpcode::Cgt => writer.emit_cgt(),
1598 ClrOpcode::Clt => writer.emit_clt(),
1599 ClrOpcode::Ret => writer.emit_ret(),
1600 ClrOpcode::Dup => writer.emit_dup(),
1601 ClrOpcode::Pop => writer.emit_pop(),
1602 ClrOpcode::And => writer.emit_and(),
1603 ClrOpcode::Or => writer.emit_or(),
1604 ClrOpcode::Ldnull => writer.emit_ldnull(),
1605 ClrOpcode::LdindI4 => writer.emit_ldind_i4(),
1606 ClrOpcode::LdindI8 => writer.emit_ldind_i8(),
1607 ClrOpcode::LdindR4 => writer.emit_ldind_r4(),
1608 ClrOpcode::LdindR8 => writer.emit_ldind_r8(),
1609 ClrOpcode::LdindRef => writer.emit_ldind_ref(),
1610 ClrOpcode::StindI4 => writer.emit_stind_i4(),
1611 ClrOpcode::StindI8 => writer.emit_stind_i8(),
1612 ClrOpcode::StindR4 => writer.emit_stind_r4(),
1613 ClrOpcode::StindR8 => writer.emit_stind_r8(),
1614 ClrOpcode::StindRef => writer.emit_stind_ref(),
1615 ClrOpcode::ConvI4 => writer.emit_conv_i4(),
1616 ClrOpcode::ConvI8 => writer.emit_conv_i8(),
1617 ClrOpcode::ConvR4 => writer.emit_conv_r4(),
1618 ClrOpcode::ConvR8 => writer.emit_conv_r8(),
1619 ClrOpcode::Ldlen => writer.emit_ldlen(),
1620 _ => Err(GaiaError::custom_error(format!("Unsupported simple opcode: {:?}", opcode))),
1621 },
1622 IlMode::Binary { current_method, .. } => {
1623 if let Some(method) = current_method {
1624 method.instructions.push(ClrInstruction::Simple { opcode });
1625 Ok(())
1626 }
1627 else {
1628 Err(GaiaError::custom_error("No current method"))
1629 }
1630 }
1631 }
1632 }
1633
1634 fn emit_with_immediate(&mut self, opcode: ClrOpcode, value: i32) -> Result<()> {
1635 match &mut self.mode {
1636 IlMode::Text(writer) => match opcode {
1637 ClrOpcode::LdcI4 => writer.emit_ldc_i4(value),
1638 _ => Err(GaiaError::custom_error(format!("Unsupported immediate opcode: {:?}", opcode))),
1639 },
1640 IlMode::Binary { current_method, .. } => {
1641 if let Some(method) = current_method {
1642 method.instructions.push(ClrInstruction::WithImmediate { opcode, value });
1643 Ok(())
1644 }
1645 else {
1646 Err(GaiaError::custom_error("No current method"))
1647 }
1648 }
1649 }
1650 }
1651
1652 fn emit_branch(&mut self, opcode: ClrOpcode, label: &str) -> Result<()> {
1653 match &mut self.mode {
1654 IlMode::Text(writer) => match opcode {
1655 ClrOpcode::Br => writer.emit_br(label),
1656 ClrOpcode::Brtrue => writer.emit_brtrue(label),
1657 ClrOpcode::Brfalse => writer.emit_brfalse(label),
1658 _ => Err(GaiaError::custom_error(format!("Unsupported branch opcode: {:?}", opcode))),
1659 },
1660 IlMode::Binary { current_method, .. } => {
1661 if let Some(method) = current_method {
1662 method.instructions.push(ClrInstruction::WithLabel { opcode, label: label.to_string() });
1663 Ok(())
1664 }
1665 else {
1666 Err(GaiaError::custom_error("No current method"))
1667 }
1668 }
1669 }
1670 }
1671}
1672
1673#[cfg(feature = "clr")]
1674fn gaia_type_to_clr_type(t: &GaiaType) -> ClrTypeReference {
1675 match t {
1676 GaiaType::Array(elem, _) => {
1677 let mut elem_ref = gaia_type_to_clr_type(elem);
1678 elem_ref.name = format!("{}[]", elem_ref.name);
1679 elem_ref.is_value_type = false;
1680 elem_ref.is_reference_type = true;
1681 elem_ref
1682 }
1683 _ => {
1684 let name = match t {
1685 GaiaType::I8 => "int8",
1686 GaiaType::U8 => "uint8",
1687 GaiaType::I16 => "int16",
1688 GaiaType::U16 => "uint16",
1689 GaiaType::I32 => "int32",
1690 GaiaType::U32 => "uint32",
1691 GaiaType::I64 => "int64",
1692 GaiaType::U64 => "uint64",
1693 GaiaType::F32 => "float32",
1694 GaiaType::F64 => "float64",
1695 GaiaType::String => "string",
1696 GaiaType::Bool => "bool",
1697 GaiaType::Void => "void",
1698 GaiaType::Class(name) => name,
1699 GaiaType::Struct(name) => name,
1700 _ => "object",
1701 };
1702 ClrTypeReference {
1703 name: name.to_string(),
1704 namespace: None,
1705 assembly: None,
1706 is_value_type: !matches!(t, GaiaType::String | GaiaType::Object | GaiaType::Array(_, _) | GaiaType::Class(_)),
1707 is_reference_type: matches!(
1708 t,
1709 GaiaType::String | GaiaType::Object | GaiaType::Array(_, _) | GaiaType::Class(_)
1710 ),
1711 generic_parameters: vec![],
1712 }
1713 }
1714 }
1715}
1716
1717#[cfg(feature = "clr")]
1718fn convert_to_clr_program(program: &GaiaModule, settings: Option<&GaiaSettings>) -> Result<ClrProgram> {
1719 let mut context = IlContext::new_binary(program.name.clone());
1720 if let Some(s) = settings {
1721 context.function_mapper = FunctionMapper::from_config(s).unwrap_or_default();
1722 }
1723 compile_program(&mut context, program)?;
1724 context.finish_binary()
1725}