Skip to main content

clr_assembler/program/
builder.rs

1use crate::program::*;
2
3/// CLR program builder that simplifies the construction of ClrProgram instances.
4#[derive(Debug)]
5pub struct ClrBuilder {
6    program: ClrProgram,
7    current_type: Option<usize>,
8    current_method: Option<usize>,
9}
10
11impl ClrBuilder {
12    /// Creates a new ClrBuilder with the specified assembly name.
13    pub fn new(name: String) -> Self {
14        Self {
15            program: ClrProgram {
16                name,
17                version: ClrVersion { major: 1, minor: 0, build: 0, revision: 0 },
18                access_flags: ClrAccessFlags::default(),
19                external_assemblies: Vec::new(),
20                module: None,
21                types: Vec::new(),
22                global_methods: Vec::new(),
23                global_fields: Vec::new(),
24                attributes: Vec::new(),
25                constant_pool: ClrConstantPool::new(),
26                source_file: None,
27            },
28            current_type: None,
29            current_method: None,
30        }
31    }
32
33    /// Adds an external assembly reference to the program.
34    pub fn add_external_assembly(&mut self, name: String) {
35        self.program.external_assemblies.push(ClrExternalAssembly {
36            name,
37            version: ClrVersion { major: 4, minor: 0, build: 0, revision: 0 },
38            public_key_token: None,
39            culture: None,
40            hash_value: None,
41        });
42    }
43
44    /// Begins a new class definition with the specified name and optional namespace.
45    pub fn begin_class(&mut self, name: String, namespace: Option<String>) {
46        let clr_type = ClrType::new(name, namespace);
47        self.program.types.push(clr_type);
48        self.current_type = Some(self.program.types.len() - 1);
49        self.current_method = None;
50    }
51
52    /// Begins a new method definition with the specified name and return type.
53    pub fn begin_method(&mut self, name: String, return_type: ClrTypeReference) {
54        let mut method = ClrMethod::new(name, return_type);
55        // Set default access flags for methods
56        method.access_flags.is_public = true;
57        method.impl_flags.is_managed = true;
58        if method.name == "main" {
59            method.is_entry_point = true;
60        }
61        if let Some(type_idx) = self.current_type {
62            self.program.types[type_idx].methods.push(method);
63            self.current_method = Some(self.program.types[type_idx].methods.len() - 1);
64        }
65        else {
66            self.program.global_methods.push(method);
67            self.current_method = Some(self.program.global_methods.len() - 1);
68        }
69    }
70
71    /// Emits an instruction with the specified opcode and optional operand.
72    pub fn emit(&mut self, opcode: ClrOpcode, operand: Option<ClrInstructionOperand>) {
73        let inst = ClrInstruction {
74            opcode,
75            operand,
76            offset: 0, // Offset is typically calculated by the binary encoder
77        };
78
79        if let Some(type_idx) = self.current_type {
80            if let Some(method_idx) = self.current_method {
81                self.program.types[type_idx].methods[method_idx].instructions.push(inst);
82            }
83        }
84        else if let Some(method_idx) = self.current_method {
85            self.program.global_methods[method_idx].instructions.push(inst);
86        }
87    }
88
89    /// Finalizes the builder and returns the constructed ClrProgram.
90    pub fn finish(self) -> ClrProgram {
91        self.program
92    }
93}